diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace.meta b/Assets/External/EVMC4U.meta similarity index 77% rename from Assets/External/UniGLTF/Samples/ScreenSpace.meta rename to Assets/External/EVMC4U.meta index 72aa1b85f..d32b80117 100644 --- a/Assets/External/UniGLTF/Samples/ScreenSpace.meta +++ b/Assets/External/EVMC4U.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8458a1e47a62f6f4187d89d44f564117 +guid: f265d3b79baedc046a3ff59ee213ef75 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/External/EVMC4U/3rdpartylicenses(ExternalReceiverPack).txt b/Assets/External/EVMC4U/3rdpartylicenses(ExternalReceiverPack).txt new file mode 100644 index 000000000..10d1da4f2 --- /dev/null +++ b/Assets/External/EVMC4U/3rdpartylicenses(ExternalReceiverPack).txt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:603c96b009ad8b7f27a676b3390594634bea36a3592e73e88a68074a73c58f7f +size 5737 diff --git a/Assets/External/UniGLTF/Runtime/Resources/test_motion.txt.meta b/Assets/External/EVMC4U/3rdpartylicenses(ExternalReceiverPack).txt.meta similarity index 75% rename from Assets/External/UniGLTF/Runtime/Resources/test_motion.txt.meta rename to Assets/External/EVMC4U/3rdpartylicenses(ExternalReceiverPack).txt.meta index b77c0c6f7..cb377a99b 100644 --- a/Assets/External/UniGLTF/Runtime/Resources/test_motion.txt.meta +++ b/Assets/External/EVMC4U/3rdpartylicenses(ExternalReceiverPack).txt.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7d2617171adc40b41ac50228f101e178 +guid: 9402b207048258649b4b1c0580e1b73b TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/External/EVMC4U/CameraReceiver.cs b/Assets/External/EVMC4U/CameraReceiver.cs new file mode 100644 index 000000000..6ebe2539c --- /dev/null +++ b/Assets/External/EVMC4U/CameraReceiver.cs @@ -0,0 +1,193 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma warning disable 0414,0219 +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Profiling; + +namespace EVMC4U +{ + public class CameraReceiver : MonoBehaviour, IExternalReceiver + { + [Header("CameraReceiver v1.1")] + [SerializeField, Label("VMCカメラ制御同期Camera")] + public Camera VMCControlledCamera = null; //VMCカメラ制御同期 + [SerializeField, Label("動作状況")] + private string StatusMessage = ""; //Inspector表示用 + +#if EVMC4U_JA + [Header("カメラ手ブレ補正フィルタ")] +#else + [Header("Lowpass Filter Option")] +#endif + [SerializeField, Label("カメラ位置フィルタ(手ブレ補正)")] + public bool CameraPositionFilterEnable = false; //カメラ位置フィルタ(手ブレ補正) + [SerializeField, Label("カメラ回転フィルタ(手ブレ補正)")] + public bool CameraRotationFilterEnable = false; //カメラ回転フィルタ(手ブレ補正) + [SerializeField, Label("カメラフィルタ係数")] + public float CameraFilter = 0.95f; //カメラフィルタ係数 + +#if EVMC4U_JA + [Header("デイジーチェーン")] +#else + [Header("Daisy Chain")] +#endif + public GameObject[] NextReceivers = new GameObject[1]; + + private ExternalReceiverManager externalReceiverManager = null; + bool shutdown = false; + + private Vector3 cameraPosFilter = Vector3.zero; + private Quaternion cameraRotFilter = Quaternion.identity; + + //メッセージ処理一時変数struct(負荷対策) + //Vector3 pos; + //Quaternion rot; + + //カメラ情報のキャッシュ + Vector3 cameraPos = Vector3.zero; + Quaternion cameraRot = Quaternion.identity; + float fov = 0; + + void Start() + { + externalReceiverManager = new ExternalReceiverManager(NextReceivers); + StatusMessage = "Waiting for Master..."; + } + + //デイジーチェーンを更新 + public void UpdateDaisyChain() + { + externalReceiverManager.GetIExternalReceiver(NextReceivers); + } + + void Update() + { + //カメラがセットされているならば + if (VMCControlledCamera != null && VMCControlledCamera.transform != null && fov != 0) + { + CameraFilter = Mathf.Clamp(CameraFilter, 0f, 1f); + + //カメラ移動フィルタ + if (CameraPositionFilterEnable) + { + cameraPosFilter = (cameraPosFilter * CameraFilter) + cameraPos * (1.0f - CameraFilter); + VMCControlledCamera.transform.localPosition = cameraPosFilter; + } + else + { + VMCControlledCamera.transform.localPosition = cameraPos; + } + //カメラ回転フィルタ + if (CameraRotationFilterEnable) + { + cameraRotFilter = Quaternion.Slerp(cameraRotFilter, cameraRot, 1.0f - CameraFilter); + VMCControlledCamera.transform.localRotation = cameraRotFilter; + } + else + { + VMCControlledCamera.transform.localRotation = cameraRot; + } + //FOV同期 + VMCControlledCamera.fieldOfView = fov; + } + } + + public void MessageDaisyChain(ref uOSC.Message message, int callCount) + { + //Startされていない場合無視 + if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) + { + return; + } + + if (shutdown) + { + return; + } + + StatusMessage = "OK"; + + //異常を検出して動作停止 + try + { + ProcessMessage(ref message); + } + catch (Exception e) + { + StatusMessage = "Error: Exception"; + Debug.LogError(" --- Communication Error ---"); + Debug.LogError(e.ToString()); + shutdown = true; + return; + } + + if (!externalReceiverManager.SendNextReceivers(message, callCount)) + { + StatusMessage = "Infinite loop detected!"; + shutdown = true; + } + } + + private void ProcessMessage(ref uOSC.Message message) + { + //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない + if (message.address == null || message.values == null) + { + StatusMessage = "Bad message."; + return; + } + + //カメラ姿勢FOV同期 v2.1 + if (message.address == "/VMC/Ext/Cam" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + && (message.values[8] is float) + ) + { + cameraPos.x = (float)message.values[1]; + cameraPos.y = (float)message.values[2]; + cameraPos.z = (float)message.values[3]; + cameraRot.x = (float)message.values[4]; + cameraRot.y = (float)message.values[5]; + cameraRot.z = (float)message.values[6]; + cameraRot.w = (float)message.values[7]; + fov = (float)message.values[8]; + //受信と更新のタイミングは切り離した + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogEditor.cs.meta b/Assets/External/EVMC4U/CameraReceiver.cs.meta similarity index 83% rename from Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogEditor.cs.meta rename to Assets/External/EVMC4U/CameraReceiver.cs.meta index de1678682..0e21421eb 100644 --- a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogEditor.cs.meta +++ b/Assets/External/EVMC4U/CameraReceiver.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 04fa1873cf1c0374aab1670a24d741b5 +guid: eddf837c1e0f4a04697b1b68adb4a39f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/External/EVMC4U/CommunicationValidator.cs b/Assets/External/EVMC4U/CommunicationValidator.cs new file mode 100644 index 000000000..8c16c967b --- /dev/null +++ b/Assets/External/EVMC4U/CommunicationValidator.cs @@ -0,0 +1,256 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma warning disable 0414,0219 +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Profiling; + + +namespace EVMC4U +{ + public class CommunicationValidator : MonoBehaviour, IExternalReceiver + { + [Header("CommunicationValidator v1.2")] + [SerializeField, Label("動作状況")] + private string StatusMessage = ""; //Inspector表示用 + +#if EVMC4U_JA + [Header("UI オプション")] +#else + [Header("UI Option")] +#endif + [SerializeField, Label("画面上に表示する")] + public bool ShowInformation = false; + +#if EVMC4U_JA + [Header("状態モニタ(表示用)")] +#else + [Header("Status Monitor(Read only)")] +#endif + [SerializeField, Label("受信処理再帰呼出し回数")] + private int CallCountMonitor = 0; //Inspector表示用 + + [SerializeField, Label("利用可能")] + public int Available = 0; + [SerializeField, Label("送信側Time")] + public float time = 0; + + [SerializeField, Label("キャリブレーション状態")] + public CalibrationState calibrationState = 0; + [SerializeField, Label("キャリブレーションモード")] + public CalibrationMode calibrationMode = 0; + +#if EVMC4U_JA + [Header("送信側受信状態(表示用)")] +#else + [Header("Receive Status(Read only)")] +#endif + [SerializeField, Label("受信許可")] + public bool ReceiveEnable = false; + [SerializeField, Label("受信ポート")] + public int ReceivePort = 0; + [SerializeField, Label("読み込み済み設定ファイルパス")] + public string LoadedConfigPath = ""; + [SerializeField, Label("背景色")] + public Color backgroundColor = Color.clear; + +#if EVMC4U_JA + [Header("送信側ウィンドウ属性情報")] +#else + [Header("Window Attribute Info(Read only)")] +#endif + [SerializeField, Label("最前面")] + public bool IsTopMost = false; + [SerializeField, Label("透過")] + public bool IsTransparent = false; + [SerializeField, Label("クリックスルー")] + public bool WindowClickThrough = false; + [SerializeField, Label("枠なし")] + public bool HideBorder = false; + + +#if EVMC4U_JA + [Header("デイジーチェーン")] +#else + [Header("Daisy Chain")] +#endif + public GameObject[] NextReceivers = new GameObject[1]; + + private ExternalReceiverManager externalReceiverManager = null; + bool shutdown = false; + + readonly Rect rect1 = new Rect(0, 0, 120, 70); + readonly Rect rect2 = new Rect(10, 20, 100, 30); + readonly Rect rect3 = new Rect(10, 40, 100, 300); + + void Start() + { + externalReceiverManager = new ExternalReceiverManager(NextReceivers); + StatusMessage = "Waiting for Master..."; + } + + //デイジーチェーンを更新 + public void UpdateDaisyChain() + { + externalReceiverManager.GetIExternalReceiver(NextReceivers); + } + + int GetAvailable() + { + return Available; + } + + float GetRemoteTime() + { + return time; + } + + void OnGUI() + { + if (ShowInformation) + { + GUI.TextField(rect1, "ExternalReceiver"); + GUI.Label(rect2, "Available: " + GetAvailable()); + GUI.Label(rect3, "Time: " + GetRemoteTime()); + } + } + + public void MessageDaisyChain(ref uOSC.Message message, int callCount) + { + //Startされていない場合無視 + if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) + { + return; + } + + if (shutdown) + { + return; + } + + CallCountMonitor = callCount; + StatusMessage = "OK"; + + //異常を検出して動作停止 + try + { + ProcessMessage(ref message); + } + catch (Exception e) + { + StatusMessage = "Error: Exception"; + Debug.LogError(" --- Communication Error ---"); + Debug.LogError(e.ToString()); + shutdown = true; + return; + } + + if (!externalReceiverManager.SendNextReceivers(message, callCount)) + { + StatusMessage = "Infinite loop detected!"; + shutdown = true; + } + } + + private void ProcessMessage(ref uOSC.Message message) + { + //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない + if (message.address == null || message.values == null) + { + StatusMessage = "Bad message."; + return; + } + + if (message.address == "/VMC/Ext/OK" + && (message.values[0] is int)) + { + Available = (int)message.values[0]; + if (Available == 0) + { + StatusMessage = "Waiting for [Load VRM]"; + } + else { + StatusMessage = "OK"; + } + + //V2.5 キャリブレーション状態(長さ3以上) + if (message.values.Length >= 3) + { + if ((message.values[1] is int) && (message.values[2] is int)) + { + calibrationState = (CalibrationState)message.values[1]; + calibrationMode = (CalibrationMode)message.values[2]; + } + } + } + //データ送信時刻 + else if (message.address == "/VMC/Ext/T" + && (message.values[0] is float)) + { + time = (float)message.values[0]; + } + //V2.4 受信情報 + else if (message.address == "/VMC/Ext/Rcv" + && (message.values[0] is int) + && (message.values[1] is int)) + { + ReceiveEnable = (int)message.values[0] != 0; + ReceivePort = (int)message.values[1]; + } + //V2.4 背景色情報 + else if (message.address == "/VMC/Ext/Setting/Color" + && (message.values[0] is float) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float)) + { + backgroundColor = new Color((float)message.values[0], (float)message.values[1], (float)message.values[2], (float)message.values[3]); + } + //V2.4 ウィンドウ情報 + else if (message.address == "/VMC/Ext/Setting/Win" + && (message.values[0] is int) + && (message.values[1] is int) + && (message.values[2] is int) + && (message.values[3] is int)) + { + IsTopMost = (int)message.values[0] != 0; + IsTransparent = (int)message.values[1] != 0; + WindowClickThrough = (int)message.values[2] != 0; + HideBorder = (int)message.values[3] != 0; + } + //V2.5 読み込み済み設定ファイルパス情報 + else if (message.address == "/VMC/Ext/Config" + && (message.values[0] is string)) + { + LoadedConfigPath = (string)message.values[0]; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/AssetsPath.cs.meta b/Assets/External/EVMC4U/CommunicationValidator.cs.meta similarity index 83% rename from Assets/External/UniGLTF/Editor/MeshUtility/AssetsPath.cs.meta rename to Assets/External/EVMC4U/CommunicationValidator.cs.meta index 4918b11e4..33c248d11 100644 --- a/Assets/External/UniGLTF/Editor/MeshUtility/AssetsPath.cs.meta +++ b/Assets/External/EVMC4U/CommunicationValidator.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: da24ccbbed21eb94d902d42337df3699 +guid: 8a8590b55e73bba4aa42b08101a7cc84 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/External/EVMC4U/DeviceReceiver.cs b/Assets/External/EVMC4U/DeviceReceiver.cs new file mode 100644 index 000000000..4d8a3497d --- /dev/null +++ b/Assets/External/EVMC4U/DeviceReceiver.cs @@ -0,0 +1,333 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma warning disable 0414,0219 +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Profiling; + + +namespace EVMC4U +{ + public class DeviceReceiver : MonoBehaviour, IExternalReceiver + { + const int arrayMax = 16; + + [Header("DeviceReceiver v1.1")] + [SerializeField, Label("動作状況")] + private string StatusMessage = ""; //Inspector表示用 + [SerializeField, Label("現実のトラッキング位置を反映")] + public bool RealPosition = false; + +#if EVMC4U_JA + [Header("トラッキング設定")] +#else + [Header("Tracking Config")] +#endif + public string[] Serials = new string[arrayMax]; + public Transform[] Transforms = new Transform[arrayMax]; + +#if EVMC4U_JA + [Header("トラッキングデバイス情報モニタ(表示用)")] +#else + [Header("Tracking Device Monitor")] +#endif + public string[] Types = new string[arrayMax]; + public Vector3[] Vector3s = new Vector3[arrayMax]; + +#if EVMC4U_JA + [Header("デイジーチェーン")] +#else + [Header("Daisy Chain")] +#endif + public GameObject[] NextReceivers = new GameObject[1]; + + private ExternalReceiverManager externalReceiverManager = null; + bool shutdown = false; + + Dictionary SerialIndexes = new Dictionary(); + int ListIndex = 0; + + //メッセージ処理一時変数struct(負荷対策) + Vector3 pos; + Quaternion rot; + + + void Start() + { + externalReceiverManager = new ExternalReceiverManager(NextReceivers); + StatusMessage = "Waiting for Master..."; + + //モニタ強制 + Types = new string[Serials.Length]; + Vector3s = new Vector3[Serials.Length]; + + //登録処理 + ListIndex = 0; + for (int i = 0; i < Serials.Length; i++) + { + //nullでも空白でもない場合(対象がある場合) + if (Serials[i] != null && Serials[i] != "") + { + //辞書に登録 + SerialIndexes.Add(Serials[i], ListIndex); + //インデックスを更新 + ListIndex++; + } + } + } + + //デイジーチェーンを更新 + public void UpdateDaisyChain() + { + externalReceiverManager.GetIExternalReceiver(NextReceivers); + } + + public void MessageDaisyChain(ref uOSC.Message message, int callCount) + { + //Startされていない場合無視 + if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) + { + return; + } + + if (shutdown) + { + return; + } + + StatusMessage = "OK"; + + //異常を検出して動作停止 + try + { + ProcessMessage(ref message); + } + catch (Exception e) + { + StatusMessage = "Error: Exception"; + Debug.LogError(" --- Communication Error ---"); + Debug.LogError(e.ToString()); + shutdown = true; + return; + } + + if (!externalReceiverManager.SendNextReceivers(message, callCount)) + { + StatusMessage = "Infinite loop detected!"; + shutdown = true; + } + } + + private void ProcessMessage(ref uOSC.Message message) + { + //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない + if (message.address == null || message.values == null) + { + StatusMessage = "Bad message."; + return; + } + + if (!RealPosition) + { + if (message.address == "/VMC/Ext/Hmd/Pos" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + + devideUpdate("HMD", (string)message.values[0], pos, rot); + //Debug.Log("HMD pos " + (string)message.values[0] + " : " + pos + "/" + rot); + } + // v2.2 + else if (message.address == "/VMC/Ext/Con/Pos" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + + devideUpdate("Controller", (string)message.values[0], pos, rot); + //Debug.Log("Con pos " + (string)message.values[0] + " : " + pos + "/" + rot); + } + // v2.2 + else if (message.address == "/VMC/Ext/Tra/Pos" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + + devideUpdate("Tracker", (string)message.values[0], pos, rot); + //Debug.Log("Tra pos " + (string)message.values[0] + " : " + pos + "/" + rot); + } + } + else { + if (message.address == "/VMC/Ext/Hmd/Pos/Local" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + + devideUpdate("HMD", (string)message.values[0], pos, rot); + //Debug.Log("HMD pos " + (string)message.values[0] + " : " + pos + "/" + rot); + } + // v2.2 + else if (message.address == "/VMC/Ext/Con/Pos/Local" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + + devideUpdate("Controller", (string)message.values[0], pos, rot); + //Debug.Log("Con pos " + (string)message.values[0] + " : " + pos + "/" + rot); + } + // v2.2 + else if (message.address == "/VMC/Ext/Tra/Pos/Local" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + + devideUpdate("Tracker", (string)message.values[0], pos, rot); + //Debug.Log("Tra pos " + (string)message.values[0] + " : " + pos + "/" + rot); + } + + } + } + + void devideUpdate(string type, string serial, Vector3 pos, Quaternion rot) + { + //辞書に登録済み + if (SerialIndexes.ContainsKey(serial)) + { + int i = SerialIndexes[serial]; + //配列を更新 + Types[i] = type; + Vector3s[i] = pos; + + if (i < Transforms.Length && Transforms[i] != null) + { + Transforms[i].localPosition = pos; + Transforms[i].localRotation = rot; + } + } + else + { + //最大を超えたら登録しない + if (ListIndex < Serials.Length) + { + //辞書に未登録 + + //辞書に登録 + Serials[ListIndex] = serial; + SerialIndexes.Add(serial, ListIndex); + //インデックスを更新 + ListIndex++; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogTabs.cs.meta b/Assets/External/EVMC4U/DeviceReceiver.cs.meta similarity index 83% rename from Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogTabs.cs.meta rename to Assets/External/EVMC4U/DeviceReceiver.cs.meta index 76e129bdc..6a0cf120a 100644 --- a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogTabs.cs.meta +++ b/Assets/External/EVMC4U/DeviceReceiver.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 829a678062065f04582189619babae79 +guid: 11e5ccb252b6916458ec049fa79a967e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/External/EVMC4U/DirectionalLightReceiver.cs b/Assets/External/EVMC4U/DirectionalLightReceiver.cs new file mode 100644 index 000000000..de1c519c2 --- /dev/null +++ b/Assets/External/EVMC4U/DirectionalLightReceiver.cs @@ -0,0 +1,158 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2020 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma warning disable 0414,0219 +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Profiling; + + +namespace EVMC4U +{ + public class DirectionalLightReceiver : MonoBehaviour, IExternalReceiver + { + [Header("DirectionalLightReceiver v1.2")] + [SerializeField, Label("VMCディレクショナルライト制御同期Light")] + public Light VMCControlledLight = null; //VMCディレクショナルライト制御同期 + [SerializeField, Label("動作状況")] + private string StatusMessage = ""; //Inspector表示用 + +#if EVMC4U_JA + [Header("デイジーチェーン")] +#else + [Header("Daisy Chain")] +#endif + public GameObject[] NextReceivers = new GameObject[1]; + + private ExternalReceiverManager externalReceiverManager = null; + bool shutdown = false; + + Vector3 pos; + Quaternion rot; + Color col; + + void Start() + { + externalReceiverManager = new ExternalReceiverManager(NextReceivers); + StatusMessage = "Waiting for Master..."; + } + + //デイジーチェーンを更新 + public void UpdateDaisyChain() + { + externalReceiverManager.GetIExternalReceiver(NextReceivers); + } + + void Update() + { + } + + public void MessageDaisyChain(ref uOSC.Message message, int callCount) + { + //Startされていない場合無視 + if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) + { + return; + } + + if (shutdown) + { + return; + } + + StatusMessage = "OK"; + + //異常を検出して動作停止 + try + { + ProcessMessage(ref message); + } + catch (Exception e) + { + StatusMessage = "Error: Exception"; + Debug.LogError(" --- Communication Error ---"); + Debug.LogError(e.ToString()); + shutdown = true; + return; + } + + if (!externalReceiverManager.SendNextReceivers(message, callCount)) + { + StatusMessage = "Infinite loop detected!"; + shutdown = true; + } + } + + private void ProcessMessage(ref uOSC.Message message) + { + //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない + if (message.address == null || message.values == null) + { + StatusMessage = "Bad message."; + return; + } + + //ライト同期 v2.4 + if (message.address == "/VMC/Ext/Light" + && (message.values[0] is string) //name + && (message.values[1] is float) //pos.x + && (message.values[2] is float) //poy.y + && (message.values[3] is float) //pos.z + && (message.values[4] is float) //q.x + && (message.values[5] is float) //q.y + && (message.values[6] is float) //q.z + && (message.values[7] is float) //q.w + && (message.values[8] is float) //r + && (message.values[9] is float) //g + && (message.values[10] is float) //b + && (message.values[11] is float) //a + ) + { + if(VMCControlledLight != null && VMCControlledLight.transform != null) + { + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + col.r = (float)message.values[8]; + col.g = (float)message.values[9]; + col.b = (float)message.values[10]; + col.a = (float)message.values[11]; + + VMCControlledLight.transform.localPosition = pos; + VMCControlledLight.transform.localRotation = rot; + VMCControlledLight.color = col; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs.meta b/Assets/External/EVMC4U/DirectionalLightReceiver.cs.meta similarity index 83% rename from Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs.meta rename to Assets/External/EVMC4U/DirectionalLightReceiver.cs.meta index 1127183e7..47ae56834 100644 --- a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs.meta +++ b/Assets/External/EVMC4U/DirectionalLightReceiver.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 86cbd6470ebef2f4c976410efaf45638 +guid: 13f0517c7c0be404f8b9374d915fedb1 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/External/VRMShaders/VRM/IO/Editor.meta b/Assets/External/EVMC4U/Editor.meta similarity index 77% rename from Assets/External/VRMShaders/VRM/IO/Editor.meta rename to Assets/External/EVMC4U/Editor.meta index 8ccaa983d..3eaeba639 100644 --- a/Assets/External/VRMShaders/VRM/IO/Editor.meta +++ b/Assets/External/EVMC4U/Editor.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 36a5a07493511bd49b1ad9dbad2683d2 +guid: 3186d82257ef78346a44ce5a543fda47 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/External/EVMC4U/Editor/ExternalReceiverEditor.cs b/Assets/External/EVMC4U/Editor/ExternalReceiverEditor.cs new file mode 100644 index 000000000..eaad1a071 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/ExternalReceiverEditor.cs @@ -0,0 +1,53 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2020 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace EVMC4U +{ + [CustomEditor(typeof(ExternalReceiver))] + public class ExternalReceiverEditor : Editor + { + public override void OnInspectorGUI() + { +#if EVMC4U_JA + if (GUILayout.Button("説明書を開く")) + { + Tutorial.Open(); + } +#else + if (GUILayout.Button("Open Manual")) + { + Tutorial.Open(); + } +#endif + base.OnInspectorGUI(); + } + } +} diff --git a/Assets/External/EVMC4U/Editor/ExternalReceiverEditor.cs.meta b/Assets/External/EVMC4U/Editor/ExternalReceiverEditor.cs.meta new file mode 100644 index 000000000..f7e44a6a2 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/ExternalReceiverEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8377d1e33297dac458dca9e5f91a8cc4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF.meta b/Assets/External/EVMC4U/Editor/Resources.meta similarity index 77% rename from Assets/External/VRMShaders/VRM/IO/Runtime/GLTF.meta rename to Assets/External/EVMC4U/Editor/Resources.meta index 38d4fd8e7..fdccb253d 100644 --- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF.meta +++ b/Assets/External/EVMC4U/Editor/Resources.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d9c97ad7f5bbcac489a47a2f34dfff00 +guid: a374e0d063f66c049968ffeb3df4a3ee folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Util.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial.meta similarity index 77% rename from Assets/External/UniGLTF/Runtime/UniGLTF/Util.meta rename to Assets/External/EVMC4U/Editor/Resources/tutorial.meta index 84a19a442..46ce3522f 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/Util.meta +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1595b81f792ed7b469e4391dcc7d335f +guid: bee88dde7402d2d40b3d9200c336f466 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/caution_bg.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/caution_bg.png new file mode 100644 index 000000000..e37523ad7 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/caution_bg.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88ec57b74fbfe2c065c9a5768607b07150fef31fd59b7175d5da166ae68c0045 +size 204721 diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/a.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/caution_bg.png.meta similarity index 80% rename from Assets/External/UniGLTF/Samples/ScreenSpace/a.png.meta rename to Assets/External/EVMC4U/Editor/Resources/tutorial/caution_bg.png.meta index eaf9b5af2..457fb0312 100644 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/a.png.meta +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/caution_bg.png.meta @@ -1,12 +1,12 @@ fileFormatVersion: 2 -guid: c5d5d944a6503a348af34f68dfa868d4 +guid: 09fe3fc8a3f76cd489976f4245781880 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 11 mipmaps: mipMapMode: 0 - enableMipMap: 1 + enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 @@ -34,10 +34,10 @@ TextureImporter: filterMode: 1 aniso: 1 mipBias: 0 - wrapU: 0 - wrapV: 0 + wrapU: 1 + wrapV: 1 wrapW: 0 - nPOTScale: 1 + nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 @@ -49,9 +49,9 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 - alphaIsTransparency: 0 + alphaIsTransparency: 1 spriteTessellationDetail: -1 - textureType: 0 + textureType: 2 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 @@ -71,6 +71,18 @@ TextureImporter: overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/define.txt b/Assets/External/EVMC4U/Editor/Resources/tutorial/define.txt new file mode 100644 index 000000000..f5c2084d2 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/define.txt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ff4e710b96cb1c4dc994c9eac48e01a55377d5d69d09cae3d22a07ae08685e9 +size 1807 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/define.txt.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/define.txt.meta new file mode 100644 index 000000000..9a5c2edc0 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/define.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 72e1f7be484f4a049a6925bd9ab160d3 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/ignore.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/ignore.png new file mode 100644 index 000000000..b37ba3d4f --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/ignore.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e064002f5f5d1b6d09a033a2f9962d8a58e12a3ae10a76a4654b51be6ba69977 +size 65681 diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/b.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/ignore.png.meta similarity index 80% rename from Assets/External/UniGLTF/Samples/ScreenSpace/b.png.meta rename to Assets/External/EVMC4U/Editor/Resources/tutorial/ignore.png.meta index 9bb3b5005..dd3bd60eb 100644 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/b.png.meta +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/ignore.png.meta @@ -1,12 +1,12 @@ fileFormatVersion: 2 -guid: 6e9a09d0d9f0a894ab333e0ea709810e +guid: 50dac6eee108fcc40a7aa2708460ad83 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 11 mipmaps: mipMapMode: 0 - enableMipMap: 1 + enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 @@ -34,10 +34,10 @@ TextureImporter: filterMode: 1 aniso: 1 mipBias: 0 - wrapU: 0 - wrapV: 0 + wrapU: 1 + wrapV: 1 wrapW: 0 - nPOTScale: 1 + nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 @@ -49,9 +49,9 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 - alphaIsTransparency: 0 + alphaIsTransparency: 1 spriteTessellationDetail: -1 - textureType: 0 + textureType: 2 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 @@ -71,6 +71,18 @@ TextureImporter: overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/ok_button.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/ok_button.png new file mode 100644 index 000000000..4c65a7c35 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/ok_button.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3d10be97ce4e733d237285944438490fd82faa0252d5d63c0ae9d5b956069e04 +size 18299 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/ok_button.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/ok_button.png.meta new file mode 100644 index 000000000..a2e66e7ce --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/ok_button.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 6e3835e9948ccbf4ba54209dc672ca7f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start.meta new file mode 100644 index 000000000..cc2a95c5f --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc1e38df2f2e3cb4e8790360fa9c40dd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_bg.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_bg.png new file mode 100644 index 000000000..261283f5c --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_bg.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f3b1f44239db87c8ad3897eafc0596e3693fad72d9a447022a4c61e765a9407 +size 268820 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_bg.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_bg.png.meta new file mode 100644 index 000000000..69560c7f4 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_bg.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: d4c7fbbf3c8947642b9cbc4ba15f0df1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_english.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_english.png new file mode 100644 index 000000000..0c51a565b --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_english.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1983cd75e984f6eef98ebc773ce3bc8632f3173b80f49cd982faeb2f2d55d1eb +size 23627 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_english.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_english.png.meta new file mode 100644 index 000000000..c71c3b15b --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_english.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 8a9a093e2909a574b8a69a9c0d032158 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_japanese.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_japanese.png new file mode 100644 index 000000000..a187eb95b --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_japanese.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed51dfbb7e7335fcf9bcdcd650dfef11230c55acc761beaad354a0c9f9cc276 +size 17908 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_japanese.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_japanese.png.meta new file mode 100644 index 000000000..e61b22842 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start/start_japanese.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 1e9c002a5915b0c41bce8813c859270f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en.meta new file mode 100644 index 000000000..b35d7ca19 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3cf99d0802e7abd41b513dd6ece2b371 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/discord.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/discord.png new file mode 100644 index 000000000..ff56dbb8e --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/discord.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8c9e442bbf4bd00f184863352b70659bc867adc50b6ec6fbbaaed2a43007b30 +size 34018 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/discord.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/discord.png.meta new file mode 100644 index 000000000..df7948644 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/discord.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 8bd00136add62bd44b0c7692a8abd17d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/howtouse.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/howtouse.png new file mode 100644 index 000000000..e0b2fd4ce --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/howtouse.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cebfd2d52ab989337a62d8dbe5ff2d22d542e5faf474a73379f62bf572c0e927 +size 38935 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/howtouse.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/howtouse.png.meta new file mode 100644 index 000000000..b6c7cc203 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/howtouse.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 481805f552d5a1c42866f2c76e80d9d1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/vmcprotocol.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/vmcprotocol.png new file mode 100644 index 000000000..bb9412422 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/vmcprotocol.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:45143adb5ca294aaa3b61791e98d3bc874a7b5d38fa2aabadf6673ef9abd2c71 +size 51379 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/vmcprotocol.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/vmcprotocol.png.meta new file mode 100644 index 000000000..357405955 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_en/vmcprotocol.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: efbc73509d25aea43aa7e5f70fb49c3b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first.meta new file mode 100644 index 000000000..4383ff98d --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a83f9e79c7345284988cabbd2ef406b6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/en.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/en.png new file mode 100644 index 000000000..f8e1caa79 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11da8df065d0e05904b59771fe87ce689a6da6e10918e555cd58815afbec0ac6 +size 725866 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/en.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/en.png.meta new file mode 100644 index 000000000..38f1422d5 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/en.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: f0c4f23b400062b4293d2cdd97b02503 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/ja.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/ja.png new file mode 100644 index 000000000..78aaebe0c --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/ja.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5fed286df7d2990dd164abec74e8c6d4e2e87458c5ba8373cf8c8d0ae0d0b4f +size 721681 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/ja.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/ja.png.meta new file mode 100644 index 000000000..a0202e417 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_first/ja.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 3b776da16c770c8478ca233bef64f2b1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja.meta new file mode 100644 index 000000000..680f41744 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a63eda723d10ef4cac2d457e66fc2ef +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/discord.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/discord.png new file mode 100644 index 000000000..86171319a --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/discord.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c78e0387ff2fb3c34aec2b1b61d20944e4ec21cabd027bc5976206ef40970773 +size 46236 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/discord.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/discord.png.meta new file mode 100644 index 000000000..e33006b62 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/discord.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 436fee3bd2ead154f87f05481d675208 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/howtouse.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/howtouse.png new file mode 100644 index 000000000..a30b5f3eb --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/howtouse.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63ca71736748f1f22202289e3eb35c4d15adec264b8c2ea63ce65a358f6f3a7d +size 24824 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/howtouse.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/howtouse.png.meta new file mode 100644 index 000000000..6c6525dc6 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/howtouse.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 803fc02753744be4fbfebcd748d5c12a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/vmcprotocol.png b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/vmcprotocol.png new file mode 100644 index 000000000..dbddbc90a --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/vmcprotocol.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d23d4d65038fb320844b7cf91e704858d8c783d5ad21f30a8a0f5aa5115e3c1c +size 62951 diff --git a/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/vmcprotocol.png.meta b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/vmcprotocol.png.meta new file mode 100644 index 000000000..ab4fe9d14 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Resources/tutorial/start_ja/vmcprotocol.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: ae1ea106244ca354f903f9b7c235398f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Editor/Tutorial.cs b/Assets/External/EVMC4U/Editor/Tutorial.cs new file mode 100644 index 000000000..18bc00b4e --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Tutorial.cs @@ -0,0 +1,377 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2020-2022 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma warning disable CS0162 +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using UnityEngine; +using UnityEditor; +using UnityEditor.AnimatedValues; +using UnityEngine.Events; +using System.Linq; + +namespace EVMC4U +{ + public class Tutorial : EditorWindow + { + const bool check = false; //バージョンチェック条件式があったが、バージョン番号がなくなったので無効化 + const int window_w = 400; + const int window_h = 400; + + //ページ名 + static string page = ""; + + //ボタン押下アニメーション + static AnimFloat anim = new AnimFloat(0.001f); + static string animTargetName = ""; //1つのボタンだけアニメさせる識別名 + + static string jsonError = ""; + + static TutorialJson tutorialJson = null; + static Dictionary tutorialPages = new Dictionary(); + + //JSON設定ファイル定義 + [Serializable] + private class TutorialJson + { + public bool debug; + public TutorialPage[] pages; + public override string ToString() + { + return "TutorialJson debug:" + debug + " pages:" + pages.Length; + } + } + + //JSONページ定義 + [Serializable] + private class TutorialPage + { + public string name = ""; + public string text = ""; + public string image = ""; + public TutorialButton[] buttons = new TutorialButton[0]; + + public override string ToString() + { + return "TutorialPage name:" + name + " text:" + text + " iamge:" + image + " buttons:" + buttons.Length; + } + } + + //JSONボタン定義 + [Serializable] + private class TutorialButton + { + public int x = 0; + public int y = 0; + public int w = 0; + public int h = 0; + + public string text = ""; + + public string image = ""; + public string uri = ""; //"page://" = page, "http://" or "https://" = url + public string fire = ""; //event + public override string ToString() + { + return "TutorialButton (" + x + "," + y + "," + w + "," + h + ") text:" + text + " image:" + image + " uri:" + uri; + } + } + + [InitializeOnLoadMethod] + static void InitializeOnLoad() + { + //一度も開いたことない場合は、ここで開く + if (EditorUserSettings.GetConfigValue("Opened") != "1" || (check && EditorUserSettings.GetConfigValue("VRMCheckCaution") != "1")) + { + Open(); + } + } + + [MenuItem("EVMC4U/Oepn Tutorial")] + public static void Open() + { + //ウィンドウサイズを固定 + var window = GetWindow(); + window.maxSize = new Vector2(window_w, window_h - 6); + window.minSize = window.maxSize; + + //アニメーション定義 + anim.value = 0.001f; + anim.speed = 10f; + anim.target = 0.001f; + anim.valueChanged = null; + + if (Resources.Load("tutorial/define") == null) + { + //読み込み準備ができていない + return; + } + + //ページを初期位置に設定 + page = "start"; + if (EditorUserSettings.GetConfigValue("Language") == "ja") + { + page = "start_ja"; + } + if (EditorUserSettings.GetConfigValue("Language") == "en") + { + page = "start_en"; + } + + + //データを読み込む + tutorialPages = new Dictionary(); + + try + { + jsonError = ""; + var r = Resources.Load("tutorial/define"); + tutorialJson = JsonUtility.FromJson(r.text); + if (tutorialJson.debug) + { + Debug.Log(tutorialJson); + } + + //各ページのデータを読み込む + foreach (var p in tutorialJson.pages) + { + tutorialPages.Add(p.name, p); + if (tutorialJson.debug) + { + Debug.Log(p); + } + } + + //一度開いたのを覚えておく + EditorUserSettings.SetConfigValue("Opened", "1"); + } + catch (ArgumentException e) + { + //Debug.LogError(e); + jsonError = e.ToString(); + tutorialJson = null; + } + + //バージョンチェック(失敗したら失敗ページに飛ばす) + if (check) + { + EditorUserSettings.SetConfigValue("VRMCheckCaution", "1"); + page = "versionCheckFailed"; + } + else + { + EditorUserSettings.SetConfigValue("VRMCheckCaution", "0"); + } + } + + [MenuItem("EVMC4U/Reset Language")] + public static void ResetLanguage() + { + EditorUserSettings.SetConfigValue("Language", ""); + Open(); + } + + void OnGUI() + { + //ページを開いたまま初期化されたら、初期ロード処理に飛ばす + if (page == "") + { + GUI.Label(new Rect(10, 10, window_w, window_h), "INVALID STATE\n\nチュートリアルの読み込みに失敗しました。Unityを再起動してください。\nそれでもダメな場合は、UnityPackageの導入からやり直してみてください\n\nTutorial load failed.\nPlease restart Unity.\nor Please re-import UnityPackage."); + Open(); + return; + } + + //アニメーションを立ち上げる + if (anim.valueChanged == null) + { + var repaintEvent = new UnityEvent(); + repaintEvent.AddListener(() => Repaint()); + anim.valueChanged = repaintEvent; + } + + //アニメーション折り返し + if (anim.value > anim.target - 0.1f) + { + anim.target = 0.001f; + } + + //ページの表示処理を開始 + TutorialPage tutorialPage; + if (!tutorialPages.TryGetValue(page, out tutorialPage)) + { + //JSONが多分バグってるときに表示 + GUI.Label(new Rect(10, 10, window_w - 20, window_h), "JSON LOAD FAILED\n" + jsonError + "\n\nチュートリアルの読み込みに失敗しました。Unityを再起動してください。\nそれでもダメな場合は、UnityPackageの導入からやり直してみてください\n\nTutorial load failed.\nPlease restart Unity.\nor Please re-import UnityPackage."); + if (GUI.Button(new Rect(0, window_h - 30, window_w, 30), "Reload")) + { + Open(); + } + return; + } + + //デバッグログ + if (tutorialJson.debug) + { + Debug.Log("OnGUI: " + anim.value); + Debug.Log(tutorialPage); + } + + //背景画像があれば表示 + if (tutorialPage.image != "") + { + var bgtexture = Resources.Load("tutorial/" + tutorialPage.image); + EditorGUI.DrawPreviewTexture(new Rect(0, 0, window_w, window_h), bgtexture); + } + + //ページのテキストを表示(代替テキスト) + GUI.Label(new Rect(0, 0, window_w, window_h), tutorialPage.text); + + //ボタンを1つずつ表示 + foreach (var b in tutorialPage.buttons) + { + if (tutorialJson.debug) + { + Debug.Log(b); + } + + //ボタンに画像があればそれを表示 + if (b.image != "") + { + //画像を読み込む + var texture = Resources.Load("tutorial/" + b.image); + + //位置情報がない場合、下端として扱う + if (b.x == 0 && b.y == 0 && b.w == 0 && b.h == 0) + { + b.y = window_h - window_w * texture.height / texture.width; + b.w = window_w; + } + + string buttonName = "btn#" + page + "#" + b.x + "-" + b.y + "-" + b.w + "-" + b.h; + float height = b.w * texture.height / texture.width; + + Rect r = new Rect(b.x, b.y, b.w, height); + + //アニメ対象の場合だけ動く + if (buttonName == animTargetName) + { + r = new Rect(b.x + anim.value, b.y + anim.value, b.w, height); + } + + //ボタンを表示 + if (GUI.Button(r, texture, new GUIStyle())) + { + //アニメーション処理と、遷移を実行 + buttonFireProcess(b.fire); + buttonUriProcess(b.uri); + animTargetName = buttonName; + anim.target = 2f; + } + } + else + { + //テキストボタンを表示 + if (GUI.Button(new Rect(b.x, b.y, b.w, b.h), b.text)) + { + buttonFireProcess(b.fire); + buttonUriProcess(b.uri); + } + } + } + + //デバッグ再読み込みボタン + if (tutorialJson.debug) + { + if (GUI.Button(new Rect(0, window_h - 30, 30, 30), "#")) + { + Open(); + } + } + } + + void buttonUriProcess(string uri) + { + if (tutorialJson.debug) + { + Debug.LogWarning("buttonProcess: " + uri); + } + + if (uri == null) + { + return; + } + if (uri.StartsWith("page://")) + { + page = uri.Replace("page://", ""); + } + if (uri.StartsWith("http://") || uri.StartsWith("https://")) + { + System.Diagnostics.Process.Start(uri); + } + } + + void buttonFireProcess(string fire) + { + switch (fire) + { + case "SaveLanguageJa": + { + EditorUserSettings.SetConfigValue("Language", "ja"); + var symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone).Split(';').ToList(); + if (symbols.Contains("EVMC4U_EN")) + { + symbols.Remove("EVMC4U_EN"); + } + if (!symbols.Contains("EVMC4U_JA")) + { + symbols.Add("EVMC4U_JA"); + } + PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, String.Join(";", symbols.ToArray())); + + break; + } + case "SaveLanguageEn": + { + EditorUserSettings.SetConfigValue("Language", "en"); + var symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone).Split(';').ToList(); + if (symbols.Contains("EVMC4U_JA")) + { + symbols.Remove("EVMC4U_JA"); + } + if (!symbols.Contains("EVMC4U_EN")) + { + symbols.Add("EVMC4U_EN"); + } + PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, String.Join(";", symbols.ToArray())); + + break; + } + default: break; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/Editor/Tutorial.cs.meta b/Assets/External/EVMC4U/Editor/Tutorial.cs.meta new file mode 100644 index 000000000..15d1c94f7 --- /dev/null +++ b/Assets/External/EVMC4U/Editor/Tutorial.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3239c5d6ed07cd84a95fd80d1659dcce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/ExternalController.cs b/Assets/External/EVMC4U/ExternalController.cs new file mode 100644 index 000000000..796e8afaa --- /dev/null +++ b/Assets/External/EVMC4U/ExternalController.cs @@ -0,0 +1,199 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2020 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma warning disable 0414,0219 + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Profiling; + + +namespace EVMC4U +{ + [RequireComponent(typeof(uOSC.uOscClient))] + public class ExternalController : MonoBehaviour + { + [Header("ExternalController v1.0")] + public bool enable = true; + [Header("Frame Period")] + public int PeriodOfStatus = 1; + public int PeriodOfRoot = 1; + public int PeriodOfBone = 1; + public int PeriodOfBlendShape = 1; + public int PeriodOfCamera = 1; + public int PeriodOfDevices = 1; + public bool PeriodEnable = false; + + [Header("Virtual Device")] + public VirtualDevice DeviceMode = VirtualDevice.Tracker; + public Transform DeviceTransform = null; + public String DeviceSerial = "VIRTUAL_DEVICE"; + public bool DeviceEnable = false; + + [Header("Virtual MIDI CC")] + public int MidiKnob = 0; + public float MidiValue = 0f; + public bool MidiEnable = false; + + [Header("Camera Control")] + public Transform CameraTransform = null; + public float CameraFOV = 30f; + public bool CameraEnable = false; + + [Header("BlendShapeProxy")] + public string BlendShapeName = ""; + public float BlendShapeValue = 0f; + public bool BlendShapeEnable = false; + + [Header("Eye Tracking Target Position")] + public Transform EyeTrackingTargetTransform = null; + public bool EyeTrackingTargetUse = false; + public bool EyeTrackingTargetEnable = false; + + [Header("Response String")] + public string ResponseString = ""; + public bool ResponseStringEnable = false; + + [Header("Calibration")] + public bool CalibrationReady = false; + public CalibrationMode calibrationMode = 0; + public bool CalibrationExecute = false; + + [Header("Config")] + public string ConfigPath = ""; + public bool ConfigLoad = false; + + [Header("Request Information")] + public bool RequestInformation = false; + + uOSC.uOscClient client = null; + + void Start() + { + client = GetComponent(); + } + void Update() + { + if (client == null) { + return; + } + if (!enable) { + return; + } + + if (PeriodEnable) { + client.Send("/VMC/Ext/Set/Period", PeriodOfStatus, PeriodOfRoot, PeriodOfBone, PeriodOfBlendShape, PeriodOfCamera, PeriodOfDevices); + } + if (DeviceEnable) { + string name = null; + switch (DeviceMode) { + case VirtualDevice.HMD: + name = "/VMC/Ext/Hmd/Pos"; + break; + case VirtualDevice.Controller: + name = "/VMC/Ext/Con/Pos"; + break; + case VirtualDevice.Tracker: + name = "/VMC/Ext/Tra/Pos"; + break; + default: + name = null; + break; + } + if (name != null && DeviceTransform != null && DeviceSerial != null) { + client.Send(name, + (string)DeviceSerial, + (float)DeviceTransform.position.x, + (float)DeviceTransform.position.y, + (float)DeviceTransform.position.z, + (float)DeviceTransform.rotation.x, + (float)DeviceTransform.rotation.y, + (float)DeviceTransform.rotation.z, + (float)DeviceTransform.rotation.w); + } + } + if (MidiEnable) + { + client.Send("/VMC/Ext/Midi/CC/Val", MidiKnob, MidiValue); + } + if (CameraEnable) + { + client.Send("/VMC/Ext/Cam", + "Camera", + (float)CameraTransform.position.x, + (float)CameraTransform.position.y, + (float)CameraTransform.position.z, + (float)CameraTransform.rotation.x, + (float)CameraTransform.rotation.y, + (float)CameraTransform.rotation.z, + (float)CameraTransform.rotation.w, + (float)CameraFOV); + } + if (BlendShapeEnable) + { + client.Send("/VMC/Ext/Blend/Val", BlendShapeName, BlendShapeValue); + client.Send("/VMC/Ext/Blend/Apply"); + } + if (EyeTrackingTargetEnable) + { + client.Send("/VMC/Ext/Set/Eye", + EyeTrackingTargetUse?(int)1: (int)0, + (float)EyeTrackingTargetTransform.position.x, + (float)EyeTrackingTargetTransform.position.y, + (float)EyeTrackingTargetTransform.position.z); + } + if (ResponseStringEnable) + { + client.Send("/VMC/Ext/Set/Res", ResponseString); + } + if (CalibrationReady) + { + CalibrationReady = false; + client.Send("/VMC/Ext/Set/Calib/Ready"); + } + if (CalibrationExecute) + { + CalibrationExecute = false; + client.Send("/VMC/Ext/Set/Calib/Exec", (int)calibrationMode); + } + if (ConfigLoad) + { + ConfigLoad = false; + client.Send("/VMC/Ext/Set/Config", ConfigPath); + } + if (RequestInformation) + { + //毎フレーム送信要求をする + client.Send("/VMC/Ext/Set/Req"); + } + } + } + +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/ExternalController.cs.meta b/Assets/External/EVMC4U/ExternalController.cs.meta new file mode 100644 index 000000000..9c8edbb5c --- /dev/null +++ b/Assets/External/EVMC4U/ExternalController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3c76998320436b479e734d3703c3abc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/ExternalReceiver.cs b/Assets/External/EVMC4U/ExternalReceiver.cs new file mode 100644 index 000000000..bf53443c0 --- /dev/null +++ b/Assets/External/EVMC4U/ExternalReceiver.cs @@ -0,0 +1,1446 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma warning disable 0414,0219 + +using System; +using System.Reflection; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Profiling; +using UniGLTF; +using UniVRM10; + +namespace EVMC4U +{ + //[RequireComponent(typeof(uOSC.uOscServer))] + public class ExternalReceiver : MonoBehaviour, IExternalReceiver + { + [Header("ExternalReceiver v5.0a")] + [SerializeField, Label("VRMモデルのGameObject")] + public GameObject Model = null; + [SerializeField, Label("一時停止")] + public bool Freeze = false; //すべての同期を止める(撮影向け) + [SerializeField, Label("パケットリミッター")] + public bool PacktLimiter = true; //パケットフレーム数が一定値を超えるとき、パケットを捨てる + +#if EVMC4U_JA + [Header("ルート姿勢同期オプション")] +#else + [Header("Root Synchronize Option")] +#endif + [SerializeField, Label("ルート位置反映対象(VR向け)")] + public Transform RootPositionTransform = null; //VR向けroot位置同期オブジェクト指定 + [SerializeField, Label("ルート回転反映対象(VR向け)")] + public Transform RootRotationTransform = null; //VR向けroot回転同期オブジェクト指定 + [SerializeField, Label("ルート位置反映")] + public bool RootPositionSynchronize = true; //ルート座標同期(ルームスケール移動) + [SerializeField, Label("ルート回転反映")] + public bool RootRotationSynchronize = true; //ルート回転同期 + [SerializeField, Label("ルートスケール反映")] + public bool RootScaleOffsetSynchronize = false; //MRスケール適用 + +#if EVMC4U_JA + [Header("その他の同期オプション")] +#else + [Header("Other Synchronize Option")] +#endif + [SerializeField, Label("表情の同期")] + public bool BlendShapeSynchronize = true; //表情等同期 + [SerializeField, Label("ボーン位置の厳密な同期")] + public bool BonePositionSynchronize = true; //ボーン位置適用(回転は強制) + +#if EVMC4U_JA + [Header("同期遮断オプション")] +#else + [Header("Synchronize Cutoff Option")] +#endif + [SerializeField, Label("指ボーンを同期しない")] + public bool HandPoseSynchronizeCutoff = false; //指状態反映オフ + [SerializeField, Label("目ボーンを同期しない")] + public bool EyeBoneSynchronizeCutoff = false; //目ボーン反映オフ + +#if EVMC4U_JA + [Header("なめらかフィルター")] +#else + [Header("Lowpass Filter Option")] +#endif + [SerializeField, Label("ボーン位置なめらか")] + public bool BonePositionFilterEnable = false; //ボーン位置フィルタ + [SerializeField, Label("ボーン回転なめらか")] + public bool BoneRotationFilterEnable = false; //ボーン回転フィルタ + [SerializeField, Label("なめらか係数(0.500~0.999)")] + public float BoneFilter = 0.7f; //ボーンフィルタ係数 + [SerializeField, Label("表情なめらか")] + public bool BlendShapeFilterEnable = false; //BlendShapeフィルタ + [SerializeField, Label("表情なめらか係数(0.500~0.999)")] + public float BlendShapeFilter = 0.7f; //BlendShapeフィルタ係数 + +#if EVMC4U_JA + [Header("VRMファイル自動読み込み")] +#else + [Header("VRM Loader Option")] +#endif + [SerializeField, Label("VRMファイル自動読み込み(対応アプリのみ)")] + public bool enableAutoLoadVRM = true; //VRMの自動読み込みの有効可否 + +#if EVMC4U_JA + [Header("その他")] +#else + [Header("Other Option")] +#endif + [SerializeField, Label("更新タイミングをLateUpdateにする(Animationの後に実行して上書きする)")] + public bool EnableLateUpdateForOverwriteAnimationResult = false; //LateUpdateにするかどうか(Animationの後に実行して上書きする) + [SerializeField, Label("未キャリブレーション時にモデルを隠す")] + public bool HideInUncalibrated = false; //キャリブレーション出来ていないときは隠す + [SerializeField, Label("MRモード連動")] + public bool SyncCalibrationModeWithScaleOffsetSynchronize = true; //キャリブレーションモードとスケール設定を連動させる + public Action BeforeModelDestroyAction = null; //破壊時Action + public Action AfterAutoLoadAction = null; //自動ロード時Action + [SerializeField, Label("VRM1正規化ボーン選択(ロード時)")] + public UniVRM10.ControlRigGenerationOption controlRigGenerationOptionOnLoad = UniVRM10.ControlRigGenerationOption.None; //VRM1正規化ボーン(非推奨) + + +#if EVMC4U_JA + [Header("現在の状態(表示用)")] +#else + [Header("Status (Read only)")] +#endif + [SerializeField, Label("動作状況")] + private string StatusMessage = ""; //状態メッセージ(Inspector表示用) + [SerializeField, Label("オプション文字列")] + public string OptionString = ""; //VMCから送信されるオプション文字列 + + [SerializeField, Label("自動読み込みVRMパス")] + public string loadedVRMPath = ""; //読み込み済みVRMパス + [SerializeField, Label("自動読み込みVRM名前")] + public string loadedVRMName = ""; //読み込み済みVRM名前 + [SerializeField, Label("読み込んだモデルの親GameObject")] + public GameObject LoadedModelParent = null; //読み込んだモデルの親 + [SerializeField, Label("読み込んだVRMの種別")] + public string loadedVRMType = ""; //読み込んだ種別 + + [SerializeField, Label("1フレームあたりのパケットフレーム数")] + public int LastPacketframeCounterInFrame = 0; //1フレーム中に受信したパケットフレーム数 + [SerializeField, Label("廃棄されたパケット数")] + public int DropPackets = 0; //廃棄されたパケット(not パケットフレーム) + + public Vector3 HeadPosition = Vector3.zero; + +#if EVMC4U_JA + [Header("デイジーチェーン")] +#else + [Header("Daisy Chain")] +#endif + public GameObject[] NextReceivers = new GameObject[6]; //デイジーチェーン + +#if EVMC4U_JA + [Header("ボーンの個別遮断(下半身、腕のみなど)")] +#else + [Header("Cut bones")] +#endif + [SerializeField, Label("有効")] + public bool CutBonesEnable = false; + +#if EVMC4U_JA + [Header("遮断ボーン (Head)")] +#else + [Header("Cut bones(Head)")] +#endif + [SerializeField, Label("Neck遮断")] + public bool CutBoneNeck = false; + [SerializeField, Label("Head遮断")] + public bool CutBoneHead = false; + [SerializeField, Label("LeftEye遮断")] + public bool CutBoneLeftEye = false; + [SerializeField, Label("RightEye遮断")] + public bool CutBoneRightEye = false; + [SerializeField, Label("Jaw遮断")] + public bool CutBoneJaw = false; + +#if EVMC4U_JA + [Header("遮断ボーン (Body)")] +#else + [Header("Cut bones(Body)")] +#endif + [SerializeField, Label("Hips遮断")] + public bool CutBoneHips = true; + [SerializeField, Label("Spine遮断")] + public bool CutBoneSpine = true; + [SerializeField, Label("Chest遮断")] + public bool CutBoneChest = true; + [SerializeField, Label("UpperChest遮断")] + public bool CutBoneUpperChest = true; + +#if EVMC4U_JA + [Header("遮断ボーン (Left Arm)")] +#else + [Header("Cut bones(Left Arm)")] +#endif + [SerializeField, Label("LeftShoulder遮断")] + public bool CutBoneLeftShoulder = false; + [SerializeField, Label("LeftUpperArm遮断")] + public bool CutBoneLeftUpperArm = false; + [SerializeField, Label("LeftLowerArm遮断")] + public bool CutBoneLeftLowerArm = false; + [SerializeField, Label("LeftHand遮断")] + public bool CutBoneLeftHand = false; + +#if EVMC4U_JA + [Header("遮断ボーン (Right Arm)")] +#else + [Header("Cut bones(Right Arm)")] +#endif + [SerializeField, Label("RightShoulder遮断")] + public bool CutBoneRightShoulder = false; + [SerializeField, Label("RightUpperArm遮断")] + public bool CutBoneRightUpperArm = false; + [SerializeField, Label("RightLowerArm遮断")] + public bool CutBoneRightLowerArm = false; + [SerializeField, Label("RightHand遮断")] + public bool CutBoneRightHand = false; + +#if EVMC4U_JA + [Header("遮断ボーン (Left Leg)")] +#else + [Header("Cut bones(Left Leg)")] +#endif + [SerializeField, Label("LeftUpperLeg遮断")] + public bool CutBoneLeftUpperLeg = true; + [SerializeField, Label("LeftLowerLeg遮断")] + public bool CutBoneLeftLowerLeg = true; + [SerializeField, Label("LeftFoot遮断")] + public bool CutBoneLeftFoot = true; + [SerializeField, Label("LeftToes遮断")] + public bool CutBoneLeftToes = true; + +#if EVMC4U_JA + [Header("遮断ボーン (Right Leg)")] +#else + [Header("Cut bones(Right Leg)")] +#endif + [SerializeField, Label("RightUpperLeg遮断")] + public bool CutBoneRightUpperLeg = true; + [SerializeField, Label("RightLowerLeg遮断")] + public bool CutBoneRightLowerLeg = true; + [SerializeField, Label("RightFoot遮断")] + public bool CutBoneRightFoot = true; + [SerializeField, Label("RightToes遮断")] + public bool CutBoneRightToes = true; + +#if EVMC4U_JA + [Header("遮断ボーン (Left Hand)")] +#else + [Header("Cut bones(Left Hand)")] +#endif + [SerializeField, Label("LeftThumbProximal遮断")] + public bool CutBoneLeftThumbProximal = false; + [SerializeField, Label("LeftThumbIntermediate遮断")] + public bool CutBoneLeftThumbIntermediate = false; + [SerializeField, Label("LeftThumbDistal遮断")] + public bool CutBoneLeftThumbDistal = false; + [SerializeField, Label("LeftIndexProximal遮断")] + public bool CutBoneLeftIndexProximal = false; + [SerializeField, Label("LeftIndexIntermediate遮断")] + public bool CutBoneLeftIndexIntermediate = false; + [SerializeField, Label("LeftIndexDistal遮断")] + public bool CutBoneLeftIndexDistal = false; + [SerializeField, Label("LeftMiddleProximal遮断")] + public bool CutBoneLeftMiddleProximal = false; + [SerializeField, Label("LeftMiddleIntermediate遮断")] + public bool CutBoneLeftMiddleIntermediate = false; + [SerializeField, Label("LeftMiddleDistal遮断")] + public bool CutBoneLeftMiddleDistal = false; + [SerializeField, Label("LeftRingProximal遮断")] + public bool CutBoneLeftRingProximal = false; + [SerializeField, Label("LeftRingIntermediate遮断")] + public bool CutBoneLeftRingIntermediate = false; + [SerializeField, Label("LeftRingDistal遮断")] + public bool CutBoneLeftRingDistal = false; + [SerializeField, Label("LeftLittleProximal遮断")] + public bool CutBoneLeftLittleProximal = false; + [SerializeField, Label("LeftLittleIntermediate遮断")] + public bool CutBoneLeftLittleIntermediate = false; + [SerializeField, Label("LeftLittleDistal遮断")] + public bool CutBoneLeftLittleDistal = false; + +#if EVMC4U_JA + [Header("遮断ボーン (Right Hand)")] +#else + [Header("Cut bones(Right Hand)")] +#endif + [SerializeField, Label("RightThumbProximal遮断")] + public bool CutBoneRightThumbProximal = false; + [SerializeField, Label("RightThumbIntermediate遮断")] + public bool CutBoneRightThumbIntermediate = false; + [SerializeField, Label("RightThumbDistal遮断")] + public bool CutBoneRightThumbDistal = false; + [SerializeField, Label("RightIndexProximal遮断")] + public bool CutBoneRightIndexProximal = false; + [SerializeField, Label("RightIndexIntermediate遮断")] + public bool CutBoneRightIndexIntermediate = false; + [SerializeField, Label("RightIndexDistal遮断")] + public bool CutBoneRightIndexDistal = false; + [SerializeField, Label("RightMiddleProximal遮断")] + public bool CutBoneRightMiddleProximal = false; + [SerializeField, Label("RightMiddleIntermediate遮断")] + public bool CutBoneRightMiddleIntermediate = false; + [SerializeField, Label("RightMiddleDistal遮断")] + public bool CutBoneRightMiddleDistal = false; + [SerializeField, Label("RightRingProximal遮断")] + public bool CutBoneRightRingProximal = false; + [SerializeField, Label("RightRingIntermediate遮断")] + public bool CutBoneRightRingIntermediate = false; + [SerializeField, Label("RightRingDistal遮断")] + public bool CutBoneRightRingDistal = false; + [SerializeField, Label("RightLittleProximal遮断")] + public bool CutBoneRightLittleProximal = false; + [SerializeField, Label("RightLittleIntermediate遮断")] + public bool CutBoneRightLittleIntermediate = false; + [SerializeField, Label("RightLittleDistal遮断")] + public bool CutBoneRightLittleDistal = false; + + [Header("API")] + public string api1 = "void UpdateDaisyChain()"; + public string api2 = "int GetAvailable()"; + public string api3 = "float GetRemoteTime()"; + public string api4 = "void SetBlend(string key, float value)"; + public string api5 = "void ApplyBlend()"; + public string api6 = "void DestroyModel()"; + public string api7 = "void LoadVRM(string path)"; + public string api8 = "void LoadVRMFromData(byte[] VRMdata)"; + public string api9 = "void ApplicationQuit()"; + + //---Const--- + + //rootパケット長定数(拡張判別) + const int RootPacketLengthOfScaleAndOffset = 8; + + //---Private--- + + private ExternalReceiverManager externalReceiverManager = null; + + //フィルタ用データ保持変数 + private Vector3[] bonePosFilter = new Vector3[Enum.GetNames(typeof(HumanBodyBones)).Length]; + private Quaternion[] boneRotFilter = new Quaternion[Enum.GetNames(typeof(HumanBodyBones)).Length]; + private Dictionary blendShapeFilterDictionaly = new Dictionary(); + + //通信状態保持変数 + private int Available = 0; //データ送信可能な状態か + private float time = 0; //送信時の時刻 + + //モデル切替検出用reference保持変数 + private GameObject OldModel = null; + + //ボーン情報取得 + Animator animator = null; + //VRMのブレンドシェイププロキシ(VRM0) + VRM.VRMBlendShapeProxy blendShapeProxyV0 = null; + //VRM10のルート(VRM1) + UniVRM10.Vrm10Instance VrmRootV1 = null; + + //ボーンENUM情報テーブル + Dictionary HumanBodyBonesTable = new Dictionary(); + + //ボーン情報テーブル + Dictionary HumanBodyBonesPositionTable = new Dictionary(); + Dictionary HumanBodyBonesRotationTable = new Dictionary(); + + //ブレンドシェイプ変換テーブル(VRM0) + Dictionary StringToBlendShapeKeyDictionaryV0 = new Dictionary(); + Dictionary BlendShapeToValueDictionaryV0 = new Dictionary(); + //ブレンドシェイプ変換テーブル(VRM1) + Dictionary StringToExpressionKeyDictionaryV1 = new Dictionary(); + Dictionary ExpressionToValueDictionaryV1 = new Dictionary(); + + //uOSCサーバー + uOSC.uOscServer server = null; + + //エラー・無限ループ検出フラグ(trueで一切の受信を停止する) + bool shutdown = false; + + //フレーム間パケットフレーム数測定 + int PacketCounterInFrame = 0; + + //1フレームに30パケットフレーム来たら、同一フレーム内でそれ以上は受け取らない。 + const int PACKET_LIMIT_MAX = 30; + + //読込中は読み込まない + bool isLoading = false; + + //メッセージ処理一時変数struct(負荷対策) + Vector3 pos; + Quaternion rot; + Vector3 scale; + Vector3 offset; + + //同期コンテキスト + SynchronizationContext synchronizationContext; + + public void Start() + { + synchronizationContext = SynchronizationContext.Current; + + //nullチェック + if (NextReceivers == null) + { + NextReceivers = new GameObject[0]; + } + //NextReciverのインターフェースを取得する + externalReceiverManager = new ExternalReceiverManager(NextReceivers); + + //サーバーを取得 + server = GetComponent(); + if (server) + { + //サーバーを初期化 + StatusMessage = "Waiting for VMC..."; + server.onDataReceived.AddListener(OnDataReceived); + } + else + { + //デイジーチェーンスレーブモード + StatusMessage = "Waiting for Master..."; + } + + //初期状態で読み込み済みのモデルが有る場合はVRMの自動読み込みは禁止する + if (Model != null) + { + enableAutoLoadVRM = false; + } + } + + //デイジーチェーンを更新 + public void UpdateDaisyChain() + { + //nullチェック + if (NextReceivers == null) + { + NextReceivers = new GameObject[0]; + } + externalReceiverManager.GetIExternalReceiver(NextReceivers); + } + + //外部から通信状態を取得するための公開関数 + public int GetAvailable() + { + return Available; + } + + //外部から通信時刻を取得するための公開関数 + public float GetRemoteTime() + { + return time; + } + + public void Update() + { + // 毎フレーム更新処理(前) + if (!EnableLateUpdateForOverwriteAnimationResult) + { + Process(); + } + } + public void LateUpdate() + { + // 毎フレーム更新処理(後) + if (EnableLateUpdateForOverwriteAnimationResult) + { + Process(); + } + } + + public void Process() + { + //エラー・無限ループ時は処理をしない + if (shutdown) { return; } + + //Freeze有効時は動きを一切止める + if (Freeze) { return; } + + LastPacketframeCounterInFrame = PacketCounterInFrame; + PacketCounterInFrame = 0; + + //5.6.3p1などRunInBackgroundが既定で無効な場合Unityが極めて重くなるため対処 + Application.runInBackground = true; + + //VRMモデルからBlendShapeProxyを取得(タイミングの問題) (VRM0) + if (blendShapeProxyV0 == null && Model != null) + { + blendShapeProxyV0 = Model.GetComponent(); + //以降、blendShapeProxyV0 is not nullでVRM0と扱うことができる + } + //VRMモデルからVrmRootを取得(タイミングの問題) (VRM1) + if (VrmRootV1 == null && Model != null) + { + VrmRootV1 = Model.GetComponent(); + //以降、VrmRootV1 is not nullでVRM1と扱うことができる + } + + //判定 + if (blendShapeProxyV0 != null && VrmRootV1 != null) + { + loadedVRMType = "VRM0&1"; + } + else if (blendShapeProxyV0 != null) + { + loadedVRMType = "VRM0"; + } + else if (VrmRootV1 != null) + { + loadedVRMType = "VRM1"; + } + else + { + loadedVRMType = "Unknown"; + } + + //ルート位置がない場合 + if (RootPositionTransform == null && Model != null) + { + //モデル姿勢をルート姿勢にする + RootPositionTransform = Model.transform; + } + + //ルート回転がない場合 + if (RootRotationTransform == null && Model != null) + { + //モデル姿勢をルート姿勢にする + RootRotationTransform = Model.transform; + } + + //モデルがない場合はエラー表示をしておく(親切心) + if (Model == null) + { + blendShapeProxyV0 = null; + VrmRootV1 = null; + StatusMessage = "Model not found."; + return; + } + + //モデルが更新されたときに関連情報を更新する + if (OldModel != Model && Model != null) + { + blendShapeProxyV0 = Model.GetComponent(); + VrmRootV1 = Model.GetComponent(); + OldModel = Model; + + animator = Model?.GetComponent(); + + Debug.Log("[ExternalReceiver] New model detected"); + + //v0.56 BlendShape仕様変更対応 + //Debug.Log("-- Make BlendShapeProxy BSKey Table --"); + + //BSキー値辞書の初期化(SetValueで無駄なキーが適用されるのを防止する) + BlendShapeToValueDictionaryV0.Clear(); + ExpressionToValueDictionaryV1.Clear(); + + //文字-BSキー辞書の初期化(キー情報の初期化) + StringToBlendShapeKeyDictionaryV0.Clear(); + StringToExpressionKeyDictionaryV1.Clear(); + + //全Clipsを取り出す(VRM0) + if (blendShapeProxyV0) + { + foreach (var c in blendShapeProxyV0.BlendShapeAvatar.Clips) + { + string key = ""; + bool unknown = false; + //プリセットかどうかを調べる + if (c.Preset == VRM.BlendShapePreset.Unknown) + { + //非プリセット(Unknown)であれば、Unknown用の名前変数を参照する + key = c.BlendShapeName; + unknown = true; + } + else + { + //プリセットであればENUM値をToStringした値を利用する + key = c.Preset.ToString(); + unknown = false; + } + + //非ケース化するために小文字変換する + string lowerKey = key.ToLower(); + //Debug.Log("Add: [key]->" + key + " [lowerKey]->" + lowerKey + " [clip]->" + c.ToString() + " [bskey]->"+c.Key.ToString() + " [unknown]->"+ unknown); + + //小文字名-BSKeyで登録する + StringToBlendShapeKeyDictionaryV0.Add(lowerKey, c.Key); + } + } + + //全Clipsを取り出す(VRM1) + if (VrmRootV1) + { + foreach (var c in VrmRootV1.Runtime.Expression.ExpressionKeys) + { + string key = ""; + bool unknown = false; + //プリセットかどうかを調べる + if (c.Preset == UniVRM10.ExpressionPreset.custom) + { + //非プリセット(Unknown)であれば、Unknown用の名前変数を参照する + key = c.Name; + unknown = true; + } + else + { + //プリセットであればENUM値をToStringした値を利用する + key = c.Preset.ToString(); + unknown = false; + } + + //非ケース化するために小文字変換する + string lowerKey = key.ToLower(); + //Debug.Log("Add: [key]->" + key + " [lowerKey]->" + lowerKey + " [clip]->" + c.ToString() + " [bskey]->"+c.Key.ToString() + " [unknown]->"+ unknown); + + //小文字名-BSKeyで登録する + StringToExpressionKeyDictionaryV1.Add(lowerKey, c); + } + } + + //メモ: プリセット同名の独自キー、独自キーのケース違いの重複は、共に区別しないと割り切る + /* + Debug.Log("-- Registered List --"); + foreach (var k in StringToBlendShapeKeyDictionaryV0) { + Debug.Log("B [k.Key]" + k.Key + " -> [k.Value.Name]" + k.Value.Name); + } + foreach (var k in StringToExpressionKeyDictionaryV1) { + Debug.Log("E [k.Key]" + k.Key + " -> [k.Value.Name]" + k.Value.Name); + } + */ + + //Debug.Log("-- End BlendShapeProxy BSKey Table --"); + } + + // VRM1において、VRM1によるLateUpdateでの更新はUpdateにずらして(Constraints) + // EVMC4UはLateUpdateにする(視線動かない問題への暫定対処) + if (VrmRootV1?.UpdateType == Vrm10Instance.UpdateTypes.LateUpdate) + { + VrmRootV1.UpdateType = Vrm10Instance.UpdateTypes.Update; + Debug.Log("[ExternalReceiver] [Temporary Fix] Forcefully change the UpdateType of Vrm10Instance to \"Update\"."); + } + if (VrmRootV1?.UpdateType == Vrm10Instance.UpdateTypes.Update && EnableLateUpdateForOverwriteAnimationResult == false) + { + EnableLateUpdateForOverwriteAnimationResult = true; + Debug.Log("[ExternalReceiver] [Temporary Fix] Forcefully change the Update timing of ExternalReceiver to LateUpdate."); + } + + BoneSynchronizeByTable(); + + } + + //データ受信イベント + private void OnDataReceived(uOSC.Message message) + { + //チェーン数0としてデイジーチェーンを発生させる + MessageDaisyChain(ref message, 0); + } + + //デイジーチェーン処理 + public void MessageDaisyChain(ref uOSC.Message message, int callCount) + { + //Startされていない場合無視 + if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) + { + return; + } + + //エラー・無限ループ時は処理をしない + if (shutdown) + { + return; + } + + //パケットリミッターが有効な場合、一定以上のパケットフレーム/フレーム数を観測した場合、次のフレームまでパケットを捨てる + if (PacktLimiter && (LastPacketframeCounterInFrame > PACKET_LIMIT_MAX)) + { + DropPackets++; + return; + } + + //メッセージを処理 + if (!Freeze) + { + //異常を検出して動作停止 + try + { + ProcessMessage(ref message); + } + catch (Exception e) + { + StatusMessage = "Error: Exception"; + Debug.LogError(" --- Communication Error ---"); + Debug.LogError(e.ToString()); + shutdown = true; + return; + } + } + + //次のデイジーチェーンへ伝える + if (!externalReceiverManager.SendNextReceivers(message, callCount)) + { + //無限ループ対策 + StatusMessage = "Infinite loop detected!"; + + //以降の処理を全部停止 + shutdown = true; + } + } + + //メッセージ処理本体 + private void ProcessMessage(ref uOSC.Message message) + { + //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない + if (message.address == null || message.values == null) + { + StatusMessage = "Bad message."; + return; + } + + //ルート位置がない場合 + if (RootPositionTransform == null && Model != null) + { + //モデル姿勢をルート姿勢にする + RootPositionTransform = Model.transform; + } + + //ルート回転がない場合 + if (RootRotationTransform == null && Model != null) + { + //モデル姿勢をルート姿勢にする + RootRotationTransform = Model.transform; + } + + //モーションデータ送信可否 + if (message.address == "/VMC/Ext/OK" + && (message.values[0] is int)) + { + Available = (int)message.values[0]; + if (Available == 0) + { + StatusMessage = "Waiting for [Load VRM]"; + } + + //V2.5 キャリブレーション状態(長さ3以上) + if (message.values.Length >= 3) + { + if ((message.values[1] is int) && (message.values[2] is int)) + { + int calibrationState = (int)message.values[1]; + int calibrationMode = (int)message.values[2]; + + //キャリブレーション出来ていないときは隠す + if (HideInUncalibrated && Model != null) + { + Model.SetActive(calibrationState == 3); + } + //スケール同期をキャリブレーションと連動させる + if (SyncCalibrationModeWithScaleOffsetSynchronize) + { + RootScaleOffsetSynchronize = !(calibrationMode == 0); //通常モードならオフ、MR系ならオン + } + + } + } + return; + } + //データ送信時刻 + else if (message.address == "/VMC/Ext/T" + && (message.values[0] is float)) + { + time = (float)message.values[0]; + PacketCounterInFrame++; //フレーム中のパケットフレーム数を測定 + return; + } + //VRM自動読み込み + else if (message.address == "/VMC/Ext/VRM" + && (message.values[0] is string) + && (message.values[1] is string) + ) + { + string path = (string)message.values[0]; + string title = (string)message.values[1]; + + //前回読み込んだパスと違う場合かつ、読み込みが許可されている場合 + if (path != loadedVRMPath && enableAutoLoadVRM == true) + { + loadedVRMPath = path; + loadedVRMName = title; + LoadVRM(path); + } + return; + } + //オプション文字列 + else if (message.address == "/VMC/Ext/Opt" + && (message.values[0] is string)) + { + OptionString = (string)message.values[0]; + return; + } + + + //モデルがないか、モデル姿勢、ルート姿勢が取得できないなら以降何もしない + if (Model == null || Model.transform == null || RootPositionTransform == null || RootRotationTransform == null) + { + return; + } + + //Root姿勢 + if (message.address == "/VMC/Ext/Root/Pos" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + StatusMessage = "OK"; + + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + + //位置同期 + if (RootPositionSynchronize) + { + RootPositionTransform.localPosition = pos; + } + //回転同期 + if (RootRotationSynchronize) + { + RootRotationTransform.localRotation = rot; + } + //スケール同期とオフセット補正(v2.1拡張プロトコルの場合のみ) + if (RootScaleOffsetSynchronize && message.values.Length > RootPacketLengthOfScaleAndOffset + && (message.values[8] is float) + && (message.values[9] is float) + && (message.values[10] is float) + && (message.values[11] is float) + && (message.values[12] is float) + && (message.values[13] is float) + ) + { + scale.x = 1.0f / (float)message.values[8]; + scale.y = 1.0f / (float)message.values[9]; + scale.z = 1.0f / (float)message.values[10]; + offset.x = (float)message.values[11]; + offset.y = (float)message.values[12]; + offset.z = (float)message.values[13]; + + Model.transform.localScale = scale; + RootPositionTransform.localPosition = Vector3.Scale(RootPositionTransform.localPosition, scale); + + //位置同期が有効な場合のみオフセットを反映する + if (RootPositionSynchronize) + { + offset = Vector3.Scale(offset, scale); + RootPositionTransform.localPosition -= offset; + } + } + else + { + Model.transform.localScale = Vector3.one; + } + } + //ボーン姿勢 + else if (message.address == "/VMC/Ext/Bone/Pos" + && (message.values[0] is string) + && (message.values[1] is float) + && (message.values[2] is float) + && (message.values[3] is float) + && (message.values[4] is float) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + string boneName = (string)message.values[0]; + pos.x = (float)message.values[1]; + pos.y = (float)message.values[2]; + pos.z = (float)message.values[3]; + rot.x = (float)message.values[4]; + rot.y = (float)message.values[5]; + rot.z = (float)message.values[6]; + rot.w = (float)message.values[7]; + + //Humanoidボーンに該当するボーンがあるか調べる + HumanBodyBones bone; + if (HumanBodyBonesTryParse(ref boneName, out bone)) + { + //あれば位置と回転をキャッシュする + if (HumanBodyBonesPositionTable.ContainsKey(bone)) + { + HumanBodyBonesPositionTable[bone] = pos; + } + else + { + HumanBodyBonesPositionTable.Add(bone, pos); + } + + if (HumanBodyBonesRotationTable.ContainsKey(bone)) + { + HumanBodyBonesRotationTable[bone] = rot; + } + else + { + HumanBodyBonesRotationTable.Add(bone, rot); + } + } + //受信と更新のタイミングは切り離した + } + //ブレンドシェイプ同期 + else if (message.address == "/VMC/Ext/Blend/Val" + && (message.values[0] is string) + && (message.values[1] is float) + ) + { + //一旦変数に格納する + string key = (string)message.values[0]; + float value = (float)message.values[1]; + + if (BlendShapeSynchronize) + { + SetBlend(key, value); + } + } + //ブレンドシェープ適用 + else if (message.address == "/VMC/Ext/Blend/Apply") + { + if (BlendShapeSynchronize) + { + ApplyBlend(); + } + } + } + + //表情の設定(VRM0,VRM1共通) + public void SetBlend(string key, float value) + { + //BlendShapeフィルタが有効なら + if (BlendShapeFilterEnable) + { + //フィルタテーブルに存在するか確認する + if (blendShapeFilterDictionaly.ContainsKey(key)) + { + //存在する場合はフィルタ更新して値として反映する + blendShapeFilterDictionaly[key] = (blendShapeFilterDictionaly[key] * BlendShapeFilter) + value * (1.0f - BlendShapeFilter); + value = blendShapeFilterDictionaly[key]; + } + else + { + //存在しない場合はフィルタに登録する。値はそのまま + blendShapeFilterDictionaly.Add(key, value); + } + } + + // VRM0 + if (blendShapeProxyV0 != null) + { + //v0.56 BlendShape仕様変更対応 + //辞書からKeyに変換し、Key値辞書に値を入れる + + //通信で受信したキーを小文字に変換して非ケース化 + string lowerKey = key.ToLower(); + + //キーに該当するBSKeyが存在するかチェックする + VRM.BlendShapeKey bskey; + if (StringToBlendShapeKeyDictionaryV0.TryGetValue(lowerKey, out bskey)) + { + //キーに対して値を登録する + BlendShapeToValueDictionaryV0[bskey] = value; + + //Debug.Log("[lowerKey]->"+ lowerKey+" [bskey]->"+bskey.ToString()+" [value]->"+value); + } + else + { + //VRM1.x -> VRM0.x逆変換テーブル(前方互換性) + switch (lowerKey) + { + case "happy": lowerKey = "joy"; break; + case "sad": lowerKey = "sorrow"; break; + case "relaxed": lowerKey = "fun"; break; + case "aa": lowerKey = "a"; break; + case "ih": lowerKey = "i"; break; + case "ou": lowerKey = "u"; break; + case "ee": lowerKey = "e"; break; + case "oh": lowerKey = "o"; break; + case "blinkleft": lowerKey = "blink_l"; break; + case "blinkright": lowerKey = "blink_r"; break; + } + if (StringToBlendShapeKeyDictionaryV0.TryGetValue(lowerKey, out bskey)) + { + //キーに対して値を登録する + BlendShapeToValueDictionaryV0[bskey] = value; + + //Debug.Log("[lowerKey]->"+ lowerKey+" [bskey]->"+bskey.ToString()+" [value]->"+value); + } + else + { + //そんなキーは無い + //Debug.LogError("[lowerKey]->" + lowerKey + " is not found"); + } + } + } + + // VRM1 + if (VrmRootV1 != null) + { + //v0.56 BlendShape仕様変更対応 + //辞書からKeyに変換し、Key値辞書に値を入れる + + //通信で受信したキーを小文字に変換して非ケース化 + string lowerKey = key.ToLower(); + + //キーに該当するBSKeyが存在するかチェックする + UniVRM10.ExpressionKey exkey; + if (StringToExpressionKeyDictionaryV1.TryGetValue(lowerKey, out exkey)) + { + //キーに対して値を登録する + ExpressionToValueDictionaryV1[exkey] = value; + + //Debug.Log("[lowerKey]->"+ lowerKey+" [exkey]->"+exkey.ToString()+" [value]->"+value); + } + else + { + //VRM0.x -> VRM1.x変換テーブル(後方互換性) + switch (lowerKey) + { + case "joy": lowerKey = "happy"; break; + case "sorrow": lowerKey = "sad"; break; + case "fun": lowerKey = "relaxed"; break; + case "a": lowerKey = "aa"; break; + case "i": lowerKey = "ih"; break; + case "u": lowerKey = "ou"; break; + case "e": lowerKey = "ee"; break; + case "o": lowerKey = "oh"; break; + case "blink_l": lowerKey = "blinkleft"; break; + case "blink_r": lowerKey = "blinkright"; break; + } + if (StringToExpressionKeyDictionaryV1.TryGetValue(lowerKey, out exkey)) + { + //キーに対して値を登録する + ExpressionToValueDictionaryV1[exkey] = value; + + //Debug.Log("[lowerKey]->"+ lowerKey+" [exkey]->"+exkey.ToString()+" [value]->"+value); + } + else + { + //そんなキーは無い + //Debug.LogError("[lowerKey]->" + lowerKey + " is not found"); + } + } + } + } + + //表情の確定(VRM0,VRM1共通) + public void ApplyBlend() + { + if (blendShapeProxyV0 != null) + { + blendShapeProxyV0.SetValues(BlendShapeToValueDictionaryV0); + } + if (VrmRootV1 != null) + { + VrmRootV1.Runtime.Expression.SetWeights(ExpressionToValueDictionaryV1); + } + } + + //モデル破棄 + public void DestroyModel() + { + //存在すれば即破壊(異常顔防止) + if (Model != null) + { + BeforeModelDestroyAction?.Invoke(Model); + Destroy(Model); + Model = null; + } + if (LoadedModelParent != null) + { + Destroy(LoadedModelParent); + LoadedModelParent = null; + } + } + + //ファイルからモデルを読み込む + public void LoadVRM(string path) + { + DestroyModel(); + + //バイナリの読み込み + if (File.Exists(path)) + { + byte[] VRMdata = File.ReadAllBytes(path); + LoadVRMFromData(VRMdata); + } + else + { + Debug.LogError("VRM load failed."); + } + } + + //ファイルからモデルを読み込む + public void LoadVRMFromData(byte[] VRMdata) + { + if (isLoading) + { + Debug.LogError("Now Loading! load request is rejected."); + return; + } + DestroyModel(); + + //読み込み + GlbLowLevelParser glbLowLevelParser = new GlbLowLevelParser(null, VRMdata); + GltfData gltfData = glbLowLevelParser.Parse(); + + // VRM0 読み込み処理 + try + { + VRM.VRMData vrm = new VRM.VRMData(gltfData); + VRM.VRMImporterContext vrmImporter = new VRM.VRMImporterContext(vrm); + + isLoading = true; + + synchronizationContext.Post(async (arg) => { + RuntimeGltfInstance instance = await vrmImporter.LoadAsync(new VRMShaders.ImmediateCaller()); + isLoading = false; + + Model = instance.Root; + + //ExternalReceiverの下にぶら下げる + LoadedModelParent = new GameObject(); + LoadedModelParent.transform.SetParent(transform, false); + LoadedModelParent.name = "LoadedModelParent"; + //その下にモデルをぶら下げる + Model.transform.SetParent(LoadedModelParent.transform, false); + + instance.EnableUpdateWhenOffscreen(); + instance.ShowMeshes(); + + //カメラなどの移動補助のため、頭の位置を格納する + animator = Model.GetComponent(); + HeadPosition = animator.GetBoneTransform(HumanBodyBones.Head).position; + + //開放 + vrmImporter.Dispose(); + gltfData.Dispose(); + + //読み込み後アクションを実行 + AfterAutoLoadAction?.Invoke(Model); + }, null); + return; //VRM0 Loaded + } + catch (VRM.NotVrm0Exception) + { + //continue loading + } + + // VRM1 読み込み処理 + synchronizationContext.Post(async (_) => + { + var instance = await UniVRM10.Vrm10.LoadBytesAsync(VRMdata, canLoadVrm0X: false, showMeshes: true, controlRigGenerationOption: controlRigGenerationOptionOnLoad); + await Task.Delay(100); //VRM1不具合対策 + Model = instance.gameObject; + Model.transform.parent = this.transform; + + //ExternalReceiverの下にぶら下げる + LoadedModelParent = new GameObject(); + LoadedModelParent.transform.SetParent(transform, false); + LoadedModelParent.name = "LoadedModelParent"; + //その下にモデルをぶら下げる + Model.transform.SetParent(LoadedModelParent.transform, false); + + //カメラなどの移動補助のため、頭の位置を格納する + animator = Model.GetComponent(); + HeadPosition = animator.GetBoneTransform(HumanBodyBones.Head).position; + + var meshes = Model.GetComponentsInChildren(); + foreach (var m in meshes) + { + m.updateWhenOffscreen = true; + } + + //開放 + gltfData?.Dispose(); + + //読み込み後アクションを実行 + AfterAutoLoadAction?.Invoke(Model); + }, null); + // Debug.LogError("Failed to load VRM1 and VRM0."); + } + + //ボーン位置をキャッシュテーブルに基づいて更新 + private void BoneSynchronizeByTable() + { + //キャッシュテーブルを参照 + foreach (var bone in HumanBodyBonesTable) + { + //キャッシュされた位置・回転を適用 + if (HumanBodyBonesPositionTable.ContainsKey(bone.Value) && HumanBodyBonesRotationTable.ContainsKey(bone.Value)) + { + BoneSynchronize(bone.Value, HumanBodyBonesPositionTable[bone.Value], HumanBodyBonesRotationTable[bone.Value]); + } + } + } + + //ボーン位置同期 + private void BoneSynchronize(HumanBodyBones bone, Vector3 pos, Quaternion rot) + { + //操作可能な状態かチェック + if (animator != null && bone != HumanBodyBones.LastBone) + { + //ボーンによって操作を分ける + Transform t; + t = animator.GetBoneTransform(bone); + + if (t != null) + { + //個別ボーン遮断 + if (CutBonesEnable) + { + if (bone == HumanBodyBones.Hips && CutBoneHips) { return; } + if (bone == HumanBodyBones.LeftUpperLeg && CutBoneLeftUpperLeg) { return; } + if (bone == HumanBodyBones.RightUpperLeg && CutBoneRightUpperLeg) { return; } + if (bone == HumanBodyBones.LeftLowerLeg && CutBoneLeftLowerLeg) { return; } + if (bone == HumanBodyBones.RightLowerLeg && CutBoneRightLowerLeg) { return; } + if (bone == HumanBodyBones.LeftFoot && CutBoneLeftFoot) { return; } + if (bone == HumanBodyBones.RightFoot && CutBoneRightFoot) { return; } + if (bone == HumanBodyBones.Spine && CutBoneSpine) { return; } + if (bone == HumanBodyBones.Chest && CutBoneChest) { return; } + if (bone == HumanBodyBones.Neck && CutBoneNeck) { return; } + if (bone == HumanBodyBones.Head && CutBoneHead) { return; } + if (bone == HumanBodyBones.LeftShoulder && CutBoneLeftShoulder) { return; } + if (bone == HumanBodyBones.RightShoulder && CutBoneRightShoulder) { return; } + if (bone == HumanBodyBones.LeftUpperArm && CutBoneLeftUpperArm) { return; } + if (bone == HumanBodyBones.RightUpperArm && CutBoneRightUpperArm) { return; } + if (bone == HumanBodyBones.LeftLowerArm && CutBoneLeftLowerArm) { return; } + if (bone == HumanBodyBones.RightLowerArm && CutBoneRightLowerArm) { return; } + if (bone == HumanBodyBones.LeftHand && CutBoneLeftHand) { return; } + if (bone == HumanBodyBones.RightHand && CutBoneRightHand) { return; } + if (bone == HumanBodyBones.LeftToes && CutBoneLeftToes) { return; } + if (bone == HumanBodyBones.RightToes && CutBoneRightToes) { return; } + if (bone == HumanBodyBones.LeftEye && CutBoneLeftEye) { return; } + if (bone == HumanBodyBones.RightEye && CutBoneRightEye) { return; } + if (bone == HumanBodyBones.Jaw && CutBoneJaw) { return; } + if (bone == HumanBodyBones.LeftThumbProximal && CutBoneLeftThumbProximal) { return; } + if (bone == HumanBodyBones.LeftThumbIntermediate && CutBoneLeftThumbIntermediate) { return; } + if (bone == HumanBodyBones.LeftThumbDistal && CutBoneLeftThumbDistal) { return; } + if (bone == HumanBodyBones.LeftIndexProximal && CutBoneLeftIndexProximal) { return; } + if (bone == HumanBodyBones.LeftIndexIntermediate && CutBoneLeftIndexIntermediate) { return; } + if (bone == HumanBodyBones.LeftIndexDistal && CutBoneLeftIndexDistal) { return; } + if (bone == HumanBodyBones.LeftMiddleProximal && CutBoneLeftMiddleProximal) { return; } + if (bone == HumanBodyBones.LeftMiddleIntermediate && CutBoneLeftMiddleIntermediate) { return; } + if (bone == HumanBodyBones.LeftMiddleDistal && CutBoneLeftMiddleDistal) { return; } + if (bone == HumanBodyBones.LeftRingProximal && CutBoneLeftRingProximal) { return; } + if (bone == HumanBodyBones.LeftRingIntermediate && CutBoneLeftRingIntermediate) { return; } + if (bone == HumanBodyBones.LeftRingDistal && CutBoneLeftRingDistal) { return; } + if (bone == HumanBodyBones.LeftLittleProximal && CutBoneLeftLittleProximal) { return; } + if (bone == HumanBodyBones.LeftLittleIntermediate && CutBoneLeftLittleIntermediate) { return; } + if (bone == HumanBodyBones.LeftLittleDistal && CutBoneLeftLittleDistal) { return; } + if (bone == HumanBodyBones.RightThumbProximal && CutBoneRightThumbProximal) { return; } + if (bone == HumanBodyBones.RightThumbIntermediate && CutBoneRightThumbIntermediate) { return; } + if (bone == HumanBodyBones.RightThumbDistal && CutBoneRightThumbDistal) { return; } + if (bone == HumanBodyBones.RightIndexProximal && CutBoneRightIndexProximal) { return; } + if (bone == HumanBodyBones.RightIndexIntermediate && CutBoneRightIndexIntermediate) { return; } + if (bone == HumanBodyBones.RightIndexDistal && CutBoneRightIndexDistal) { return; } + if (bone == HumanBodyBones.RightMiddleProximal && CutBoneRightMiddleProximal) { return; } + if (bone == HumanBodyBones.RightMiddleIntermediate && CutBoneRightMiddleIntermediate) { return; } + if (bone == HumanBodyBones.RightMiddleDistal && CutBoneRightMiddleDistal) { return; } + if (bone == HumanBodyBones.RightRingProximal && CutBoneRightRingProximal) { return; } + if (bone == HumanBodyBones.RightRingIntermediate && CutBoneRightRingIntermediate) { return; } + if (bone == HumanBodyBones.RightRingDistal && CutBoneRightRingDistal) { return; } + if (bone == HumanBodyBones.RightLittleProximal && CutBoneRightLittleProximal) { return; } + if (bone == HumanBodyBones.RightLittleIntermediate && CutBoneRightLittleIntermediate) { return; } + if (bone == HumanBodyBones.RightLittleDistal && CutBoneRightLittleDistal) { return; } + if (bone == HumanBodyBones.UpperChest && CutBoneUpperChest) { return; } + } + + //指ボーン + if (bone == HumanBodyBones.LeftIndexDistal || + bone == HumanBodyBones.LeftIndexIntermediate || + bone == HumanBodyBones.LeftIndexProximal || + bone == HumanBodyBones.LeftLittleDistal || + bone == HumanBodyBones.LeftLittleIntermediate || + bone == HumanBodyBones.LeftLittleProximal || + bone == HumanBodyBones.LeftMiddleDistal || + bone == HumanBodyBones.LeftMiddleIntermediate || + bone == HumanBodyBones.LeftMiddleProximal || + bone == HumanBodyBones.LeftRingDistal || + bone == HumanBodyBones.LeftRingIntermediate || + bone == HumanBodyBones.LeftRingProximal || + bone == HumanBodyBones.LeftThumbDistal || + bone == HumanBodyBones.LeftThumbIntermediate || + bone == HumanBodyBones.LeftThumbProximal || + + bone == HumanBodyBones.RightIndexDistal || + bone == HumanBodyBones.RightIndexIntermediate || + bone == HumanBodyBones.RightIndexProximal || + bone == HumanBodyBones.RightLittleDistal || + bone == HumanBodyBones.RightLittleIntermediate || + bone == HumanBodyBones.RightLittleProximal || + bone == HumanBodyBones.RightMiddleDistal || + bone == HumanBodyBones.RightMiddleIntermediate || + bone == HumanBodyBones.RightMiddleProximal || + bone == HumanBodyBones.RightRingDistal || + bone == HumanBodyBones.RightRingIntermediate || + bone == HumanBodyBones.RightRingProximal || + bone == HumanBodyBones.RightThumbDistal || + bone == HumanBodyBones.RightThumbIntermediate || + bone == HumanBodyBones.RightThumbProximal) + { + //指ボーンカットオフが有効でなければ + if (!HandPoseSynchronizeCutoff) + { + //ボーン同期する。ただしフィルタはかけない + BoneSynchronizeSingle(t, ref bone, ref pos, ref rot, false, false); + } + } + //目ボーン + else if (bone == HumanBodyBones.LeftEye || + bone == HumanBodyBones.RightEye) + { + //目ボーンカットオフが有効でなければ + if (!EyeBoneSynchronizeCutoff) + { + //ボーン同期する。ただしフィルタはかけない + BoneSynchronizeSingle(t, ref bone, ref pos, ref rot, false, false); + } + } + else + { + //ボーン同期する。フィルタは設定依存 + BoneSynchronizeSingle(t, ref bone, ref pos, ref rot, BonePositionFilterEnable, BoneRotationFilterEnable); + } + } + } + } + + //1本のボーンの同期 + private void BoneSynchronizeSingle(Transform t, ref HumanBodyBones bone, ref Vector3 pos, ref Quaternion rot, bool posFilter, bool rotFilter) + { + BoneFilter = Mathf.Clamp(BoneFilter, 0f, 1f); + + //ボーン位置同期が有効か + if (BonePositionSynchronize) + { + //ボーン位置フィルタが有効か + if (posFilter) + { + bonePosFilter[(int)bone] = (bonePosFilter[(int)bone] * BoneFilter) + pos * (1.0f - BoneFilter); + t.localPosition = bonePosFilter[(int)bone]; + } + else + { + t.localPosition = pos; + } + } + + //ボーン回転フィルタが有効か + if (rotFilter) + { + boneRotFilter[(int)bone] = Quaternion.Slerp(boneRotFilter[(int)bone], rot, 1.0f - BoneFilter); + t.localRotation = boneRotFilter[(int)bone]; + } + else + { + t.localRotation = rot; + } + } + + //ボーンENUM情報をキャッシュして高速化 + private bool HumanBodyBonesTryParse(ref string boneName, out HumanBodyBones bone) + { + //ボーンキャッシュテーブルに存在するなら + if (HumanBodyBonesTable.ContainsKey(boneName)) + { + //キャッシュテーブルから返す + bone = HumanBodyBonesTable[boneName]; + //ただしLastBoneは発見しなかったことにする(無効値として扱う) + if (bone == HumanBodyBones.LastBone) + { + return false; + } + return true; + } + else + { + //キャッシュテーブルにない場合、検索する + var res = EnumTryParse(boneName, out bone); + if (!res) + { + //見つからなかった場合はLastBoneとして登録する(無効値として扱う)ことにより次回から検索しない + bone = HumanBodyBones.LastBone; + } + //キャシュテーブルに登録する + HumanBodyBonesTable.Add(boneName, bone); + return res; + } + } + + //互換性を持ったTryParse + private static bool EnumTryParse(string value, out T result) where T : struct + { +#if NET_4_6 + return Enum.TryParse(value, out result); +#else + try + { + result = (T)Enum.Parse(typeof(T), value, true); + return true; + } + catch + { + result = default(T); + return false; + } +#endif + } + + //アプリケーションを終了させる + public void ApplicationQuit() + { +#if UNITY_EDITOR + UnityEditor.EditorApplication.isPlaying = false; +#else + Application.Quit(); +#endif + } + } +} diff --git a/Assets/External/EVMC4U/ExternalReceiver.cs.meta b/Assets/External/EVMC4U/ExternalReceiver.cs.meta new file mode 100644 index 000000000..096c22971 --- /dev/null +++ b/Assets/External/EVMC4U/ExternalReceiver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2b1a1db52b2afb4e9cb87fac5cbf079 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/ExternalReceiver.prefab b/Assets/External/EVMC4U/ExternalReceiver.prefab new file mode 100644 index 000000000..8f2c54b13 --- /dev/null +++ b/Assets/External/EVMC4U/ExternalReceiver.prefab @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e1139f26b3478199b62fe686fdf2e296f200ef08418bd84c607c3240dd044bc3 +size 11896 diff --git a/Assets/External/EVMC4U/ExternalReceiver.prefab.meta b/Assets/External/EVMC4U/ExternalReceiver.prefab.meta new file mode 100644 index 000000000..adb1f3c7e --- /dev/null +++ b/Assets/External/EVMC4U/ExternalReceiver.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 86b1e8192cb57cd47890882526664df1 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/ExternalReceiver.unity b/Assets/External/EVMC4U/ExternalReceiver.unity new file mode 100644 index 000000000..2810a4920 --- /dev/null +++ b/Assets/External/EVMC4U/ExternalReceiver.unity @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:74d59c22a9d3226c71f9137d5d2f5dcbbb1ed56eaae1f9822bfe85f83de1005a +size 9527 diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/ScreenSpace.unity.meta b/Assets/External/EVMC4U/ExternalReceiver.unity.meta similarity index 74% rename from Assets/External/UniGLTF/Samples/ScreenSpace/ScreenSpace.unity.meta rename to Assets/External/EVMC4U/ExternalReceiver.unity.meta index 897e9994b..70f27ad39 100644 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/ScreenSpace.unity.meta +++ b/Assets/External/EVMC4U/ExternalReceiver.unity.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 810bf20df2b55ed4584c6ca1b8469907 +guid: a8cb6a0ea0acf0e4399570a0194b57a1 DefaultImporter: externalObjects: {} userData: diff --git a/Assets/External/EVMC4U/InputReceiver.cs b/Assets/External/EVMC4U/InputReceiver.cs new file mode 100644 index 000000000..76e712f40 --- /dev/null +++ b/Assets/External/EVMC4U/InputReceiver.cs @@ -0,0 +1,268 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma warning disable 0414,0219 +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Profiling; + + +namespace EVMC4U +{ + public class InputReceiver : MonoBehaviour, IExternalReceiver + { + [Header("InputReceiver v1.1")] + [SerializeField, Label("動作状況")] + private string StatusMessage = ""; //Inspector表示用 + [SerializeField, Label("最終入力")] + private string LastInput = ""; + +#if EVMC4U_JA + [Header("入力イベント")] +#else + [Header("Event Callback")] +#endif + public KeyInputEvent KeyInputAction = new KeyInputEvent(); //キーボード入力イベント + public ControllerInputEvent ControllerInputAction = new ControllerInputEvent(); //コントローラボタンイベント + public MidiNoteInputEvent MidiNoteInputAction = new MidiNoteInputEvent(); + public MidiCCValueInputEvent MidiCCValueInputAction = new MidiCCValueInputEvent(); + public MidiCCButtonInputEvent MidiCCButtonInputAction = new MidiCCButtonInputEvent(); + +#if EVMC4U_JA + [Header("MIDI CC モニタ(つまみ、ボタン)")] +#else + [Header("MIDI CC Monitor")] +#endif + public float[] CCValuesMonitor = new float[128]; + +#if EVMC4U_JA + [Header("デイジーチェーン")] +#else + [Header("Daisy Chain")] +#endif + public GameObject[] NextReceivers = new GameObject[1]; + + //--- + + //入力辞書(コールバックではなく定値で取得したい場合に使う) + public Dictionary InputDictionary = new Dictionary(); + + //--- + + private ExternalReceiverManager externalReceiverManager = null; + bool shutdown = false; + + //メッセージ処理一時変数struct(負荷対策) + ControllerInput con; + KeyInput key; + MidiNote note; + MidiCCValue ccvalue; + MidiCCButton ccbutton; + + void Start() + { + externalReceiverManager = new ExternalReceiverManager(NextReceivers); + StatusMessage = "Waiting for Master..."; + + //強制 + CCValuesMonitor = new float[128]; + } + + //デイジーチェーンを更新 + public void UpdateDaisyChain() + { + externalReceiverManager.GetIExternalReceiver(NextReceivers); + } + + public void MessageDaisyChain(ref uOSC.Message message, int callCount) + { + //Startされていない場合無視 + if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false) + { + return; + } + + if (shutdown) + { + return; + } + + StatusMessage = "OK"; + + //異常を検出して動作停止 + try + { + ProcessMessage(ref message); + } + catch (Exception e) + { + StatusMessage = "Error: Exception"; + Debug.LogError(" --- Communication Error ---"); + Debug.LogError(e.ToString()); + shutdown = true; + return; + } + + if (!externalReceiverManager.SendNextReceivers(message, callCount)) + { + StatusMessage = "Infinite loop detected!"; + shutdown = true; + } + } + + private void ProcessMessage(ref uOSC.Message message) + { + //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない + if (message.address == null || message.values == null) + { + StatusMessage = "Bad message."; + return; + } + + //コントローラ操作情報 v2.1 + if (message.address == "/VMC/Ext/Con" + && (message.values[0] is int) + && (message.values[1] is string) + && (message.values[2] is int) + && (message.values[3] is int) + && (message.values[4] is int) + && (message.values[5] is float) + && (message.values[6] is float) + && (message.values[7] is float) + ) + { + con.active = (int)message.values[0]; + con.name = (string)message.values[1]; + con.IsLeft = (int)message.values[2]; + con.IsTouch = (int)message.values[3]; + con.IsAxis = (int)message.values[4]; + con.Axis.x = (float)message.values[5]; + con.Axis.y = (float)message.values[6]; + con.Axis.z = (float)message.values[7]; + + //イベントを呼び出す + if (ControllerInputAction != null) + { + ControllerInputAction.Invoke(con); + } + if (con.IsAxis == 0) { + if (con.IsLeft == 1) + { + LastInput = "Left-" + con.name + " = " + con.active; + InputDictionary["Left-" + con.name] = (con.active != 0); + } + else + { + LastInput = "Right-" + con.name + " = " + con.active; + InputDictionary["Right-" + con.name] = (con.active != 0); + } + } + } + //キーボード操作情報 v2.1 + else if (message.address == "/VMC/Ext/Key" + && (message.values[0] is int) + && (message.values[1] is string) + && (message.values[2] is int) + ) + { + key.active = (int)message.values[0]; + key.name = (string)message.values[1]; + key.keycode = (int)message.values[2]; + + //イベントを呼び出す + if (KeyInputAction != null) + { + KeyInputAction.Invoke(key); + } + + LastInput = "Key-" + key.name +" = "+key.active + " (" + key.keycode + ")"; + } + // v2.2 + else if (message.address == "/VMC/Ext/Midi/Note" + && (message.values[0] is int) + && (message.values[1] is int) + && (message.values[2] is int) + && (message.values[3] is float) + ) + { + note.active = (int)message.values[0]; + note.channel = (int)message.values[1]; + note.note = (int)message.values[2]; + note.velocity = (float)message.values[3]; + + //イベントを呼び出す + if (MidiNoteInputAction != null) + { + MidiNoteInputAction.Invoke(note); + } + + LastInput = "Note-" + note.note + " = "+note.active + "/" + note.channel + "/" + note.velocity; + InputDictionary["Note-" + note.note] = (note.active != 0); + } + // v2.2 + else if (message.address == "/VMC/Ext/Midi/CC/Val" + && (message.values[0] is int) + && (message.values[1] is float) + ) + { + ccvalue.knob = (int)message.values[0]; + ccvalue.value = (float)message.values[1]; + + //イベントを呼び出す + if (MidiCCValueInputAction != null) + { + MidiCCValueInputAction.Invoke(ccvalue); + } + + LastInput = "CC Val " + ccvalue.knob + " = " + ccvalue.value; + + if (ccvalue.knob >= 0 && ccvalue.knob < 128) { + CCValuesMonitor[ccvalue.knob] = ccvalue.value; + } + } + // v2.2 + else if (message.address == "/VMC/Ext/Midi/CC/Bit" + && (message.values[0] is int) + && (message.values[1] is int) + ) + { + ccbutton.knob = (int)message.values[0]; + ccbutton.active = (int)message.values[1]; + + //イベントを呼び出す + if (MidiCCButtonInputAction != null) + { + MidiCCButtonInputAction.Invoke(ccbutton); + } + LastInput = "CC-" + ccbutton.knob + " = " + ccbutton.active; + InputDictionary["CC-" + ccbutton.knob] = (ccbutton.active != 0); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/InputReceiver.cs.meta b/Assets/External/EVMC4U/InputReceiver.cs.meta new file mode 100644 index 000000000..079166936 --- /dev/null +++ b/Assets/External/EVMC4U/InputReceiver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7b6344b39082f64e8111bc0fd99f9c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/LICENSE b/Assets/External/EVMC4U/LICENSE new file mode 100644 index 000000000..4061123fa --- /dev/null +++ b/Assets/External/EVMC4U/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2020 gpsnmeajp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.unity.meta b/Assets/External/EVMC4U/LICENSE.meta similarity index 74% rename from Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.unity.meta rename to Assets/External/EVMC4U/LICENSE.meta index 2a3f1964d..e56dfac9a 100644 --- a/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.unity.meta +++ b/Assets/External/EVMC4U/LICENSE.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 99665560be9c32e4d9f7813b076c92ee +guid: d4d62af2deec5eb48896ec651fa9571b DefaultImporter: externalObjects: {} userData: diff --git a/Assets/External/EVMC4U/SampleScripts.meta b/Assets/External/EVMC4U/SampleScripts.meta new file mode 100644 index 000000000..fc399ccb8 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fe826b9d334c93e4ca357d6af02179cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/CCCameraControl.meta b/Assets/External/EVMC4U/SampleScripts/CCCameraControl.meta new file mode 100644 index 000000000..06d752b2f --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CCCameraControl.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d554b7baaffa0cf4c907cd10362bf827 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/CCCameraControl/CCCameraControl.cs b/Assets/External/EVMC4U/SampleScripts/CCCameraControl/CCCameraControl.cs new file mode 100644 index 000000000..dc2270f19 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CCCameraControl/CCCameraControl.cs @@ -0,0 +1,44 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace EVMC4U +{ + public class CCCameraControl : MonoBehaviour + { + public InputReceiver r; + public Camera c; + private void Update() + { + c.fieldOfView = r.CCValuesMonitor[16] * 90 + 1; + c.transform.position = new Vector3((r.CCValuesMonitor[0] - 0.5f) * 3f, (r.CCValuesMonitor[1] - 0.5f) * 3f, (r.CCValuesMonitor[2]-0.5f)*3f); + c.transform.rotation = Quaternion.Euler(r.CCValuesMonitor[3]*360f, r.CCValuesMonitor[4] * 360f, r.CCValuesMonitor[5] * 360f); + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/SampleScripts/CCCameraControl/CCCameraControl.cs.meta b/Assets/External/EVMC4U/SampleScripts/CCCameraControl/CCCameraControl.cs.meta new file mode 100644 index 000000000..c4d79e980 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CCCameraControl/CCCameraControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38cb49d414319034c9a457279ea5133f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/CalibrationByController.meta b/Assets/External/EVMC4U/SampleScripts/CalibrationByController.meta new file mode 100644 index 000000000..9b0acaaeb --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CalibrationByController.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7af78563b203db9458af57d24f50e7b0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/CalibrationByController/CalibrationByController.cs b/Assets/External/EVMC4U/SampleScripts/CalibrationByController/CalibrationByController.cs new file mode 100644 index 000000000..16fd6b3e0 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CalibrationByController/CalibrationByController.cs @@ -0,0 +1,123 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2020 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using EVMC4U; + +public class CalibrationByController : MonoBehaviour +{ + public InputReceiver inputReceiver; + public CommunicationValidator communicationValidator; + public ExternalController externalController; + + [Header("Button Configuration")] + public string Key = "ScrollLock"; + public string Button = "ClickAbutton"; + + [Header("Time Configuration")] + public float Time = 3f; + + [Header("Button Monitor")] + public bool LeftButton = false; + public bool RightButton = false; + + readonly Rect rect1 = new Rect(0, 0, 300, 40); + + void Start() + { + inputReceiver.KeyInputAction.AddListener(OnKey); + inputReceiver.ControllerInputAction.AddListener(OnCon); + } + + void OnGUI() + { + if (communicationValidator.calibrationState == CalibrationState.Uncalibrated) + { + GUI.TextField(rect1, "★キャリブレーションを待っています\n準備ができたらボタンを押してください"); + } + if (communicationValidator.calibrationState == CalibrationState.WaitingForCalibrating) + { + GUI.TextField(rect1, "★姿勢を整えてください"); + } + if (communicationValidator.calibrationState == CalibrationState.Calibrating) + { + GUI.TextField(rect1, "!動かないでください!"); + } + } + + void OnKey(KeyInput key) + { + if (key.name == Key && key.active == 1) + { + CalibrationReady(); + } + } + void OnCon(ControllerInput con) + { + if (con.name == Button) + { + if (con.IsLeft == 1) + { + LeftButton = (con.active == 1); + } + else { + RightButton = (con.active == 1); + } + if (LeftButton && RightButton) { + //キャリブレーションできていないときのみ実行 + if (communicationValidator.calibrationState == CalibrationState.Uncalibrated) + { + CalibrationReady(); + } + + LeftButton = false; + RightButton = false; + } + } + } + + void CalibrationReady() + { + Debug.Log("[CalibrationByController] CalibrationReady"); + //多重キャリブレーション時の不良動作対処に、2回キャリブレーション要求する + externalController.CalibrationReady = true; + Invoke("CalibrationReady2", 0.5f); + } + void CalibrationReady2() { + Debug.Log("[CalibrationByController] CalibrationReady"); + + externalController.CalibrationReady = true; + Invoke("CalibrationExecute", Time); + } + void CalibrationExecute() { + Debug.Log("[CalibrationByController] CalibrationExecute"); + + //キャリブレーション実施 + externalController.CalibrationExecute = true; + } +} diff --git a/Assets/External/EVMC4U/SampleScripts/CalibrationByController/CalibrationByController.cs.meta b/Assets/External/EVMC4U/SampleScripts/CalibrationByController/CalibrationByController.cs.meta new file mode 100644 index 000000000..adca077f3 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CalibrationByController/CalibrationByController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a57104fd6abed25418f0b912791d8f6d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover.meta b/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover.meta new file mode 100644 index 000000000..d5c32a6a8 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 46a4a79844c54ef45967f469e02791ed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover/CapsuleRigidbodyMover.cs b/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover/CapsuleRigidbodyMover.cs new file mode 100644 index 000000000..b19dbf453 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover/CapsuleRigidbodyMover.cs @@ -0,0 +1,117 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +namespace EVMC4U +{ + public class CapsuleRigidbodyMover : MonoBehaviour + { + public Transform MovePos; + public Transform MoveRot; + public Transform chest; + + EDirection direction = EDirection.STOP; + bool click = false; + + enum EDirection { + STOP, + FORWARD, + BACK, + LEFT, + RIGHT + } + + // Start is called before the first frame update + void Start() + { + } + + // Update is called once per frame + void Update() + { + switch (direction) { + case EDirection.FORWARD: MovePos.position += chest.forward * 10f * Time.deltaTime; break; + case EDirection.BACK: MovePos.position += chest.forward * -10f * Time.deltaTime; break; + case EDirection.LEFT: MoveRot.Rotate(new Vector3(0, -100f * Time.deltaTime, 0)); break; + case EDirection.RIGHT: MoveRot.Rotate(new Vector3(0, 100f * Time.deltaTime, 0)); break; + default: break; + } + } + + public void KeyInputEvent(EVMC4U.KeyInput key) + { + if (key.active == 1) + { + switch (key.name) { + case "W": direction = EDirection.FORWARD; break; + case "S": direction = EDirection.BACK; break; + case "A": direction = EDirection.LEFT; break; + case "D": direction = EDirection.RIGHT; break; + } + }else{ + direction = 0; + } + } + + public void ControllerInputEvent(EVMC4U.ControllerInput con) + { + if (con.name == "PositionTrackpad") + { + if (con.IsAxis == 1) + { + var rot = Mathf.Atan2(con.Axis.x, con.Axis.y) * Mathf.Rad2Deg; + + if (-45 <= rot && rot < 45) + { + direction = EDirection.FORWARD; + } + else if (45 <= rot && rot < 135) + { + direction = EDirection.RIGHT; + } + else if (-135 <= rot && rot < -45) + { + direction = EDirection.LEFT; + } + else + { + direction = EDirection.BACK; + } + } + } + if(con.name == "ClickTrackpad") + { + click = con.active == 1; + } + if (!click) + { + direction = EDirection.STOP; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover/CapsuleRigidbodyMover.cs.meta b/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover/CapsuleRigidbodyMover.cs.meta new file mode 100644 index 000000000..b70faa262 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/CapsuleRigidbodyMover/CapsuleRigidbodyMover.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f1fc480ff691e345af16e7fa651417e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/DeviceAttacher.meta b/Assets/External/EVMC4U/SampleScripts/DeviceAttacher.meta new file mode 100644 index 000000000..f5c587455 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/DeviceAttacher.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86b6989340add9447bb256f0c003b57f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/DeviceAttacher/DeviceAttacher.cs b/Assets/External/EVMC4U/SampleScripts/DeviceAttacher/DeviceAttacher.cs new file mode 100644 index 000000000..a8c12b823 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/DeviceAttacher/DeviceAttacher.cs @@ -0,0 +1,43 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2020 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using EVMC4U; + +public class DeviceAttacher: MonoBehaviour { + public DeviceReceiver deviceReceiver; + public string DeviceSerial = null; + + void Update () { + for (int i = 0; i < deviceReceiver.Serials.Length; i++) { + if (deviceReceiver.Serials[i] == DeviceSerial) { + deviceReceiver.Transforms[i] = transform; + } + } + } +} diff --git a/Assets/External/EVMC4U/SampleScripts/DeviceAttacher/DeviceAttacher.cs.meta b/Assets/External/EVMC4U/SampleScripts/DeviceAttacher/DeviceAttacher.cs.meta new file mode 100644 index 000000000..b796319c7 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/DeviceAttacher/DeviceAttacher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6adc09d226c320b47931ccca7db11d22 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/FreezeSwitch.meta b/Assets/External/EVMC4U/SampleScripts/FreezeSwitch.meta new file mode 100644 index 000000000..60fdeed94 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/FreezeSwitch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e3ab1687368e7234191bef23b011eda6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/FreezeSwitch/FreezeSwitch.cs b/Assets/External/EVMC4U/SampleScripts/FreezeSwitch/FreezeSwitch.cs new file mode 100644 index 000000000..28b5de11a --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/FreezeSwitch/FreezeSwitch.cs @@ -0,0 +1,64 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace EVMC4U +{ + public class FreezeSwitch : MonoBehaviour + { + public ExternalReceiver externalReceiver; + public InputReceiver inputReceiver; + + public string Key= "スペース"; + public string Button= "ClickMenu"; + void Start() + { + inputReceiver.KeyInputAction.AddListener(OnKey); + inputReceiver.ControllerInputAction.AddListener(OnCon); + } + void OnKey(KeyInput key) + { + if (key.name == Key) { + if (key.active == 1) { + externalReceiver.Freeze = !externalReceiver.Freeze; + } + } + } + void OnCon(ControllerInput con) + { + if (con.name == Button) + { + if (con.active == 1) + { + externalReceiver.Freeze = !externalReceiver.Freeze; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/SampleScripts/FreezeSwitch/FreezeSwitch.cs.meta b/Assets/External/EVMC4U/SampleScripts/FreezeSwitch/FreezeSwitch.cs.meta new file mode 100644 index 000000000..c7d91f535 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/FreezeSwitch/FreezeSwitch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 97fd16077045a25459ca9b9ad21be3e3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/HandCatch.meta b/Assets/External/EVMC4U/SampleScripts/HandCatch.meta new file mode 100644 index 000000000..7f8f7ed23 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/HandCatch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1ba7b15a3117ea446a06b3d34fa9b5e1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch.cs b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch.cs new file mode 100644 index 000000000..c58ce8cc2 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch.cs @@ -0,0 +1,412 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace EVMC4U +{ + [RequireComponent(typeof(ExternalReceiver))] + public class HandCatch : MonoBehaviour + { + //表示オンオフ + public bool ShowCollider = true; + bool ShowColliderOld = true; + + public float NonHoldFilter = 0f; + public float InHoldFilter = 0.90f; + + float offset = 0.06f; + float size = 0.15f; + + public string CollisionTag = ""; + + public float SpeedMultiplier = 1.0f; + + public string LeftKey = "Z"; + public string RightKey = "X"; + public string ControllerButton = "ClickTrigger"; + + public bool signaling = true; + + public bool StickyMode = false; + + bool stickyLeft = false; + bool stickyRight = false; + + ExternalReceiver exrcv; + InputReceiver inputrcv; + + Transform leftHand; + Transform rightHand; + + GameObject leftSphere; + GameObject rightSphere; + + Rigidbody leftRigidBody; + Rigidbody rightRigidBody; + + Vector3 leftLastPos; + Vector3 rightLastPos; + Vector3 leftLastSpeed; + Vector3 rightLastSpeed; + + HandCatch_Helper leftHelper; + HandCatch_Helper rightHelper; + + GameObject leftCatchedObject; + GameObject rightCatchedObject; + + bool leftCatchedObjectIsKinematic; + bool rightCatchedObjectIsKinematic; + + Transform leftCatchedObjectParent; + Transform rightCatchedObjectParent; + + void Start() + { + //ExternalReceiverにキー操作を登録 + exrcv = GetComponent(); + inputrcv = GetComponentInChildren(); + + inputrcv.ControllerInputAction.AddListener(ControllerInputEvent); + inputrcv.KeyInputAction.AddListener(KeyInputEvent); + + //ブレ防止用にフィルタを設定 + exrcv.BonePositionFilterEnable = true; + exrcv.BoneRotationFilterEnable = true; + exrcv.BoneFilter = NonHoldFilter; + + //手のボーンを取得 + var anim = exrcv.Model.GetComponent(); + leftHand = anim.GetBoneTransform(HumanBodyBones.LeftHand); + rightHand = anim.GetBoneTransform(HumanBodyBones.RightHand); + + //左手当たり判定スフィア生成 + leftSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + leftSphere.transform.parent = leftHand; + leftSphere.transform.localPosition = new Vector3(-offset, 0f, 0f); + leftSphere.transform.localScale = new Vector3(size, size, size); + + //左手当たり判定スフィアコライダー設定 + var leftCollider = leftSphere.GetComponent(); + //コライダーは反応のみで衝突しない + leftCollider.isTrigger = true; + + //左手当たり判定物理演算追加 + leftRigidBody = leftSphere.AddComponent(); + //物理は反応のみで演算しない + leftRigidBody.isKinematic = true; + + //左手当たり判定ヘルパー追加 + leftHelper = leftSphere.AddComponent(); + + //右手当たり判定スフィア生成 + rightSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + rightSphere.transform.parent = rightHand; + rightSphere.transform.localPosition = new Vector3(offset, 0f, 0f); + rightSphere.transform.localScale = new Vector3(size, size, size); + + //右手当たり判定スフィアコライダー設定 + var rightCollider = rightSphere.GetComponent(); + //コライダーは反応のみで衝突しない + rightCollider.isTrigger = true; + + //右手当たり判定物理演算追加 + rightRigidBody = rightSphere.AddComponent(); + //物理は反応のみで演算しない + rightRigidBody.isKinematic = true; + + //右手当たり判定ヘルパー追加 + rightHelper = rightSphere.AddComponent(); + } + + //物理演算のためFixedUpdate + void FixedUpdate() + { + //剥がれ防止で親を設定 + leftSphere.transform.parent = leftHand; + leftSphere.transform.localPosition = new Vector3(-offset, 0f, 0f); + leftSphere.transform.localScale = new Vector3(size, size, size); + rightSphere.transform.parent = rightHand; + rightSphere.transform.localPosition = new Vector3(offset, 0f, 0f); + rightSphere.transform.localScale = new Vector3(size, size, size); + + //表示非表示を反映 + if (ShowColliderOld != ShowCollider) { + leftSphere.GetComponent().enabled = ShowCollider; + rightSphere.GetComponent().enabled = ShowCollider; + + ShowColliderOld = ShowCollider; + } + + //投げるとき用にフレーム間速度を求める + leftLastSpeed = SpeedMultiplier * (leftHand.transform.position - leftLastPos)/Time.fixedDeltaTime; + leftLastPos = leftHand.transform.position; + rightLastSpeed = SpeedMultiplier * (rightHand.transform.position - rightLastPos)/Time.fixedDeltaTime; + rightLastPos = rightHand.transform.position; + } + + //左手掴む処理 + void CatchLeft(bool s) + { + if (s) + { + //つかみ処理 + if (leftHelper.Trigger && leftHelper.other != null) + { + //コリジョンタグになにか文字が入っていて、対象と一致しない場合は処理しない + if (CollisionTag != "" && CollisionTag != leftHelper.other.tag) { + return; + } + //左手ですでに掴んでいるものは掴まない + if (leftHelper.other.gameObject.transform.parent == leftSphere.transform) + { + return; + } + //右手ですでに掴んでいるものは掴まない + if (leftHelper.other.gameObject.transform.parent == rightSphere.transform) + { + return; + } + + //解除用に保持 + leftCatchedObject = leftHelper.other.gameObject; + + //親を保存 + leftCatchedObjectParent = leftCatchedObject.transform.parent; + + //手を親に上書き + leftCatchedObject.transform.parent = leftSphere.transform; + + //掴むために物理演算を切る + var rigid = leftCatchedObject.GetComponent(); + if (rigid != null) { + //IsKinematicを保存 + leftCatchedObjectIsKinematic = rigid.isKinematic; + //設定に関わらずtrueにする + rigid.isKinematic = true; + } + + //フィルタ強く + exrcv.BoneFilter = InHoldFilter; + + //オブジェクトにメッセージを送る + if (signaling) + { + leftCatchedObject.SendMessage("OnCatchedLeftHand"); + } + } + } + else + { + if (leftCatchedObject != null) + { + //解除して親に戻す + leftCatchedObject.transform.parent = leftCatchedObjectParent; + + //掴むために物理演算を切る + var rigid = leftCatchedObject.GetComponent(); + if (rigid != null) + { + //IsKinematicを保存していた設定にする + rigid.isKinematic = leftCatchedObjectIsKinematic; + + //投げるために速度を転送する + rigid.linearVelocity = leftLastSpeed; + } + + //フィルタ解除 + exrcv.BoneFilter = NonHoldFilter; + + //オブジェクトにメッセージを送る + if (signaling) + { + leftCatchedObject.SendMessage("OnReleasedLeftHand"); + } + } + } + } + + void CatchRight(bool s) + { + if (s) + { + if (rightHelper.Trigger && rightHelper.other != null) + { + //コリジョンタグになにか文字が入っていて、対象と一致しない場合は処理しない + if (CollisionTag != "" && CollisionTag != rightHelper.other.tag) + { + return; + } + //左手ですでに掴んでいるものは掴まない + if (rightHelper.other.gameObject.transform.parent == leftSphere.transform) + { + return; + } + //右手ですでに掴んでいるものは掴まない + if (rightHelper.other.gameObject.transform.parent == rightSphere.transform) + { + return; + } + + //解除用に保持 + rightCatchedObject = rightHelper.other.gameObject; + + //親を保存 + rightCatchedObjectParent = rightCatchedObject.transform.parent; + + //手を親に上書き + rightCatchedObject.transform.parent = rightSphere.transform; + + //掴むために物理演算を切る + var rigid = rightCatchedObject.GetComponent(); + if (rigid != null) + { + //IsKinematicを保存 + rightCatchedObjectIsKinematic = rigid.isKinematic; + //設定に関わらずtrueにする + rigid.isKinematic = true; + } + + //フィルタ強く + exrcv.BoneFilter = InHoldFilter; + + //オブジェクトにメッセージを送る + if (signaling) + { + rightCatchedObject.SendMessage("OnCatchedRightHand"); + } + } + } + else + { + if (rightCatchedObject != null) + { + //解除して親に戻す + rightCatchedObject.transform.parent = rightCatchedObjectParent; + + //掴むために物理演算を切る + var rigid = rightCatchedObject.GetComponent(); + if (rigid != null) + { + //IsKinematicを保存していた設定にする + rigid.isKinematic = rightCatchedObjectIsKinematic; + + Debug.Log(rightRigidBody.linearVelocity); + //投げるために速度を転送する + rigid.linearVelocity = rightLastSpeed; + } + + //フィルタ解除 + exrcv.BoneFilter = NonHoldFilter; + + //オブジェクトにメッセージを送る + if (signaling) + { + rightCatchedObject.SendMessage("OnReleasedRightHand"); + } + } + } + } + + public void KeyInputEvent(EVMC4U.KeyInput key) + { + if (!StickyMode) + { + //Zキーが押されたか + if (key.name == LeftKey) + { + //つかみ・離し + CatchLeft(key.active == 1); + } + //Xキー押されたか + if (key.name == RightKey) + { + //つかみ・離し + CatchRight(key.active == 1); + } + } + else { + if (key.active == 1) + { + //Zキーが押されたか + if (key.name == LeftKey) + { + //つかみ・離し + stickyLeft = !stickyLeft; + CatchLeft(stickyLeft); + } + //Xキー押されたか + if (key.name == RightKey) + { + //つかみ・離し + stickyRight = !stickyRight; + CatchRight(stickyRight); + } + } + } + } + + public void ControllerInputEvent(EVMC4U.ControllerInput con) + { + //トリガー引かれたか + if (con.name == ControllerButton) + { + if (!StickyMode) + { + if (con.IsLeft == 1) + { + //つかみ・離し + CatchLeft(con.active == 1); + } + else + { + //つかみ・離し + CatchRight(con.active == 1); + } + } + else { + if (con.active == 1) { + if (con.IsLeft == 1) + { + //つかみ・離し + stickyLeft = !stickyLeft; + CatchLeft(stickyLeft); + } + else + { + //つかみ・離し + stickyRight = !stickyRight; + CatchRight(stickyRight); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch.cs.meta b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch.cs.meta new file mode 100644 index 000000000..1670c879f --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d956bc80add4844891ac394eb195161 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_Helper.cs b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_Helper.cs new file mode 100644 index 000000000..c7330ca12 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_Helper.cs @@ -0,0 +1,54 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace EVMC4U +{ + public class HandCatch_Helper : MonoBehaviour + { + public bool Trigger = false; + public Collider other; + + private void OnTriggerEnter(Collider other) + { + this.other = other; + Trigger = true; + + GetComponent().material.color = Color.cyan; + } + private void OnTriggerExit(Collider other) + { + this.other = other; + Trigger = false; + + GetComponent().material.color = Color.white; + } + + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_Helper.cs.meta b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_Helper.cs.meta new file mode 100644 index 000000000..4e894e514 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_Helper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32a6e766ebdc4c140b2e2324eae9915c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_WeaponHelper.cs b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_WeaponHelper.cs new file mode 100644 index 000000000..1b3744758 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_WeaponHelper.cs @@ -0,0 +1,110 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +//掴まれたとき: 手の位置に持つ +//離されたとき: 鞘の位置なら、収まるべき場所に戻る +// そうでないなら、親なしにしてとどまる +namespace EVMC4U +{ + public class HandCatch_WeaponHelper : MonoBehaviour + { + public Transform CaseParent; //鞘オブジェクト + public Transform LeftHoldPosition; //左手保持位置 + public Transform RightHoldPosition; //右手保持位置 + + //鞘に戻らない限界距離 + public float Threshold = 0.5f; + + //どれだけふわっと動くか + public float Filter = 0.8f; + + //初期位置(鞘に収まっている状態) + Vector3 CasePosition; + Quaternion CaseRotation; + + //初期位置(鞘に収まっている状態) + Vector3 TragetPosition; + Quaternion TargetRotation; + + void Start() + { + CasePosition = transform.localPosition; + CaseRotation = transform.localRotation; + + TragetPosition = CasePosition; + TargetRotation = CaseRotation; + } + + void Update() + { + if (transform.parent != null) { + transform.localPosition = Vector3.Lerp(TragetPosition, transform.localPosition, Filter); + transform.localRotation = Quaternion.Lerp(TargetRotation, transform.localRotation, Filter); + } + } + + void OnCatchedLeftHand() + { + Debug.Log("C:L"); + TragetPosition = LeftHoldPosition.localPosition; + TargetRotation = LeftHoldPosition.localRotation; + } + void OnCatchedRightHand() + { + Debug.Log("C:R"); + TragetPosition = RightHoldPosition.localPosition; + TargetRotation = RightHoldPosition.localRotation; + } + + void OnReleasedLeftHand() + { + Debug.Log("R:L"); + OnReleasedRightHand();//同じ処理 + } + + void OnReleasedRightHand() + { + Debug.Log("R:R"); + + //計算用に一時的に親にする + transform.parent = CaseParent; + float distance = Vector3.Distance(CasePosition, transform.localPosition); + if (distance < Threshold) + { + transform.parent = CaseParent; + TragetPosition = CasePosition; + TargetRotation = CaseRotation; + } + else { + transform.parent = null; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_WeaponHelper.cs.meta b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_WeaponHelper.cs.meta new file mode 100644 index 000000000..0263fa669 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/HandCatch/HandCatch_WeaponHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b722cb0621aaad4f9585f5d17bf89e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/ObjectSwitch.meta b/Assets/External/EVMC4U/SampleScripts/ObjectSwitch.meta new file mode 100644 index 000000000..89e06e98b --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/ObjectSwitch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ac5b962b075c1f4e913c49ad9c50680 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/ObjectSwitch/ObjectSwitch.cs b/Assets/External/EVMC4U/SampleScripts/ObjectSwitch/ObjectSwitch.cs new file mode 100644 index 000000000..44daac8a7 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/ObjectSwitch/ObjectSwitch.cs @@ -0,0 +1,57 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2020 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using EVMC4U; + +public class ObjectSwitch : MonoBehaviour +{ + public InputReceiver inputReceiver; + + public string Key = "スペース"; + public string Button = "ClickMenu"; + void Start() + { + inputReceiver.KeyInputAction.AddListener(OnKey); + inputReceiver.ControllerInputAction.AddListener(OnCon); + } + void OnKey(KeyInput key) + { + if (key.name == Key && key.active == 1) + { + gameObject.SetActive(!gameObject.activeSelf); + } + } + void OnCon(ControllerInput con) + { + if (con.name == Button && con.active == 1) + { + gameObject.SetActive(!gameObject.activeSelf); + } + } +} diff --git a/Assets/External/EVMC4U/SampleScripts/ObjectSwitch/ObjectSwitch.cs.meta b/Assets/External/EVMC4U/SampleScripts/ObjectSwitch/ObjectSwitch.cs.meta new file mode 100644 index 000000000..77bcbec0f --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/ObjectSwitch/ObjectSwitch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca3e3053b95a4864cb49cc75a25c816f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/TeleportKit.meta b/Assets/External/EVMC4U/SampleScripts/TeleportKit.meta new file mode 100644 index 000000000..65be00ad3 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/TeleportKit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ae2642b6e10fda49985acfd80a2bcda +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/TeleportKit/TeleportManager.cs b/Assets/External/EVMC4U/SampleScripts/TeleportKit/TeleportManager.cs new file mode 100644 index 000000000..a5d839992 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/TeleportKit/TeleportManager.cs @@ -0,0 +1,73 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace EVMC4U +{ + public class TeleportManager : MonoBehaviour + { + public InputReceiver inputReceiver; + public GameObject ParentObject; + public Animator model; + + public string[] TriggerKey = new string[5]; + public Transform[] TeleportTarget = new Transform[5]; + + private Transform footpos; + + void Start() + { + inputReceiver.KeyInputAction.AddListener(OnKey); + + footpos = model.GetBoneTransform(HumanBodyBones.LeftFoot); + } + + void OnKey(KeyInput key) + { + //押されたときのみ + if (key.active != 1) { + return; + } + //該当するキーを探す + for (int i = 0; i < TriggerKey.Length; i++) { + if (TriggerKey[i] == key.name) { + Debug.Log("Key:" + key.name); + //発見したらターゲット有効性をチェックする + if (TeleportTarget.Length > i) { + if (TeleportTarget[i] != null) { + //モデルに反映 + ParentObject.transform.position -= (footpos.position - TeleportTarget[i].position); + ParentObject.transform.rotation = TeleportTarget[i].rotation; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/SampleScripts/TeleportKit/TeleportManager.cs.meta b/Assets/External/EVMC4U/SampleScripts/TeleportKit/TeleportManager.cs.meta new file mode 100644 index 000000000..6aa14efcd --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/TeleportKit/TeleportManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ca42dd9317a6194d82d5ab6c382cd59 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/misc.meta b/Assets/External/EVMC4U/SampleScripts/misc.meta new file mode 100644 index 000000000..03d828a05 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/misc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9cc666ef35f0a954280a2dc6a3c01c04 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/SampleScripts/misc/HiResolutionPhotoCamera.cs b/Assets/External/EVMC4U/SampleScripts/misc/HiResolutionPhotoCamera.cs new file mode 100644 index 000000000..e033ecba6 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/misc/HiResolutionPhotoCamera.cs @@ -0,0 +1,86 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class HiResolutionPhotoCamera : MonoBehaviour { + //撮影したい解像度 + public int width = 4096; + public int height = 2160; + + //撮影したいカメラ + public Camera cam; + + //撮影ボタン + public bool shot = false; + + void Update () { + //撮影ボタンが押されたら撮影する + if (shot) { + shot = false; + TakePhoto(); + } + } + + void TakePhoto() { + width = 8192; + height = (int)((float)8192 * (float)Screen.height/ (float)Screen.width); + + //撮影したい解像度のRenderテクスチャを作成 + var renderTexture = new RenderTexture(width, height, 24); + //アクティブなレンダーテクスチャを保存 + var save = RenderTexture.active; + + //カメラに描画対象を設定 + cam.targetTexture = renderTexture; + //ReadPixelsの取得元(アクティブなレンダーテクスチャ)を設定 + RenderTexture.active = renderTexture; + + //即座にレンダリングする + cam.Render(); + + //テクスチャを生成して読み取り + Texture2D texture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false); + texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0); + texture.Apply(); + + //テクスチャをpngファイルに保存 + byte[] data = texture.EncodeToPNG(); + File.WriteAllBytes("output" + DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss-ff")+ ".png", data); + + //破棄 + DestroyImmediate(texture); + + //カメラの描画対象を元に戻す + cam.targetTexture = null; + //アクティブなレンダーテクスチャを復元 + RenderTexture.active = save; + } +} diff --git a/Assets/External/EVMC4U/SampleScripts/misc/HiResolutionPhotoCamera.cs.meta b/Assets/External/EVMC4U/SampleScripts/misc/HiResolutionPhotoCamera.cs.meta new file mode 100644 index 000000000..2d2305a31 --- /dev/null +++ b/Assets/External/EVMC4U/SampleScripts/misc/HiResolutionPhotoCamera.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a163057f77fd4964d930cb2b19e510c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Test.meta b/Assets/External/EVMC4U/Test.meta new file mode 100644 index 000000000..07b4912cc --- /dev/null +++ b/Assets/External/EVMC4U/Test.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e3d414de8589044f8af782fc6e85db6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Test/AddComponentTest.cs b/Assets/External/EVMC4U/Test/AddComponentTest.cs new file mode 100644 index 000000000..dbd802320 --- /dev/null +++ b/Assets/External/EVMC4U/Test/AddComponentTest.cs @@ -0,0 +1,51 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +namespace EVMC4U +{ + public class AddComponentTest : MonoBehaviour + { + public GameObject Model; + + // Use this for initialization + void Start() + { + var x = gameObject.AddComponent(); + x.Model = Model; + } + + // Update is called once per frame + void Update() + { + + } + } +} diff --git a/Assets/External/EVMC4U/Test/AddComponentTest.cs.meta b/Assets/External/EVMC4U/Test/AddComponentTest.cs.meta new file mode 100644 index 000000000..e9b884de0 --- /dev/null +++ b/Assets/External/EVMC4U/Test/AddComponentTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca033debfd5f5e749bf2054d2a0527dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Test/DaisyChainTesting.cs b/Assets/External/EVMC4U/Test/DaisyChainTesting.cs new file mode 100644 index 000000000..3ce9e753c --- /dev/null +++ b/Assets/External/EVMC4U/Test/DaisyChainTesting.cs @@ -0,0 +1,55 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using uOSC; + +namespace EVMC4U +{ + public class DaisyChainTesting : MonoBehaviour, IExternalReceiver + { + //デイジーチェーンテスト + public void MessageDaisyChain(ref Message message, int callCount) + { + if (message.address == "/VMC/Ext/T") + { + Debug.Log(message.address + "[" + (float)message.values[0] + "]"); + } + + //メッセージ全部Logに出そうとか考えないこと。Unityが死ぬほど送られてきます。 + } + + public void UpdateDaisyChain() + { + throw new NotImplementedException(); + } + + } + +} diff --git a/Assets/External/EVMC4U/Test/DaisyChainTesting.cs.meta b/Assets/External/EVMC4U/Test/DaisyChainTesting.cs.meta new file mode 100644 index 000000000..8b026623f --- /dev/null +++ b/Assets/External/EVMC4U/Test/DaisyChainTesting.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 115a682733d799a4c8da6c4e1da18253 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/Test/InputTesting.cs b/Assets/External/EVMC4U/Test/InputTesting.cs new file mode 100644 index 000000000..3b94bd9a3 --- /dev/null +++ b/Assets/External/EVMC4U/Test/InputTesting.cs @@ -0,0 +1,103 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace EVMC4U +{ + public class InputTesting : MonoBehaviour + { + public InputReceiver receiver; + private void Start() + { + receiver.ControllerInputAction.AddListener(ControllerInputEvent); + receiver.KeyInputAction.AddListener(KeyInputEvent); + + receiver.MidiNoteInputAction.AddListener(MidiNoteEvent); + receiver.MidiCCValueInputAction.AddListener(MidiCCValEvent); + receiver.MidiCCButtonInputAction.AddListener(MidiCCButtonEvent); + } + + public void KeyInputEvent(EVMC4U.KeyInput key) + { + switch (key.active) + { + case 1: + Debug.Log("" + key.name + "(" + key.keycode + ") pressed."); + break; + case 0: + Debug.Log("" + key.name + "(" + key.keycode + ") released."); + break; + default: + Debug.Log("" + key.name + "(" + key.keycode + ") unknown."); + break; + } + } + + public void ControllerInputEvent(EVMC4U.ControllerInput con) + { + switch (con.active) + { + case 2: + Debug.Log("" + con.name + "(" + ((con.IsAxis == 1) ? "Axis" : "Non Axis") + "/" + ((con.IsLeft == 1) ? "Left" : "Right") + "/" + ((con.IsTouch == 1) ? "Touch" : "Non Touch") + " [" + con.Axis.x + "," + con.Axis.y + "," + con.Axis.z + "]" + ") changed."); + break; + case 1: + Debug.Log("" + con.name + "(" + ((con.IsAxis == 1) ? "Axis" : "Non Axis") + "/" + ((con.IsLeft == 1) ? "Left" : "Right") + "/" + ((con.IsTouch == 1) ? "Touch" : "Non Touch") + " [" + con.Axis.x + "," + con.Axis.y + "," + con.Axis.z + "]" + ") pressed."); + break; + case 0: + Debug.Log("" + con.name + "(" + ((con.IsAxis == 1) ? "Axis" : "Non Axis") + "/" + ((con.IsLeft == 1) ? "Left" : "Right") + "/" + ((con.IsTouch == 1) ? "Touch" : "Non Touch") + " [" + con.Axis.x + "," + con.Axis.y + "," + con.Axis.z + "]" + ") released."); + break; + default: + Debug.Log("" + con.name + "(" + ((con.IsAxis == 1) ? "Axis" : "Non Axis") + "/" + ((con.IsLeft == 1) ? "Left" : "Right") + "/" + ((con.IsTouch == 1) ? "Touch" : "Non Touch") + " [" + con.Axis.x + "," + con.Axis.y + "," + con.Axis.z + "]" + ") unknown."); + break; + } + } + + public void MidiNoteEvent(EVMC4U.MidiNote note) + { + if (note.active == 1) + { + Debug.Log("MIDI Note ON =" + note.note + " channel=" + note.channel + " velocity=" + note.velocity); + } + else + { + Debug.Log("MIDI note OFF =" + note.note + " channel=" + note.channel + " velocity=" + note.velocity); + } + } + + public void MidiCCValEvent(EVMC4U.MidiCCValue val) + { + Debug.Log("MIDI CC Value knob=" + val.knob + " value=" + val.value); + } + + public void MidiCCButtonEvent(EVMC4U.MidiCCButton bit) + { + Debug.Log("MIDI CC Button knob=" + bit.knob + " active=" + bit.active); + } + } +} \ No newline at end of file diff --git a/Assets/External/EVMC4U/Test/InputTesting.cs.meta b/Assets/External/EVMC4U/Test/InputTesting.cs.meta new file mode 100644 index 000000000..4978ad1e7 --- /dev/null +++ b/Assets/External/EVMC4U/Test/InputTesting.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30c17a2abdf40c749a563c6beb9c4cb3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/class.meta b/Assets/External/EVMC4U/class.meta new file mode 100644 index 000000000..b2e62171b --- /dev/null +++ b/Assets/External/EVMC4U/class.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7618eb7d813fe0348ba985c6aee44247 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/class/EVMC4UeventClass.cs b/Assets/External/EVMC4U/class/EVMC4UeventClass.cs new file mode 100644 index 000000000..1dd7cc0cc --- /dev/null +++ b/Assets/External/EVMC4U/class/EVMC4UeventClass.cs @@ -0,0 +1,45 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +namespace EVMC4U { + //イベント定義 + [Serializable] + public class KeyInputEvent : UnityEvent { }; + [Serializable] + public class ControllerInputEvent : UnityEvent { }; + [Serializable] + public class MidiNoteInputEvent : UnityEvent { }; + [Serializable] + public class MidiCCValueInputEvent : UnityEvent { }; + [Serializable] + public class MidiCCButtonInputEvent : UnityEvent { }; +} diff --git a/Assets/External/EVMC4U/class/EVMC4UeventClass.cs.meta b/Assets/External/EVMC4U/class/EVMC4UeventClass.cs.meta new file mode 100644 index 000000000..ac58fc0a5 --- /dev/null +++ b/Assets/External/EVMC4U/class/EVMC4UeventClass.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c8815bc3a23b2e64d867d5a797c3d66b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/class/EVMC4Ustructs.cs b/Assets/External/EVMC4U/class/EVMC4Ustructs.cs new file mode 100644 index 000000000..34146b0fc --- /dev/null +++ b/Assets/External/EVMC4U/class/EVMC4Ustructs.cs @@ -0,0 +1,128 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace EVMC4U { + //キーボード入力情報 + public struct KeyInput + { + public int active; + public string name; + public int keycode; + } + + //コントローラ入力情報 + public struct ControllerInput + { + public int active; + public string name; + public int IsLeft; + public int IsTouch; + public int IsAxis; + public Vector3 Axis; + } + + //MIDI Note入力情報 + public struct MidiNote + { + public int active; + public int channel; + public int note; + public float velocity; + } + + //MIDI CC Value入力情報 + public struct MidiCCValue + { + public int knob; + public float value; + } + + //MIDI CC Button入力情報 + public struct MidiCCButton + { + public int knob; + public float active; + } + + public enum CalibrationState + { + Uncalibrated = 0, + WaitingForCalibrating = 1, + Calibrating = 2, + Calibrated = 3, + } + public enum CalibrationMode + { + Normal = 0, + MR_Hand = 1, + MR_Floor = 2, + T_Pose = 3, + } + public enum VirtualDevice + { + HMD = 0, + Controller = 1, + Tracker = 2, + } + public class LabelAttribute : PropertyAttribute + { + public readonly string name; + public LabelAttribute(string name) + { + this.name = name; + } + } + +#if UNITY_EDITOR + [CustomPropertyDrawer(typeof(LabelAttribute))] + public class LabelAttributeDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { +#if EVMC4U_JA + var attr = attribute as LabelAttribute; + label.text = attr.name; +#endif + EditorGUI.PropertyField(position, property, label, true); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return base.GetPropertyHeight(property, label); + } + } +#endif +} diff --git a/Assets/External/EVMC4U/class/EVMC4Ustructs.cs.meta b/Assets/External/EVMC4U/class/EVMC4Ustructs.cs.meta new file mode 100644 index 000000000..b274ec802 --- /dev/null +++ b/Assets/External/EVMC4U/class/EVMC4Ustructs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c408232ad0549a04885448ccc3c949c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/class/ExternalReceiverManager.cs b/Assets/External/EVMC4U/class/ExternalReceiverManager.cs new file mode 100644 index 000000000..c116409b1 --- /dev/null +++ b/Assets/External/EVMC4U/class/ExternalReceiverManager.cs @@ -0,0 +1,88 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +namespace EVMC4U { + public class ExternalReceiverManager + { + List receivers = new List(); + + //コンストラクタ + public ExternalReceiverManager(GameObject[] gameObjects) { + GetIExternalReceiver(gameObjects); + } + + //ゲームオブジェクトからIExternalReceiverを探す + public void GetIExternalReceiver(GameObject[] gameObjects) + { + //リストをクリア + receivers.Clear(); + if (gameObjects == null) { + return; + } + + //GameObjectを調べる + foreach (var g in gameObjects) + { + //GameObjectが存在するなら + if (g != null) { + //IExternalReceiverを探す + var f = g.GetComponent(typeof(IExternalReceiver)) as IExternalReceiver; + if (f != null) { + //リストに突っ込む + receivers.Add(f); + } + } + } + } + + //IExternalReceiverのリストを使って配信する + public bool SendNextReceivers(uOSC.Message message, int callCount) + { + if (callCount > 100) + { + //無限ループ対策 + Debug.LogError("[ExternalReceiver] Too many call(maybe infinite loop)."); + return false; + } + + foreach (var r in receivers) { + //インターフェースがあるか + if (r != null) + { + //Chain数を+1して次へ + r.MessageDaisyChain(ref message, callCount + 1); + } + } + return true; + } + } +} diff --git a/Assets/External/EVMC4U/class/ExternalReceiverManager.cs.meta b/Assets/External/EVMC4U/class/ExternalReceiverManager.cs.meta new file mode 100644 index 000000000..f2b73a07d --- /dev/null +++ b/Assets/External/EVMC4U/class/ExternalReceiverManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5bff20909940d4b42906662b389b7cb1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/EVMC4U/class/IExternalReceiver.cs b/Assets/External/EVMC4U/class/IExternalReceiver.cs new file mode 100644 index 000000000..15255be37 --- /dev/null +++ b/Assets/External/EVMC4U/class/IExternalReceiver.cs @@ -0,0 +1,40 @@ +/* + * ExternalReceiver + * https://sabowl.sakura.ne.jp/gpsnmeajp/ + * + * MIT License + * + * Copyright (c) 2019 gpsnmeajp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +namespace EVMC4U { + //デイジーチェーン受信の最低限のインターフェース + public interface IExternalReceiver + { + void MessageDaisyChain(ref uOSC.Message message, int callCount); + void UpdateDaisyChain(); + } +} diff --git a/Assets/External/EVMC4U/class/IExternalReceiver.cs.meta b/Assets/External/EVMC4U/class/IExternalReceiver.cs.meta new file mode 100644 index 000000000..8d290d306 --- /dev/null +++ b/Assets/External/EVMC4U/class/IExternalReceiver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f1804aa17fcc684f856124d233e9672 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/Client - OptiTrack.prefab b/Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/Client - OptiTrack.prefab index 4ea7725aa..4195b2258 100644 --- a/Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/Client - OptiTrack.prefab +++ b/Assets/External/OptiTrack Unity Plugin/OptiTrack/Prefabs/Client - OptiTrack.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ede9972b068fca6ddc5b3437bbb918c1aa31daf32f77acde061344497d1b422 -size 2481 +oid sha256:0725d6622005cda966a2c32dda8b2199a6f4dc1cc0feb58bbff880ba7fe4b83e +size 2480 diff --git a/Assets/External/UniGLTF/Editor/Animation/EditorAnimationExporter.cs b/Assets/External/UniGLTF/Editor/Animation/EditorAnimationExporter.cs index cbf8c3404..f7c248c99 100644 --- a/Assets/External/UniGLTF/Editor/Animation/EditorAnimationExporter.cs +++ b/Assets/External/UniGLTF/Editor/Animation/EditorAnimationExporter.cs @@ -13,16 +13,19 @@ namespace UniGLTF static List GetAnimationClips(GameObject Copy) { var clips = new List(); + var animator = Copy.GetComponent(); - var animation = Copy.GetComponent(); if (animator != null) { - clips = AnimationExporter.GetAnimationClips(animator); + clips.AddRange(AnimationExporter.GetAnimationClips(animator)); } - else if (animation != null) + + var animation = Copy.GetComponent(); + if (animation != null) { - clips = AnimationExporter.GetAnimationClips(animation); + clips.AddRange(AnimationExporter.GetAnimationClips(animation)); } + return clips; } diff --git a/Assets/External/UniGLTF/Editor/TopMenuImplementation.cs b/Assets/External/UniGLTF/Editor/GltfImportMenu.cs similarity index 84% rename from Assets/External/UniGLTF/Editor/TopMenuImplementation.cs rename to Assets/External/UniGLTF/Editor/GltfImportMenu.cs index 6a5cf2ad6..913dd69dc 100644 --- a/Assets/External/UniGLTF/Editor/TopMenuImplementation.cs +++ b/Assets/External/UniGLTF/Editor/GltfImportMenu.cs @@ -4,18 +4,19 @@ using UnityEngine; namespace UniGLTF { - public static class TopMenuImplementation + public static class GltfImportMenu { - public static void ExportGameObjectToGltfFile() - { - var window = (GltfExportWindow)GltfExportWindow.GetWindow(typeof(GltfExportWindow)); - window.titleContent = new GUIContent("Gltf Exporter"); - window.Show(); - } - + public const string MENU_NAME = "Import glTF... (*.gltf|*.glb|*.zip)"; public static void ImportGltfFileToGameObject() { - var path = EditorUtility.OpenFilePanel("open glb", "", "gltf,glb,zip"); + var path = EditorUtility.OpenFilePanel(MENU_NAME + ": open glb", "", +#if UNITY_EDITOR_OSX + // https://github.com/vrm-c/UniVRM/issues/1837 + "glb" +#else + "gltf,glb,zip" +#endif +); if (string.IsNullOrEmpty(path)) { return; @@ -91,11 +92,5 @@ namespace UniGLTF var asset = unitypath.LoadAsset(); Selection.activeObject = asset; } - - public static void GenerateSerializationCode() - { - SerializerGenerator.GenerateSerializer(); - DeserializerGenerator.GenerateSerializer(); - } } } diff --git a/Assets/External/UniGLTF/Editor/GltfImportMenu.cs.meta b/Assets/External/UniGLTF/Editor/GltfImportMenu.cs.meta new file mode 100644 index 000000000..275dd0fc3 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/GltfImportMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31e28050bb28edd40a730d8e05ddcde5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/AssetsPath.cs b/Assets/External/UniGLTF/Editor/MeshUtility/AssetsPath.cs deleted file mode 100644 index f3bedd50e..000000000 --- a/Assets/External/UniGLTF/Editor/MeshUtility/AssetsPath.cs +++ /dev/null @@ -1,309 +0,0 @@ -using System; -using System.IO; -using UnityEngine; -using System.Collections.Generic; -using UnityEditor; - - -namespace UniGLTF.MeshUtility -{ - /// - /// Application.dataPath を root とするファイルパスを扱う。 - /// (Project/Assets) - /// - public struct AssetsPath - { - public string RelativePath - { - get; - private set; - } - - public override string ToString() - { - return $"assets://{RelativePath}"; - } - - public string FileName - { - get { return Path.GetFileName(RelativePath); } - } - - public string FileNameWithoutExtension - { - get - { - return Path.GetFileNameWithoutExtension(RelativePath); - } - } - - public string Extension - { - get { return Path.GetExtension(RelativePath); } - } - - public AssetsPath Parent - { - get - { - return new AssetsPath(Path.GetDirectoryName(RelativePath)); - } - } - - static readonly char[] EscapeChars = new char[] - { - '\\', - '/', - ':', - '*', - '?', - '"', - '<', - '>', - '|', - }; - - static string EscapeFilePath(string path) - { - foreach (var x in EscapeChars) - { - path = path.Replace(x, '+'); - } - return path; - } - - public AssetsPath Child(string name) - { - if (RelativePath == null) - { - throw new NotImplementedException(); - } - else if (RelativePath == "") - { - return new AssetsPath(name); - } - else - { - return new AssetsPath(RelativePath + "/" + name); - } - } - - public override int GetHashCode() - { - if (RelativePath == null) - { - return 0; - } - return RelativePath.GetHashCode(); - } - - public override bool Equals(object obj) - { - if (obj is AssetsPath) - { - var rhs = (AssetsPath)obj; - if (RelativePath == null && rhs.RelativePath == null) - { - return true; - } - else if (RelativePath == null) - { - return false; - } - else if (rhs.RelativePath == null) - { - return false; - } - else - { - return RelativePath == rhs.RelativePath; - } - } - else - { - return false; - } - } - - AssetsPath(string value) : this() - { - RelativePath = value.Replace("\\", "/"); - } - - #region FullPath - static string s_basePath; - static string BaseFullPath - { - get - { - if (string.IsNullOrEmpty(s_basePath)) - { - s_basePath = Path.GetFullPath(Application.dataPath).Replace("\\", "/"); - } - return s_basePath; - } - } - - public string FullPath - { - get - { - if (RelativePath == null) - { - throw new NotImplementedException(); - } - return Path.Combine(BaseFullPath, RelativePath).Replace("\\", "/"); - } - } - - public bool IsFileExists - { - get { return File.Exists(FullPath); } - } - - public bool IsDirectoryExists - { - get { return Directory.Exists(FullPath); } - } - - /// - /// - /// - /// C:/path/to/file - /// - public static AssetsPath FromFullpath(string fullPath) - { - if (fullPath == null) - { - fullPath = ""; - } - fullPath = fullPath.Replace("\\", "/"); - - if (fullPath == BaseFullPath) - { - return new AssetsPath - { - RelativePath = "" - }; - } - else if (fullPath.StartsWith(BaseFullPath + "/")) - { - return new AssetsPath(fullPath.Substring(BaseFullPath.Length + 1)); - } - else - { - return default(AssetsPath); - } - } - #endregion - - public IEnumerable TraverseDir() - { - if (IsDirectoryExists) - { - yield return this; - - foreach (var child in ChildDirs) - { - foreach (var x in child.TraverseDir()) - { - yield return x; - } - } - } - } - - public IEnumerable ChildDirs - { - get - { - foreach (var x in Directory.GetDirectories(FullPath)) - { - yield return AssetsPath.FromFullpath(x); - } - } - } - - public IEnumerable ChildFiles - { - get - { - foreach (var x in Directory.GetFiles(FullPath)) - { - yield return AssetsPath.FromFullpath(x); - } - } - } - -#if UNITY_EDITOR - string UnityPath => $"Assets/{RelativePath}"; - - public T GetImporter() where T : AssetImporter - { - return AssetImporter.GetAtPath(UnityPath) as T; - } - - public static AssetsPath FromAsset(UnityEngine.Object asset) - { - // skip Assets/ - return new AssetsPath(AssetDatabase.GetAssetPath(asset).Substring(7)); - } - - public void ImportAsset() - { - AssetDatabase.ImportAsset(UnityPath); - } - - public void EnsureFolder() - { - if (RelativePath == null) - { - throw new NotImplementedException(); - } - - if (!string.IsNullOrEmpty(Parent.RelativePath)) - { - Parent.EnsureFolder(); - } - - if (!IsDirectoryExists) - { - var parent = Parent; - // ensure parent - parent.ImportAsset(); - // create - AssetDatabase.CreateFolder( - parent.UnityPath, - Path.GetFileName(RelativePath) - ); - ImportAsset(); - } - } - - public UnityEngine.Object[] GetSubAssets() - { - return AssetDatabase.LoadAllAssetsAtPath(UnityPath); - } - - public void CreateAsset(UnityEngine.Object o) - { - AssetDatabase.CreateAsset(o, UnityPath); - } - - public void AddObjectToAsset(UnityEngine.Object o) - { - AssetDatabase.AddObjectToAsset(o, UnityPath); - } - - public T LoadAsset() where T : UnityEngine.Object - { - return AssetDatabase.LoadAssetAtPath(UnityPath); - } - - public AssetsPath GenerateUniqueAssetPath() - { - return new AssetsPath(AssetDatabase.GenerateUniqueAssetPath(UnityPath)); - } -#endif - } -} diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs b/Assets/External/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs new file mode 100644 index 000000000..85ceb93a9 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs @@ -0,0 +1,111 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public class MeshIntegrationTab + { + bool _modified = false; + protected GltfMeshUtility _meshUtil; + + Splitter _splitter; + ReorderableList _groupList; + ReorderableList _rendererList; + public List _renderers = new List(); + protected int _selected = -1; + protected int Selected + { + set + { + if (_selected == value) + { + return; + } + if (value < 0 || value >= _meshUtil.MeshIntegrationGroups.Count) + { + return; + } + _selected = value; + _renderers.Clear(); + _renderers.AddRange(_meshUtil.MeshIntegrationGroups[_selected].Renderers); + } + } + + public MeshIntegrationTab(EditorWindow editor, GltfMeshUtility meshUtility) + { + _meshUtil = meshUtility; + _splitter = new VerticalSplitter(editor, 200, 50); + + _groupList = new ReorderableList(_meshUtil.MeshIntegrationGroups, typeof(MeshIntegrationGroup)); + _groupList.drawHeaderCallback = (Rect rect) => + { + GUI.Label(rect, "Integration group"); + }; + _groupList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => + { + // Flag / Name + var group = _meshUtil.MeshIntegrationGroups[index]; + + const float LEFT_WIDTH = 92.0f; + var left = rect; + left.width = LEFT_WIDTH; + var right = rect; + right.width -= LEFT_WIDTH; + right.x += LEFT_WIDTH; + + group.IntegrationType = (MeshIntegrationGroup.MeshIntegrationTypes)EditorGUI.EnumPopup(left, group.IntegrationType); + group.Name = EditorGUI.TextField(right, group.Name); + }; + _groupList.onSelectCallback = rl => + { + Selected = (rl.selectedIndices.Count > 0) ? rl.selectedIndices[0] : -1; + }; + + _rendererList = new ReorderableList(_renderers, typeof(Renderer)); + _rendererList.drawHeaderCallback = (Rect rect) => + { + GUI.Label(rect, "Renderer"); + }; + _rendererList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => + { + var r = _renderers[index]; + EditorGUI.ObjectField(rect, r, typeof(Renderer), true); + }; + + // +ボタンが押された時のコールバック + _rendererList.onAddCallback = list => Debug.Log("+ clicked."); + + // -ボタンが押された時のコールバック + _rendererList.onRemoveCallback = list => Debug.Log("- clicked : " + list.index + "."); + } + + public void UpdateMeshIntegrationList(GameObject root) + { + _selected = -1; + _meshUtil.UpdateMeshIntegrationGroups(root); + Selected = 0; + } + + private void ShowGroup(Rect rect) + { + _groupList.DoList(rect); + } + + private void ShowSelected(Rect rect) + { + _rendererList.DoList(rect); + } + + public bool OnGui(Rect rect) + { + _modified = false; + _splitter.OnGUI( + rect, + ShowGroup, + ShowSelected); + return _modified; + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs.meta b/Assets/External/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs.meta new file mode 100644 index 000000000..3ed1e2492 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27b74253f485b4b45a8d2847ec3c2b34 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs b/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs deleted file mode 100644 index b1fc04feb..000000000 --- a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs +++ /dev/null @@ -1,113 +0,0 @@ -using UnityEngine; -using UnityEditor; -using UniGLTF.M17N; -using System.Collections.Generic; - -namespace UniGLTF.MeshUtility -{ - public class MeshProcessDialog : EditorWindow - { - const string TITLE = "Mesh Processing Window"; - MeshProcessDialogTabs _tab; - - private GameObject _exportTarget; - - [SerializeField] - public bool _separateByBlendShape = true; - - [SerializeField] - public SkinnedMeshRenderer _skinnedMeshRenderer = null; - - [SerializeField] - public List _eraseBones; - - private MeshProcessDialogEditor _boneMeshEraserEditor; - private Vector2 _scrollPos = new Vector2(0, 0); - - public static void OpenWindow() - { - var window = - (MeshProcessDialog)EditorWindow.GetWindow(typeof(MeshProcessDialog)); - window.titleContent = new GUIContent(TITLE); - window.Show(); - } - - private void OnEnable() - { - if (!_boneMeshEraserEditor) - { - _boneMeshEraserEditor = (MeshProcessDialogEditor)Editor.CreateEditor(this); - } - } - - private void OnGUI() - { - _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); - EditorGUIUtility.labelWidth = 200; - LanguageGetter.OnGuiSelectLang(); - _exportTarget = (GameObject)EditorGUILayout.ObjectField(MeshProcessingMessages.TARGET_OBJECT.Msg(), _exportTarget, typeof(GameObject), true); - _tab = TabBar.OnGUI(_tab, "LargeButton", GUI.ToolbarButtonSize.Fixed); - - var processed = false; - switch (_tab) - { - case MeshProcessDialogTabs.MeshSeparator: - { - EditorGUILayout.HelpBox(MeshProcessingMessages.MESH_SEPARATOR.Msg(), MessageType.Info); - if (TabMeshSeparator.TryExecutable(_exportTarget, out string msg)) - { - processed = TabMeshSeparator.OnGUI(_exportTarget); - } - else - { - EditorGUILayout.HelpBox(msg, MessageType.Error); - } - break; - } - - case MeshProcessDialogTabs.MeshIntegrator: - { - EditorGUILayout.HelpBox(MeshProcessingMessages.MESH_INTEGRATOR.Msg(), MessageType.Info); - _separateByBlendShape = EditorGUILayout.Toggle(MeshProcessingMessages.MESH_SEPARATOR_BY_BLENDSHAPE.Msg(), _separateByBlendShape); - if (TabMeshIntegrator.TryExecutable(_exportTarget, out string msg)) - { - if (GUILayout.Button("Process", GUILayout.MinWidth(100))) - { - processed = TabMeshIntegrator.Execute(_exportTarget, _separateByBlendShape); - } - } - else - { - EditorGUILayout.HelpBox(msg, MessageType.Error); - } - break; - } - - case MeshProcessDialogTabs.BoneMeshEraser: - { - EditorGUILayout.HelpBox(MeshProcessingMessages.BONE_MESH_ERASER.Msg(), MessageType.Info); - if (_boneMeshEraserEditor) - { - _boneMeshEraserEditor.OnInspectorGUI(); - } - if (TabBoneMeshRemover.TryExecutable(_exportTarget, _skinnedMeshRenderer, out string msg)) - { - processed = TabBoneMeshRemover.OnGUI(_exportTarget, _skinnedMeshRenderer, _eraseBones); - } - else - { - EditorGUILayout.HelpBox(msg, MessageType.Error); - } - break; - } - } - EditorGUILayout.EndScrollView(); - - if (processed) - { - Close(); - GUIUtility.ExitGUI(); - } - } - } -} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogEditor.cs b/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogEditor.cs deleted file mode 100644 index e14659de0..000000000 --- a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogEditor.cs +++ /dev/null @@ -1,43 +0,0 @@ -using UniGLTF.M17N; -using UnityEditor; -using UnityEngine; - -namespace UniGLTF.MeshUtility -{ - /// - /// BoneMeshRemover 向けのエディタ。 - /// - /// SerializedProperty 経由で ユーザー定義 struct のフィールド - /// public List _eraseBones; - /// を EditorGUILayout.PropertyField するための細工である。 - /// - /// SerializedObject は UnityEngine.Object から作成するので、 - /// UnityEngine.Object を継承したクラスのフィールドに ユーザー定義 struct を配置する。 - /// 持ち主の SerializedObject を経由して EditorGUILayout.PropertyField してる。 - /// - [CustomEditor(typeof(MeshProcessDialog), true)] - class MeshProcessDialogEditor : Editor - { - MeshProcessDialog _targetDialog; - SerializedProperty _skinnedMesh; - SerializedProperty _eraseBones; - - void OnEnable() - { - _targetDialog = target as MeshProcessDialog; - if (_targetDialog) - { - _skinnedMesh = serializedObject.FindProperty(nameof(MeshProcessDialog._skinnedMeshRenderer)); - _eraseBones = serializedObject.FindProperty(nameof(MeshProcessDialog._eraseBones)); - } - } - - public override void OnInspectorGUI() - { - serializedObject.Update(); - EditorGUILayout.PropertyField(_skinnedMesh); - EditorGUILayout.PropertyField(_eraseBones); - serializedObject.ApplyModifiedProperties(); - } - } -} diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogTabs.cs b/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogTabs.cs deleted file mode 100644 index 87ad28880..000000000 --- a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessDialogTabs.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace UniGLTF.MeshUtility -{ - public enum MeshProcessDialogTabs - { - MeshSeparator, - MeshIntegrator, - BoneMeshEraser, - } -} diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessingMessages.cs b/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessingMessages.cs deleted file mode 100644 index 965e70846..000000000 --- a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessingMessages.cs +++ /dev/null @@ -1,87 +0,0 @@ -using UniGLTF.M17N; - -namespace UniGLTF.MeshUtility -{ - public enum MeshProcessingMessages - { - [LangMsg(Languages.ja, "ターゲットオブジェクト")] - [LangMsg(Languages.en, "TargetObject")] - TARGET_OBJECT, - - [LangMsg(Languages.ja, @"ターゲットオブジェクト下の SkinnedMeshRenderer にアタッチされたメッシュを、 BlendShape の有無で分割します。 - -* Asset: 新しい Mesh Asset が元と同じフォルダに作成されます。例: Original -> Original_WithBlendShape.mesh & Original_WithoutBlendShape.mesh -* Scene: コピーされたヒエラルキーでは、分割された Mesh は BlendShape のある Mesh で置き換えられて、BlendShape の無い Mesh を使った SkinnedMeshRenderer が追加されます。 -")] - [LangMsg(Languages.en, @"Separate the mesh attached to the SkinnedMeshRenderer under the target object with or without BlendShape. - -* Asset: A new Mesh Asset will be created in the same folder as the original. Example: Original-> Original_WithBlendShape.mesh & Original_WithoutBlendShape.mesh -* Scene: In the copied hierarchy, the split Mesh is replaced with a Mesh that holds the BlendShape, and a SkinnedMeshRenderer with a Mesh without BlendShape is added. -")] - MESH_SEPARATOR, - - - [LangMsg(Languages.ja, "ブレンドシェイプの有無で分割する")] - [LangMsg(Languages.en, "Divide by the presence or absence of `blendshape`")] - MESH_SEPARATOR_BY_BLENDSHAPE, - - [LangMsg(Languages.ja, @"ターゲットオブジェクト下の SkinnedMeshRenderer または MeshFilter にアタッチされたメッシュを統合します。 - -* Asset: Assets/MeshIntegrated.mesh が作成されます(上書きされるので注意してください)。 -* Scene: コピーされたヒエラルキーでは、統合された Mesh は除去されます。新しく MeshIntegrator ノードが追加されます。 -* VRMではBlendShapeClipの統合など追加の処理が必要です。`VRM0-MeshIntegratorWizard` を使ってください。 -")] - [LangMsg(Languages.en, @"Integrates the attached mesh into the SkinnedMeshRenderer or MeshFilter under the target object. - -* Asset: Assets/MeshIntegrated.mesh is created (note that it will be overwritten). -* Scene: In the copied hierarchy, the integrated mesh is removed. A new MeshIntegrator node is added. -* VRM requires additional processing such as BlendShapeClip integration. Use the `VRM0-MeshIntegratorWizard` integration feature. -")] - MESH_INTEGRATOR, - - // [LangMsg(Languages.ja, "静的メッシュを一つに統合します")] - // [LangMsg(Languages.en, "Integrate static meshes into one")] - // STATIC_MESH_INTEGRATOR, - - [LangMsg(Languages.ja, @"指定された SkinnedMeshRenderer から、指定されたボーンに対する Weight を保持する三角形を除去します。 - -* Asset: 元の Mesh と同じフォルダに、三角形を除去した Mesh を保存します。 -* Scene: コピーされたヒエラルキーでは、三角形が除去された Mesh に差し替えられます。 -")] - [LangMsg(Languages.en, @"Removes the triangle that holds the weight for the specified bone from the specified SkinnedMeshRenderer. - -* Assets: Save the mesh with the triangles removed in the same folder as the original mesh. -* Scene: In the copied hierarchy, it will be replaced with a Mesh with the triangles removed. -")] - - BONE_MESH_ERASER, - - [LangMsg(Languages.ja, "Skinned Meshを選んでください")] - [LangMsg(Languages.en, "Select a skinned mesh")] - SELECT_SKINNED_MESH, - - [LangMsg(Languages.ja, "Erase Rootを選んでください")] - [LangMsg(Languages.en, "Select a erase root")] - SELECT_ERASE_ROOT, - - [LangMsg(Languages.ja, "GameObjectを選んでください")] - [LangMsg(Languages.en, "Select a GameObject first")] - NO_GAMEOBJECT_SELECTED, - - [LangMsg(Languages.ja, "GameObjectにスキンメッシュが含まれていません")] - [LangMsg(Languages.en, "No skinned mesh is contained")] - NO_SKINNED_MESH, - - [LangMsg(Languages.ja, "GameObjectに静的メッシュが含まれていません")] - [LangMsg(Languages.en, "No static mesh is contained")] - NO_STATIC_MESH, - - [LangMsg(Languages.ja, "GameObjectにスキンメッシュ・静的メッシュが含まれていません")] - [LangMsg(Languages.en, "Skinned/Static mesh is not contained")] - NO_MESH, - - [LangMsg(Languages.ja, "BlendShapeClipが不整合を起こすので、`VRM0-> MeshIntegrator`を使ってください")] - [LangMsg(Languages.en, "Because BlendShapeClip causes inconsistency , use `VRM0 -> MeshIntegrator` instead")] - VRM_DETECTED, - } -} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessingMessages.cs.meta b/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessingMessages.cs.meta deleted file mode 100644 index e3b56a221..000000000 --- a/Assets/External/UniGLTF/Editor/MeshUtility/MeshProcessingMessages.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 575d573f28f0e4a48a2a6509e69b7f6f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs new file mode 100644 index 000000000..c2feca8ff --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -0,0 +1,325 @@ +using UnityEngine; +using UnityEditor; +using UniGLTF.M17N; +using System.Collections.Generic; +using System.Linq; +using System; + + +namespace UniGLTF.MeshUtility +{ + public class MeshUtilityDialog : EditorWindow + { + public const string MENU_NAME = "glTF MeshUtility"; + protected const string ASSET_SUFFIX = ".mesh.asset"; + public static void OpenWindow() + { + var window = + (MeshUtilityDialog)EditorWindow.GetWindow(typeof(MeshUtilityDialog)); + window.titleContent = new GUIContent(MENU_NAME); + window.Show(); + } + + protected enum Tabs + { + Freeze, + IntegrateSplit, + } + protected Tabs _tab; + protected GameObject _exportTarget; + + GltfMeshUtility _meshUtil; + protected virtual GltfMeshUtility MeshUtility + { + get + { + if (_meshUtil == null) + { + _meshUtil = new GltfMeshUtility(); + } + return _meshUtil; + } + } + MeshIntegrationTab _integrationTab; + protected virtual MeshIntegrationTab MeshIntegration + { + get + { + if (_integrationTab == null) + { + _integrationTab = new MeshIntegrationTab(this, MeshUtility); + } + return _integrationTab; + } + } + + protected List _validations = new List(); + protected virtual void Validate() + { + _validations.Clear(); + if (_exportTarget == null) + { + _validations.Add(Validation.Error("set target GameObject")); + return; + } + } + bool IsValid => !_validations.Any(v => !v.CanExport); + + MeshInfo[] integrationResults; + + Vector2 _scrollPos; + + void OnEnable() + { + } + + protected virtual void DialogMessage() + { + EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_UTILITY.Msg(), MessageType.Info); + } + + private void OnGUI() + { + var modified = false; + EditorGUIUtility.labelWidth = 200; + LanguageGetter.OnGuiSelectLang(); + + DialogMessage(); + + var exportTarget = (GameObject)EditorGUILayout.ObjectField( + MeshUtilityMessages.TARGET_OBJECT.Msg(), + _exportTarget, typeof(GameObject), true); + if (exportTarget != _exportTarget) + { + _exportTarget = exportTarget; + MeshIntegration.UpdateMeshIntegrationList(_exportTarget); + modified = true; + } + if (_exportTarget == null) + { + return; + } + + _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); + + // GameObject or Prefab ? + switch (_exportTarget.GetPrefabType()) + { + case UnityExtensions.PrefabType.PrefabAsset: + EditorGUILayout.HelpBox(MeshUtilityMessages.PREFAB_ASSET.Msg(), MessageType.Warning); + break; + + case UnityExtensions.PrefabType.PrefabInstance: + EditorGUILayout.HelpBox(MeshUtilityMessages.PREFAB_INSTANCE.Msg(), MessageType.Warning); + break; + } + + // tab bar + _tab = TabBar.OnGUI(_tab, "LargeButton", GUI.ToolbarButtonSize.Fixed); + + foreach (var validation in _validations) + { + validation.DrawGUI(); + } + + switch (_tab) + { + case Tabs.Freeze: + { + if (MeshFreezeGui()) + { + modified = true; + } + break; + } + + case Tabs.IntegrateSplit: + { + if (MeshIntegrateGui()) + { + modified = true; + } + break; + } + + // TODO: + // Mesh統合のオプション + // case Tabs.BoneMeshEraser: + // { + // // TODO: FirstPerson 処理と統合する + // EditorGUILayout.HelpBox(MeshUtilityMessages.BONE_MESH_ERASER.Msg(), MessageType.Info); + // // if (_boneMeshEraserEditor) + // // { + // // _boneMeshEraserEditor.OnInspectorGUI(); + // // } + // // if (TabBoneMeshRemover.TryExecutable(_exportTarget, _skinnedMeshRenderer, out string msg)) + // // { + // // processed = TabBoneMeshRemover.OnGUI(_exportTarget, _skinnedMeshRenderer, _eraseBones); + // // } + // // else + // // { + // // EditorGUILayout.HelpBox(msg, MessageType.Error); + // // } + // break; + // } + } + EditorGUILayout.EndScrollView(); + + if (modified) + { + Validate(); + } + + GUI.enabled = IsValid; + var pressed = GUILayout.Button("Process", GUILayout.MinWidth(100)); + GUI.enabled = true; + if (pressed) + { + if (_exportTarget.GetPrefabType() == UnityExtensions.PrefabType.PrefabAsset) + { + /// [prefab] + /// + /// * prefab から instance を作る + /// * instance に対して 焼き付け, 統合, 分離 を実行する + /// * instance のヒエラルキーが改変され、mesh 等のアセットは改変版が作成される(元は変わらない) + /// * instance を asset に保存してから prefab を削除して終了する + /// + UnityPath assetFolder = default; + try + { + assetFolder = PrefabContext.GetOutFolder(_exportTarget); + } + catch (Exception) + { + EditorUtility.DisplayDialog("asset folder", "Target folder must be in the Assets or writable Packages folder", "cancel"); + return; + } + + using (var context = new PrefabContext(_exportTarget, assetFolder)) + { + try + { + // prefab が instantiate されていた場合に + // Mesh統合設定を instantiate に置き換える + var groupCopy = MeshUtility.CopyInstantiate(_exportTarget, context.Instance); + + var (results, created) = MeshUtility.Process(context.Instance, groupCopy); + + // TODO: this should be replaced export and reimport ? + WriteAssets(context.AssetFolder, context.Instance, results); + WritePrefab(context.AssetFolder, context.Instance); + } + catch (Exception ex) + { +#if DEBUG + Debug.LogException(ex, context.Instance); + context.Keep = true; +#endif + } + } + } + else + { + using (var context = new UndoContext("MeshUtility", _exportTarget)) + { + var (results, created) = MeshUtility.Process(_exportTarget, MeshUtility.MeshIntegrationGroups); + MeshUtility.Clear(results); + + foreach (var go in created) + { + // 処理後の mesh をアタッチした Renderer.gameobject + Undo.RegisterCreatedObjectUndo(go, "MeshUtility"); + } + } + } + + // TODO: Show Result ? + _exportTarget = null; + } + } + + Mesh WriteAndReload(Mesh src, string assetPath) + { + Debug.LogFormat("CreateAsset: {0}", assetPath); + AssetDatabase.CreateAsset(src, assetPath); + var unityPath = UnityPath.FromUnityPath(assetPath); + unityPath.ImportAsset(); + var mesh = unityPath.LoadAsset(); + return mesh; + } + + /// + /// Write Mesh + /// + protected virtual void WriteAssets(string assetFolder, GameObject instance, List results) + { + foreach (var result in results) + { + if (result.Integrated != null) + { + var childAssetPath = $"{assetFolder}/{result.Integrated.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; + result.Integrated.IntegratedRenderer.sharedMesh = WriteAndReload( + result.Integrated.IntegratedRenderer.sharedMesh, childAssetPath); + } + if (result.IntegratedNoBlendShape != null) + { + var childAssetPath = $"{assetFolder}/{result.IntegratedNoBlendShape.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; + result.IntegratedNoBlendShape.IntegratedRenderer.sharedMesh = WriteAndReload( + result.IntegratedNoBlendShape.IntegratedRenderer.sharedMesh, childAssetPath); + } + } + + MeshUtility.Clear(results); + } + + /// + /// Write Prefab + /// + protected virtual string WritePrefab(string assetFolder, GameObject instance) + { + var prefabPath = $"{assetFolder}/Integrated.prefab"; + Debug.Log(prefabPath); + PrefabUtility.SaveAsPrefabAsset(instance, prefabPath, out bool success); + if (!success) + { + throw new Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); + } + return prefabPath; + } + + protected bool ToggleIsModified(string label, ref bool value) + { + var newValue = EditorGUILayout.Toggle(label, value); + if (newValue == value) + { + return false; + } + value = newValue; + return true; + } + + bool MeshFreezeGui() + { + return ToggleIsModified("BlendShapeRotationScaling", ref MeshUtility.FreezeBlendShapeRotationAndScaling); + } + + protected virtual bool MeshIntegrateGui() + { + var split = ToggleIsModified("Separate by BlendShape", ref MeshUtility.SplitByBlendShape); + var p = position; + var last = GUILayoutUtility.GetLastRect(); + var y = last.y + last.height; + var rect = new Rect + { + x = last.x, + y = y, + width = p.width, + height = p.height - y + // process button の高さ + - 30 + }; + var mod = MeshIntegration.OnGui(rect); + return split || mod; + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs.meta b/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs.meta new file mode 100644 index 000000000..826fcfe43 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1bdcb928351f92047a91c17c3d629853 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs b/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs new file mode 100644 index 000000000..a516e0c96 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs @@ -0,0 +1,114 @@ +using UniGLTF.M17N; + +namespace UniGLTF.MeshUtility +{ + public enum MeshUtilityMessages + { + [LangMsg(Languages.ja, "ターゲットオブジェクト")] + [LangMsg(Languages.en, "TargetObject")] + TARGET_OBJECT, + + [LangMsg(Languages.ja, @"凍結 > 統合 > 分割 という一連の処理を実行します。 + +[凍結] +- ヒエラルキーの 回転・拡縮を Mesh に焼き付けます。 +- BlendShape の現状を Mesh に焼き付けます。 + +[統合] +- ヒエラルキーに含まれる MeshRenderer と SkinnedMeshRenderer をひとつの SkinnedMeshRenderer に統合します。 + +[分割] +- 統合結果を BlendShape の有無を基準に分割します。 + +[Scene と Prefab] +Scene と Prefab で挙動が異なります。 + +(Scene/Runtime) +- 対象のヒエラルキーを変更します。UNDO可能。 +- Asset の書き出しはしません。Unityを再起動すると、書き出していない Mesh などの Asset が消滅します。 + +(Prefab/Editor) +- 対象の prefab をシーンにコピーして処理を実行し、生成する Asset を指定されたフォルダに書き出します。 +- Asset 書き出し後にコピーを削除します。 +- Undo はありません。 +")] + [LangMsg(Languages.en, @" +Separate the mesh attached to the SkinnedMeshRenderer under the target object with or without BlendShape. + +* Asset: A new Mesh Asset will be created in the same folder as the original. Example: Original-> Original_WithBlendShape.mesh & Original_WithoutBlendShape.mesh +* Scene: In the copied hierarchy, the split Mesh is replaced with a Mesh that holds the BlendShape, and a SkinnedMeshRenderer with a Mesh without BlendShape is added. +")] + MESH_UTILITY, + + [LangMsg(Languages.ja, "ブレンドシェイプの有無で分割する")] + [LangMsg(Languages.en, "Divide by the presence or absence of `blendshape`")] + MESH_SEPARATOR_BY_BLENDSHAPE, + + // [LangMsg(Languages.ja, @"ターゲットオブジェクト下の SkinnedMeshRenderer または MeshFilter にアタッチされたメッシュを統合します。 + + // * Asset: Assets/MeshIntegrated.mesh が作成されます(上書きされるので注意してください)。 + // * Scene: コピーされたヒエラルキーでは、統合された Mesh は除去されます。新しく MeshIntegrator ノードが追加されます。 + // * VRMではBlendShapeClipの統合など追加の処理が必要です。`VRM0-MeshIntegratorWizard` を使ってください。 + // ")] + // [LangMsg(Languages.en, @"Integrates the attached mesh into the SkinnedMeshRenderer or MeshFilter under the target object. + + // * Asset: Assets/MeshIntegrated.mesh is created (note that it will be overwritten). + // * Scene: In the copied hierarchy, the integrated mesh is removed. A new MeshIntegrator node is added. + // * VRM requires additional processing such as BlendShapeClip integration. Use the `VRM0-MeshIntegratorWizard` integration feature. + // ")] + // MESH_INTEGRATOR, + + // // [LangMsg(Languages.ja, "静的メッシュを一つに統合します")] + // // [LangMsg(Languages.en, "Integrate static meshes into one")] + // // STATIC_MESH_INTEGRATOR, + + // [LangMsg(Languages.ja, @"指定された SkinnedMeshRenderer から、指定されたボーンに対する Weight を保持する三角形を除去します。 + + // * Asset: 元の Mesh と同じフォルダに、三角形を除去した Mesh を保存します。 + // * Scene: コピーされたヒエラルキーでは、三角形が除去された Mesh に差し替えられます。 + // ")] + // [LangMsg(Languages.en, @"Removes the triangle that holds the weight for the specified bone from the specified SkinnedMeshRenderer. + + // * Assets: Save the mesh with the triangles removed in the same folder as the original mesh. + // * Scene: In the copied hierarchy, it will be replaced with a Mesh with the triangles removed. + // ")] + + // BONE_MESH_ERASER, + + [LangMsg(Languages.ja, "Skinned Meshを選んでください")] + [LangMsg(Languages.en, "Select a skinned mesh")] + SELECT_SKINNED_MESH, + + // [LangMsg(Languages.ja, "Erase Rootを選んでください")] + // [LangMsg(Languages.en, "Select a erase root")] + // SELECT_ERASE_ROOT, + + [LangMsg(Languages.ja, "GameObjectを選んでください")] + [LangMsg(Languages.en, "Select a GameObject first")] + NO_GAMEOBJECT_SELECTED, + + [LangMsg(Languages.ja, "GameObjectにスキンメッシュが含まれていません")] + [LangMsg(Languages.en, "No skinned mesh is contained")] + NO_SKINNED_MESH, + + // [LangMsg(Languages.ja, "GameObjectに静的メッシュが含まれていません")] + // [LangMsg(Languages.en, "No static mesh is contained")] + // NO_STATIC_MESH, + + [LangMsg(Languages.ja, "GameObjectにスキンメッシュ・静的メッシュが含まれていません")] + [LangMsg(Languages.en, "Skinned/Static mesh is not contained")] + NO_MESH, + + [LangMsg(Languages.ja, "BlendShapeClipが不整合を起こすので、`VRM0-> MeshIntegrator`を使ってください")] + [LangMsg(Languages.en, "Because BlendShapeClip causes inconsistency , use `VRM0 -> MeshIntegrator` instead")] + VRM_DETECTED, + + [LangMsg(Languages.ja, "対象は, Prefab Asset です。実行時に書き出しファイルの指定があります。")] + [LangMsg(Languages.en, "The target is prefab asset. A temporary file is specified during execution.")] + PREFAB_ASSET, + + [LangMsg(Languages.ja, "対象は, Prefab Instance です。Unpack されます。")] + [LangMsg(Languages.en, "The target is prefab asset. A temporary file is specified during execution.")] + PREFAB_INSTANCE, + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs.meta b/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs.meta new file mode 100644 index 000000000..8d37d7253 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: abaf50b8dc367d4448cd5d7c99a4eea3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/PrefabContext.cs b/Assets/External/UniGLTF/Editor/MeshUtility/PrefabContext.cs new file mode 100644 index 000000000..df80d3f3b --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/PrefabContext.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + // Instantiate + class PrefabContext : IDisposable + { + public readonly GameObject Instance; + + readonly UnityPath _assetFolder; + + public bool Keep = false; + + public string AssetFolder => _assetFolder.Value; + + public PrefabContext(GameObject prefab, UnityPath assetFolder) + { + this._assetFolder = assetFolder; + this.Instance = GameObject.Instantiate(prefab); + if (PrefabUtility.IsOutermostPrefabInstanceRoot(this.Instance)) + { + // どういう条件でここに来るかはよくわからない + PrefabUtility.UnpackPrefabInstance(this.Instance, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + } + } + + // - Instance を Asset に書き出す + // - Instance を削除する + public void Dispose() + { + if (Keep) + { + // for debug + return; + } + UnityEngine.Object.DestroyImmediate(Instance); + } + + public static UnityPath GetOutFolder(GameObject _exportTarget) + { + // 出力フォルダを決める + var folder = "Assets"; + var prefab = _exportTarget.GetPrefab(); + if (prefab != null) + { + folder = AssetDatabase.GetAssetPath(prefab); + // Debug.Log(folder); + } + + // 新規で作成されるアセットはすべてこのフォルダの中に作る。上書きチェックはしない + var assetFolder = EditorUtility.SaveFolderPanel("select asset save folder", Path.GetDirectoryName(folder), "Integrated"); + var unityPath = UniGLTF.UnityPath.FromFullpath(assetFolder); + if (!unityPath.IsUnderWritableFolder) + { + throw new Exception("not in asset folder"); + } + return unityPath; + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/PrefabContext.cs.meta b/Assets/External/UniGLTF/Editor/MeshUtility/PrefabContext.cs.meta new file mode 100644 index 000000000..6cc2fba37 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/PrefabContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 948458ced6bcc904781eed04ebe7cd01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/Splitter.cs b/Assets/External/UniGLTF/Editor/MeshUtility/Splitter.cs new file mode 100644 index 000000000..f1fd2e221 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/Splitter.cs @@ -0,0 +1,183 @@ +using UnityEngine; +using UnityEditor; +using System; + +namespace UniGLTF.MeshUtility +{ + [Serializable] + public abstract class Splitter + { + internal enum SplitMode + { + Horizontal, + Vertical, + } + + protected float _value; + + private EditorWindow _window; + private SplitMode _lockMode; + private float _lockValues; + private MouseCursor _mouseCursor; + protected float _barSize; + + private bool _isResize; + private Rect _resizeRect; + private float _ratio = 0.5f; + + private static readonly Color SPLITTER_COLOR = new Color(0, 0, 0, 1.0f); + private static readonly Color SPLITTER_COLOR_FREE = new Color(0.5f, 0.5f, 0.5f, 1.0f); + + internal Splitter(EditorWindow window, float defaultValue, SplitMode lockMode, float minValue, float barSize = 16f) + { + _window = window; + _value = defaultValue; + _lockMode = lockMode; + _lockValues = minValue; + _mouseCursor = lockMode == SplitMode.Vertical ? MouseCursor.ResizeHorizontal : MouseCursor.ResizeVertical; + _barSize = barSize; + } + + protected abstract RectOffset RectOffset(); + + protected abstract Rect MainRect(Rect rect); + + protected abstract Rect SubRect(Rect rect); + + protected abstract Rect BarRect(Rect rect); + + public void OnGUI(Rect rect, Action mainDelegate, Action subDelegate) + { + var current = Event.current; + + mainDelegate(MainRect(rect)); + subDelegate(SubRect(rect)); + + _resizeRect = BarRect(rect); + EditorGUIUtility.AddCursorRect(_resizeRect, _mouseCursor); + + var clampMax = _lockMode == SplitMode.Vertical ? rect.width - _lockValues : rect.height - _lockValues; + var targetSplitterValue = _lockMode == SplitMode.Vertical ? rect.width : rect.height; + + _ratio = _lockMode == SplitMode.Vertical ? _value / rect.width : _value / rect.height; + + if (current.type == EventType.MouseDown && _resizeRect.Contains(current.mousePosition)) + _isResize = true; + if (current.type == EventType.MouseUp) + _isResize = false; + + if (_isResize && current.type == EventType.MouseDrag) + { + var targetValue = _lockMode == SplitMode.Vertical + ? current.mousePosition.x + : current.mousePosition.y; + var diffValue = _lockMode == SplitMode.Vertical ? rect.width : rect.height; + _ratio = targetValue / diffValue; + } + else if (current.type != EventType.Layout && Event.current.type != EventType.Used) + { + _ratio = targetSplitterValue * _ratio / targetSplitterValue; + } + + _value = Mathf.Clamp(targetSplitterValue * _ratio, _lockValues, clampMax); + + EditorGUI.DrawRect(RectOffset().Remove(_resizeRect), SPLITTER_COLOR_FREE); + + if (_isResize) + _window.Repaint(); + } + } + + [Serializable] + public class HorizontalSplitter : Splitter + { + private static readonly RectOffset RECT_OFFSET = new RectOffset(0, 0, 7, 8); + + public HorizontalSplitter(EditorWindow window, float defaultValue, float minValue, float barSize = 16) + : base(window, defaultValue, SplitMode.Horizontal, minValue, barSize) + { + } + + protected override RectOffset RectOffset() + { + return RECT_OFFSET; + } + + protected override Rect MainRect(Rect rect) + { + return new Rect(rect) + { + x = 0, + y = 0, + height = _value, + }; + } + + protected override Rect SubRect(Rect rect) + { + return new Rect(rect) + { + x = 0, + y = _value, + height = rect.height - _value, + }; + } + + protected override Rect BarRect(Rect rect) + { + return new Rect(rect) + { + x = 0, + y = _value - _barSize / 2, + height = _barSize, + }; + } + + } + + [Serializable] + public class VerticalSplitter : Splitter + { + private static readonly RectOffset RECT_OFFSET = new RectOffset(0, 0, 7, 8); + + public VerticalSplitter(EditorWindow window, float defaultValue, float minValue, float barSize = 4) + : base(window, defaultValue, SplitMode.Vertical, minValue, barSize) + { + } + + protected override RectOffset RectOffset() + { + return RECT_OFFSET; + } + + protected override Rect MainRect(Rect rect) + { + return new Rect(rect) + { + x = rect.x + 0, + y = rect.y + 0, + width = _value, + }; + } + + protected override Rect SubRect(Rect rect) + { + return new Rect(rect) + { + x = rect.x + _value, + y = rect.y + 0, + width = rect.width - _value, + }; + } + + protected override Rect BarRect(Rect rect) + { + return new Rect(rect) + { + x = rect.x + _value - _barSize / 2, + y = rect.y + 0, + width = _barSize, + }; + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/Splitter.cs.meta b/Assets/External/UniGLTF/Editor/MeshUtility/Splitter.cs.meta new file mode 100644 index 000000000..4ef6a69d1 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/Splitter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dbb5f5bceb86592499a56fc18011553e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs b/Assets/External/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs index 9e7566e78..ac06f7747 100644 --- a/Assets/External/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs +++ b/Assets/External/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs @@ -17,13 +17,13 @@ namespace UniGLTF.MeshUtility { if (root == null) { - msg = MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(); + msg = MeshUtilityMessages.NO_GAMEOBJECT_SELECTED.Msg(); return false; } if (smr == null) { - msg = MeshProcessingMessages.SELECT_SKINNED_MESH.Msg(); + msg = MeshUtilityMessages.SELECT_SKINNED_MESH.Msg(); return false; } diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs b/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs deleted file mode 100644 index 95c19948b..000000000 --- a/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using UniGLTF.M17N; -using UnityEditor; -using UnityEngine; - -namespace UniGLTF.MeshUtility -{ - public static class TabMeshIntegrator - { - public static bool TryExecutable(GameObject root, out string msg) - { - // check - if (root == null) - { - msg = MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(); - return false; - } - - if (HasVrm(root)) - { - msg = MeshProcessingMessages.VRM_DETECTED.Msg(); - return false; - } - - if (root.GetComponentsInChildren().Length == 0 && root.GetComponentsInChildren().Length == 0) - { - msg = MeshProcessingMessages.NO_MESH.Msg(); - return false; - } - - msg = ""; - return true; - } - - const string VRM_META = "VRMMeta"; - static bool HasVrm(GameObject root) - { - var allComponents = root.GetComponents(typeof(Component)); - foreach (var component in allComponents) - { - if (component == null) continue; - var sourceString = component.ToString(); - if (sourceString.Contains(VRM_META)) - { - return true; - } - } - return false; - } - - const string ASSET_SUFFIX = ".mesh.asset"; - - static string GetMeshWritePath(Mesh mesh) - { - if (!string.IsNullOrEmpty((AssetDatabase.GetAssetPath(mesh)))) - { - var directory = Path.GetDirectoryName(AssetDatabase.GetAssetPath(mesh)).Replace("\\", "/"); - return $"{directory}/{Path.GetFileNameWithoutExtension(mesh.name)}{ASSET_SUFFIX}"; - } - else - { - return $"Assets/{Path.GetFileNameWithoutExtension(mesh.name)}{ASSET_SUFFIX}"; - } - } - - /// GameObject instance in scene or prefab - public static bool Execute(GameObject src, bool onlyBlendShapeRenderers) - { - var results = new List(); - - // instance or prefab => copy - var copy = GameObject.Instantiate(src); - copy.name = copy.name + "_mesh_integration"; - - // integrate - if (onlyBlendShapeRenderers) - { - results.Add(MeshIntegratorUtility.Integrate(copy, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape)); - results.Add(MeshIntegratorUtility.Integrate(copy, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape)); - } - else - { - results.Add(MeshIntegratorUtility.Integrate(copy, onlyBlendShapeRenderers: MeshEnumerateOption.All)); - } - - // replace - MeshIntegratorUtility.ReplaceMeshWithResults(copy, results); - - // write mesh asset. - foreach (var result in results) - { - var mesh = result.IntegratedRenderer.sharedMesh; - var assetPath = GetMeshWritePath(mesh); - Debug.LogFormat("CreateAsset: {0}", assetPath); - AssetDatabase.CreateAsset(mesh, assetPath); - } - - if (src.GetGameObjectType() == GameObjectType.AssetPrefab) - { - // write prefab. - { - var prefabPath = UnityPath.FromAsset(src); - prefabPath = prefabPath.Parent.Child($"{prefabPath.FileNameWithoutExtension}_integrated.prefab"); - Debug.LogFormat("WritePrefab: {0}", prefabPath); - PrefabUtility.SaveAsPrefabAsset(copy, prefabPath.Value); - } - - // destroy copy in scene. - GameObject.DestroyImmediate(copy); - } - else - { - // do nothing. keep copy. - } - - return true; - } - } -} diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta b/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta deleted file mode 100644 index 5c60a51fe..000000000 --- a/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 65a227dcf3cb5f34085bd6829894fb64 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs b/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs index 3dab965b2..992681a57 100644 --- a/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs +++ b/Assets/External/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs @@ -24,13 +24,13 @@ namespace UniGLTF.MeshUtility { if (root == null) { - msg = MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(); + msg = MeshUtilityMessages.NO_GAMEOBJECT_SELECTED.Msg(); return false; } if (root.GetComponentsInChildren().Length == 0) { - msg = MeshProcessingMessages.NO_SKINNED_MESH.Msg(); + msg = MeshUtilityMessages.NO_SKINNED_MESH.Msg(); return false; } @@ -104,7 +104,7 @@ namespace UniGLTF.MeshUtility /// /// /// (Mesh 分割前, Mesh BlendShape有り、Mesh BlendShape無し)のリストを返す - private static List<(Mesh Src, Mesh With, Mesh Without)> SeparationProcessing(GameObject go) + public static List<(Mesh Src, Mesh With, Mesh Without)> SeparationProcessing(GameObject go) { var list = new List<(Mesh Src, Mesh With, Mesh Without)>(); var skinnedMeshRenderers = go.GetComponentsInChildren(); diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/UndoContext.cs b/Assets/External/UniGLTF/Editor/MeshUtility/UndoContext.cs new file mode 100644 index 000000000..eaf53f0f8 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/UndoContext.cs @@ -0,0 +1,27 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + // Instantiate + class UndoContext : IDisposable + { + public UndoContext(string undoName, GameObject go) + { + Undo.RegisterFullObjectHierarchyUndo(go, undoName); + if (go.GetPrefabType() == UnityExtensions.PrefabType.PrefabInstance) + { + PrefabUtility.UnpackPrefabInstance(go, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + } + } + + public void Dispose() + { + // 特に何もしない + // Undo すると元に戻ってしまう + + // TODO: あれば一時オブジェクトの破棄 + } + } +} diff --git a/Assets/External/UniGLTF/Editor/MeshUtility/UndoContext.cs.meta b/Assets/External/UniGLTF/Editor/MeshUtility/UndoContext.cs.meta new file mode 100644 index 000000000..bf4202411 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/MeshUtility/UndoContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5019966789c0e094a8f58fc2734c9a35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/TopMenu.cs b/Assets/External/UniGLTF/Editor/TopMenu.cs index f41b442e6..cb98950bf 100644 --- a/Assets/External/UniGLTF/Editor/TopMenu.cs +++ b/Assets/External/UniGLTF/Editor/TopMenu.cs @@ -1,7 +1,7 @@ -using System.IO; using UnityEditor; using UnityEngine; + namespace UniGLTF { /// @@ -10,31 +10,50 @@ namespace UniGLTF public static class TopMenu { private const string UserGltfMenuPrefix = UniGLTFVersion.MENU; - private const string UserMeshUtilityPrefix = UniGLTFVersion.MENU + "/Mesh Utility"; private const string DevelopmentMenuPrefix = UniGLTFVersion.MENU + "/Development"; + [MenuItem(UserGltfMenuPrefix + "/Version: " + UniGLTFVersion.UNIGLTF_VERSION, validate = true)] private static bool ShowVersionValidation() => false; - [MenuItem(UserGltfMenuPrefix + "/Version: " + UniGLTFVersion.UNIGLTF_VERSION, priority = 0)] private static void ShowVersion() { } - [MenuItem(UserGltfMenuPrefix + "/Export to GLB", priority = 1)] - private static void ExportGameObjectToGltf() => TopMenuImplementation.ExportGameObjectToGltfFile(); - [MenuItem(UserGltfMenuPrefix + "/Import from GLTF (*.gltf|*.glb|*.zip)", priority = 2)] - private static void ImportGltfFile() => TopMenuImplementation.ImportGltfFileToGameObject(); + [MenuItem(UserGltfMenuPrefix + "/" + GltfExportWindow.MENU_NAME, priority = 1)] + private static void ExportGameObjectToGltf() => GltfExportWindow.ExportGameObjectToGltfFile(); - [MenuItem(UserMeshUtilityPrefix + "/MeshProcessing Wizard", priority = 10)] - private static void OpenMeshProcessingWindow() => MeshUtility.MeshProcessDialog.OpenWindow(); + + [MenuItem(UserGltfMenuPrefix + "/" + GltfImportMenu.MENU_NAME, priority = 2)] + private static void ImportGltfFile() => GltfImportMenu.ImportGltfFileToGameObject(); + + + [MenuItem(UserGltfMenuPrefix + "/" + MeshUtility.MeshUtilityDialog.MENU_NAME, priority = 31)] + private static void OpenMeshProcessingWindow() => MeshUtility.MeshUtilityDialog.OpenWindow(); #if VRM_DEVELOP - [MenuItem(DevelopmentMenuPrefix + "/Generate Serialization Code", priority = 20)] - private static void GenerateSerializationCode() => TopMenuImplementation.GenerateSerializationCode(); + [MenuItem(DevelopmentMenuPrefix + "/Generate Serialization Code", priority = 51)] + private static void GenerateSerializationCode() + { + SerializerGenerator.GenerateSerializer(); + DeserializerGenerator.GenerateSerializer(); + } - - [MenuItem(DevelopmentMenuPrefix + "/Generate UniJSON ConcreteCast", priority = 21)] + [MenuItem(DevelopmentMenuPrefix + "/Generate UniJSON ConcreteCast", priority = 52)] private static void GenerateUniJsonConcreteCastCode() => UniJSON.ConcreteCast.GenerateGenericCast(); + + [MenuItem("GameObject/CheckPrefabType", false, 53)] + [MenuItem("Assets/CheckPrefabType", false, 53)] + private static void CheckPrefabType() + { + if (Selection.activeObject is GameObject go) + { + Debug.Log(go.GetPrefabType()); + } + else + { + Debug.Log(Selection.activeContext.GetType()); + } + } #endif } } diff --git a/Assets/External/UniGLTF/Editor/TopMenuImplementation.cs.meta b/Assets/External/UniGLTF/Editor/TopMenuImplementation.cs.meta deleted file mode 100644 index 1024de137..000000000 --- a/Assets/External/UniGLTF/Editor/TopMenuImplementation.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 173b43f1467d4054921297a5c2e55d05 -timeCreated: 1638961414 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/UniGLTF.Editor.asmdef b/Assets/External/UniGLTF/Editor/UniGLTF.Editor.asmdef index 7d8718ed4..8298fa473 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF.Editor.asmdef +++ b/Assets/External/UniGLTF/Editor/UniGLTF.Editor.asmdef @@ -1,9 +1,11 @@ { "name": "UniGLTF.Editor", + "rootNamespace": "", "references": [ "GUID:8d76e605759c3f64a957d63ef96ada7c", "GUID:da3e51d19d51a544fa14d43fee843098", - "GUID:7da8a75dcade2144aab699032d7d7987" + "GUID:7da8a75dcade2144aab699032d7d7987", + "GUID:1cd941934d098654fa21a13f28346412" ], "includePlatforms": [ "Editor" diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs index 7564ea58a..eb67943ea 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs @@ -144,33 +144,32 @@ namespace UniGLTF // // Create and Other Buttons { - // errors - GUILayout.BeginVertical(); - // GUILayout.FlexibleSpace(); - + // errors + using (new GUILayout.VerticalScope()) { - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUI.enabled = State.Validations.All(x => x.CanExport); - - if (GUILayout.Button("Export", GUILayout.MinWidth(100))) + // GUILayout.FlexibleSpace(); { - var path = SaveFileDialog.GetPath(SaveTitle, SaveName, SaveExtensions); - if (!string.IsNullOrEmpty(path)) + using (new GUILayout.HorizontalScope()) { - ExportPath(path); - // close - Close(); - GUIUtility.ExitGUI(); + GUILayout.FlexibleSpace(); + GUI.enabled = State.Validations.All(x => x.CanExport); + + if (GUILayout.Button("Export", GUILayout.MinWidth(100))) + { + var path = SaveFileDialog.GetPath(SaveTitle, SaveName, SaveExtensions); + if (!string.IsNullOrEmpty(path)) + { + ExportPath(path); + // close + Close(); + GUIUtility.ExitGUI(); + } + } + GUI.enabled = true; } } - GUI.enabled = true; - - GUILayout.EndHorizontal(); } - GUILayout.EndVertical(); } - GUILayout.Space(8); } diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogState.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogState.cs index b592a438a..dfced70da 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogState.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogState.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; +using VRMShaders; namespace UniGLTF { @@ -58,9 +59,10 @@ namespace UniGLTF } if (m_root.IsPrefab) { -#if VRM_DEVELOP - Debug.Log($"PrefabUtility.UnloadPrefabContents({m_root.GameObject})"); -#endif + if (Symbols.VRM_DEVELOP) + { + Debug.Log($"PrefabUtility.UnloadPrefabContents({m_root.GameObject})"); + } PrefabUtility.UnloadPrefabContents(m_root.GameObject); } m_root = (value, isPrefab); diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs index 4e0387bcc..1f6b4b32e 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs @@ -9,7 +9,13 @@ namespace UniGLTF { public class GltfExportWindow : ExportDialogBase { - + public const string MENU_NAME = "Export glTF..."; + public static void ExportGameObjectToGltfFile() + { + var window = (GltfExportWindow)GltfExportWindow.GetWindow(typeof(GltfExportWindow)); + window.titleContent = new GUIContent(MENU_NAME); + window.Show(); + } enum Tabs { diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/InternalTPose.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/InternalTPose.cs index 703068203..3536ef1a1 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/InternalTPose.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/InternalTPose.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using UniGLTF.M17N; +using UniGLTF.Utils; using UnityEngine; namespace UniGLTF @@ -149,7 +150,7 @@ namespace UniGLTF var existingMappings = new Dictionary(); var animator = go.GetComponent(); - foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) + foreach (var bone in CachedEnum.GetValues()) { if (bone == HumanBodyBones.LastBone) { diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/M17N.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/M17N.cs index 69e8c2fb7..aebb5d545 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/M17N.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/M17N.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using UniGLTF.Utils; using UnityEditor; namespace UniGLTF.M17N @@ -28,7 +29,7 @@ namespace UniGLTF.M17N } } - public static class MsgCache where T : Enum + public static class MsgCache where T : struct, Enum { static Dictionary> s_cache = new Dictionary>(); @@ -57,7 +58,7 @@ namespace UniGLTF.M17N map = new Dictionary(); var t = typeof(T); - foreach (T value in Enum.GetValues(t)) + foreach (T value in CachedEnum.GetValues()) { var match = GetAttribute(value, language); // Attribute。無かったら enum の ToString @@ -107,7 +108,7 @@ namespace UniGLTF.M17N } } - public static string Msg(this T key) where T : Enum + public static string Msg(this T key) where T : struct, Enum { return MsgCache.Get(Lang, key); } diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs index b1c9f32a5..da47b75ec 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/MaterialValidator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace UniGLTF @@ -30,43 +31,23 @@ namespace UniGLTF { public virtual string GetGltfMaterialTypeFromUnityShaderName(string shaderName) { - if (shaderName == "Standard") + if (BuiltInGltfMaterialExporter.SupportedShaderNames.Contains(shaderName)) { - return "pbr"; - } - if (MaterialExporter.IsUnlit(shaderName)) - { - return "unlit"; + return "gltf"; } + return null; } public virtual IEnumerable<(string propertyName, Texture texture)> EnumerateTextureProperties(Material m) { - // main color - yield return (MaterialExporter.COLOR_TEXTURE_PROP, m.GetTexture(MaterialExporter.COLOR_TEXTURE_PROP)); - - if (GetGltfMaterialTypeFromUnityShaderName(m.shader.name) == "unlit") + foreach (var texturePropertyName in m.GetTexturePropertyNames()) { - yield break; - } - - // PBR - if (m.HasProperty(MaterialExporter.METALLIC_TEX_PROP)) - { - yield return (MaterialExporter.METALLIC_TEX_PROP, m.GetTexture(MaterialExporter.METALLIC_TEX_PROP)); - } - if (m.HasProperty(MaterialExporter.NORMAL_TEX_PROP)) - { - yield return (MaterialExporter.NORMAL_TEX_PROP, m.GetTexture(MaterialExporter.NORMAL_TEX_PROP)); - } - if (m.HasProperty(MaterialExporter.EMISSION_TEX_PROP)) - { - yield return (MaterialExporter.EMISSION_TEX_PROP, m.GetTexture(MaterialExporter.EMISSION_TEX_PROP)); - } - if (m.HasProperty(MaterialExporter.OCCLUSION_TEX_PROP)) - { - yield return (MaterialExporter.OCCLUSION_TEX_PROP, m.GetTexture(MaterialExporter.OCCLUSION_TEX_PROP)); + var tex = m.GetTexture(texturePropertyName); + if (tex != null) + { + yield return (texturePropertyName, tex); + } } } } diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs index 5ab9e55a8..91061f642 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs @@ -48,10 +48,25 @@ namespace UniGLTF public enum Messages { + [LangMsg(Languages.en, "Materials with fewer sub-meshes")] + [LangMsg(Languages.ja, "サブメッシュ数より少ないマテリアル")] MATERIALS_LESS_THAN_SUBMESH_COUNT, + + [LangMsg(Languages.en, "Materials with more sub-meshes")] + [LangMsg(Languages.ja, "サブメッシュ数より多いマテリアル")] MATERIALS_GREATER_THAN_SUBMESH_COUNT, + + [LangMsg(Languages.en, "Renderer has null in material")] + [LangMsg(Languages.ja, "レンダラーの material に null があります")] MATERIALS_CONTAINS_NULL, + + [LangMsg(Languages.en, "A Shader that cannot be exported")] + [LangMsg(Languages.ja, "エクスポート非対応のシェーダーです")] UNKNOWN_SHADER, + + [LangMsg(Languages.en, "Meshes containing BlendShapes with multiple Frames cannot be exported")] + [LangMsg(Languages.ja, "複数Frameを持つBlendShapeを含むMeshはエクスポートできません")] + MULTIFRAME_BLENDSHAPE, } public IEnumerable Validate(GameObject ExportRoot) @@ -75,9 +90,25 @@ namespace UniGLTF if (info.Materials.Take(info.Mesh.subMeshCount).Any(x => x == null)) { // material に null が含まれる(unity で magenta になっているはず) - yield return Validation.Error($"{info.Renderers}: {Messages.MATERIALS_CONTAINS_NULL.Msg()}"); + yield return Validation.Error(Messages.MATERIALS_CONTAINS_NULL.Msg(), ValidationContext.Create(info.Renderers[0].Item1)); } } + + // blendShapeFrame + var shapeCount = info.Mesh.blendShapeCount; + var multiFrameShapes = new List(); + for (int i = 0; i < shapeCount; ++i) + { + if (info.Mesh.GetBlendShapeFrameCount(i) > 1) + { + multiFrameShapes.Add($"[{i}]({info.Mesh.GetBlendShapeName(i)})"); + } + } + if (multiFrameShapes.Count > 0) + { + var names = String.Join(", ", multiFrameShapes); + yield return Validation.Error($"{names}: {Messages.MULTIFRAME_BLENDSHAPE.Msg()}", ValidationContext.Create(info.Renderers[0].Item1)); + } } foreach (var m in Meshes.GetUniqueMaterials()) diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs index b2ed86a7b..9ac7cea24 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs @@ -7,6 +7,18 @@ namespace UniGLTF public static class SaveFileDialog { static string m_lastExportDir; + + static string extensionString(string[] extensions) + { +#if UNITY_EDITOR_OSX + // in OSX multi extension cause exception. + // https://github.com/vrm-c/UniVRM/issues/1837 + return extensions.Length > 0 ? extensions[0] : ""; +#else + return string.Join(",", extensions); +#endif + } + public static string GetPath(string title, string name, params string[] extensions) { string directory = m_lastExportDir; @@ -15,12 +27,29 @@ namespace UniGLTF directory = Directory.GetParent(Application.dataPath).ToString(); } - var path = EditorUtility.SaveFilePanel(title, directory, name, string.Join(",", extensions)); + var path = EditorUtility.SaveFilePanel(title, directory, name, extensionString(extensions)); if (!string.IsNullOrEmpty(path)) { m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); } return path; } + + public static string GetDir(string title, string dir = null) + { + string directory = string.IsNullOrEmpty(dir) ? m_lastExportDir : dir; + if (string.IsNullOrEmpty(directory)) + { + directory = Directory.GetParent(Application.dataPath).ToString(); + } + + var path = EditorUtility.SaveFolderPanel(title, directory, null); + if (!string.IsNullOrEmpty(path)) + { + m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); + } + + return path; + } } } diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/TabBar.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/TabBar.cs index 8bea7db02..09ffd2264 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/TabBar.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ExportDialog/TabBar.cs @@ -5,7 +5,6 @@ using UnityEngine; namespace UniGLTF.MeshUtility { - public static class TabBar { /// diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/Gizmo/BoneInfo.cs b/Assets/External/UniGLTF/Editor/UniGLTF/Gizmo/BoneInfo.cs index 09cb3a798..c29c62ff1 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/Gizmo/BoneInfo.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/Gizmo/BoneInfo.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using UniGLTF.Utils; using UnityEngine; namespace UniGLTF @@ -129,7 +130,7 @@ namespace UniGLTF throw new ArgumentException("not humanoid"); } - var validBones = ((HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones))) + var validBones = CachedEnum.GetValues() .Where(x => x != HumanBodyBones.LastBone) .ToArray(); var headSelectedBones = new HashSet(); diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporter.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporter.cs index 3c952fc04..640d3ef87 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporter.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporter.cs @@ -7,7 +7,15 @@ using UnityEditor.Experimental.AssetImporters; namespace UniGLTF { - [ScriptedImporter(1, "glb")] +#if UNITY_2020_2_OR_NEWER +#if UNIGLTF_DISABLE_DEFAULT_GLB_IMPORTER + [ScriptedImporter(1, null, overrideExts: new[] { "glb" })] +#else + [ScriptedImporter(1, new[] { "glb" })] +#endif +#else + [ScriptedImporter(1, new[] { "glb" })] +#endif public class GlbScriptedImporter : GltfScriptedImporterBase { public override void OnImportAsset(AssetImportContext ctx) diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporterEditor.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporterEditor.cs index d10352f22..7e249821c 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporterEditor.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporterEditor.cs @@ -32,7 +32,7 @@ namespace UniGLTF } m_data = new GlbFileParser(m_importer.assetPath).Parse(); - var materialGenerator = new GltfMaterialDescriptorGenerator(); + var materialGenerator = new BuiltInGltfMaterialDescriptorGenerator(); var materialKeys = m_data.GLTF.materials.Select((_, i) => materialGenerator.Get(m_data, i).SubAssetKey); var textureKeys = new GltfTextureDescriptorGenerator(m_data).Get().GetEnumerable().Select(x => x.SubAssetKey); m_materialEditor = new RemapEditorMaterial(materialKeys.Concat(textureKeys), GetEditorMap, SetEditorMap); diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs index 39d8914ba..d99f3f1e0 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs @@ -7,7 +7,15 @@ using UnityEditor.Experimental.AssetImporters; namespace UniGLTF { - [ScriptedImporter(1, "gltf")] +#if UNITY_2020_2_OR_NEWER +#if UNIGLTF_DISABLE_DEFAULT_GLTF_IMPORTER + [ScriptedImporter(1, null, overrideExts: new[] { "gltf" })] +#else + [ScriptedImporter(1, new[] { "gltf" })] +#endif +#else + [ScriptedImporter(1, new[] { "gltf" })] +#endif public class GltfScriptedImporter : GltfScriptedImporterBase { public override void OnImportAsset(AssetImportContext ctx) diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterBase.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterBase.cs index 12bb984ce..2da25c315 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterBase.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterBase.cs @@ -26,7 +26,7 @@ namespace UniGLTF { if (m_renderPipeline == UniGLTF.RenderPipelineTypes.UniversalRenderPipeline) { - if (Shader.Find(UniGLTF.GltfPbrUrpMaterialImporter.ShaderName) == null) + if (Shader.Find(UniGLTF.UrpGltfPbrMaterialImporter.ShaderName) == null) { Debug.LogWarning("URP is not installed. Force to BuiltinRenderPipeline"); m_renderPipeline = UniGLTF.RenderPipelineTypes.BuiltinRenderPipeline; @@ -39,10 +39,10 @@ namespace UniGLTF switch (renderPipeline) { case RenderPipelineTypes.BuiltinRenderPipeline: - return new GltfMaterialDescriptorGenerator(); + return new BuiltInGltfMaterialDescriptorGenerator(); case RenderPipelineTypes.UniversalRenderPipeline: - return new GltfUrpMaterialDescriptorGenerator(); + return new UrpGltfMaterialDescriptorGenerator(); default: throw new System.NotImplementedException(); @@ -57,9 +57,10 @@ namespace UniGLTF /// protected static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, Axes reverseAxis, RenderPipelineTypes renderPipeline) { -#if VRM_DEVELOP - Debug.Log("OnImportAsset to " + scriptedImporter.assetPath); -#endif + if (Symbols.VRM_DEVELOP) + { + Debug.Log("OnImportAsset to " + scriptedImporter.assetPath); + } // // Import(create unity objects) diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditor.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditor.cs index 77efc711d..dd15468a5 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditor.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporterEditor.cs @@ -30,7 +30,7 @@ namespace UniGLTF } m_data = new AutoGltfFileParser(m_importer.assetPath).Parse(); - var materialGenerator = new GltfMaterialDescriptorGenerator(); + var materialGenerator = new BuiltInGltfMaterialDescriptorGenerator(); var materialKeys = m_data.GLTF.materials.Select((_, i) => materialGenerator.Get(m_data, i).SubAssetKey); var textureKeys = new GltfTextureDescriptorGenerator(m_data).Get().GetEnumerable().Select(x => x.SubAssetKey); m_materialEditor = new RemapEditorMaterial(materialKeys.Concat(textureKeys), GetEditorMap, SetEditorMap); diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/RemapScriptedImporterEditorBase.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/RemapScriptedImporterEditorBase.cs index 77a6d9694..bf4803adf 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/RemapScriptedImporterEditorBase.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/RemapScriptedImporterEditorBase.cs @@ -44,9 +44,24 @@ namespace UniGLTF m_editMap.AddRange(value.Select(kv => new RemapEditorBase.SubAssetPair(kv.Key, kv.Value))); } +#if UNITY_2022_2_OR_NEWER /// /// Revert /// + public override void DiscardChanges() + { + m_editMap.Clear(); + + base.DiscardChanges(); + } +#endif + + /// + /// Revert + /// +#if UNITY_2022_2_OR_NEWER + [System.Obsolete] +#endif protected override void ResetValues() { m_editMap.Clear(); diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/TextureExtractor.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/TextureExtractor.cs index 3824ccd7d..8077b58b3 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/TextureExtractor.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/TextureExtractor.cs @@ -92,9 +92,6 @@ namespace UniGLTF { // remap var externalObject = targetPath.LoadAsset(); -#if VRM_DEVELOP - // Debug.Log($"remap: {targetPath} => {externalObject}"); -#endif if (externalObject != null) { addRemap(key, externalObject); diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/ZipArchivedGltfScriptedImporterEditor.cs b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/ZipArchivedGltfScriptedImporterEditor.cs index e80c62a16..f37085ce5 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/ZipArchivedGltfScriptedImporterEditor.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/ScriptedImporter/ZipArchivedGltfScriptedImporterEditor.cs @@ -26,7 +26,7 @@ namespace UniGLTF m_importer = target as ZipArchivedGltfScriptedImporter; m_data = new AutoGltfFileParser(m_importer.assetPath).Parse(); - var materialGenerator = new GltfMaterialDescriptorGenerator(); + var materialGenerator = new BuiltInGltfMaterialDescriptorGenerator(); var materialKeys = m_data.GLTF.materials.Select((_, i) => materialGenerator.Get(m_data, i).SubAssetKey); var textureKeys = new GltfTextureDescriptorGenerator(m_data).Get().GetEnumerable().Select(x => x.SubAssetKey); m_materialEditor = new RemapEditorMaterial(materialKeys.Concat(textureKeys), GetEditorMap, SetEditorMap); diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/FieldSerializationInfo.cs b/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/FieldSerializationInfo.cs index 9e9c86ffa..49bf61af4 100644 --- a/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/FieldSerializationInfo.cs +++ b/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/FieldSerializationInfo.cs @@ -75,6 +75,10 @@ namespace UniGLTF return new StringKeyDictionarySerialization(t, GetSerialization(t.GetGenericArguments()[1], path, attr, prefix)); } + else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + return new NullableSerialization(t.GetGenericArguments()[0], path, attr, prefix); + } // GetCollectionType(fi.FieldType, out suffix, out t); if (t == typeof(sbyte)) diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/NullableSerialization.cs b/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/NullableSerialization.cs new file mode 100644 index 000000000..d129bbec1 --- /dev/null +++ b/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/NullableSerialization.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; + +namespace UniGLTF +{ + public class NullableSerialization : IValueSerialization + { + public NullableSerialization(Type t, string path, JsonSchemaAttribute attr, string prefix) + { + if (t != typeof(int)) + { + throw new NotImplementedException(); + } + } + + public Type ValueType => typeof(Int32); + public bool IsInline => true; + + public string CreateSerializationCondition(string argName, JsonSchemaAttribute t) + { + return $"{argName}.HasValue"; + } + + public string GenerateSerializerCall(string callName, string argName) + { + return $"f.Value({argName}.Value)"; + } + + public void GenerateSerializer(StreamWriter writer, string callName) + { + throw new NotImplementedException(); + } + + public string GenerateDeserializerCall(string callName, string argName) + { + return argName + ".GetInt32()"; + } + + public void GenerateDeserializer(StreamWriter writer, string callName) + { + throw new NotImplementedException(); + } + } +} diff --git a/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/NullableSerialization.cs.meta b/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/NullableSerialization.cs.meta new file mode 100644 index 000000000..f589dab5f --- /dev/null +++ b/Assets/External/UniGLTF/Editor/UniGLTF/Serialization/NullableSerialization.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 84c7673bb94af9f419ca9839910fd8be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseClipEditor.cs b/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseClipEditor.cs deleted file mode 100644 index 1b4692a00..000000000 --- a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseClipEditor.cs +++ /dev/null @@ -1,90 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System.Collections.Generic; - -namespace UniHumanoid -{ - [CustomEditor(typeof(HumanPoseClip))] - public class HumanPoseClipEditor : Editor - { - private Animator m_animator; - private HumanPoseHandler m_poseHandler; - private Animator m_lastAnimator; - - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - - var clip = target as HumanPoseClip; - if (clip == null) return; - - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Pose Application", EditorStyles.boldLabel); - - m_animator = EditorGUILayout.ObjectField("Target Animator", m_animator, typeof(Animator), true) as Animator; - - // Recreate pose handler if animator changed - if (m_animator != m_lastAnimator) - { - m_poseHandler = null; - m_lastAnimator = m_animator; - } - - if (m_animator != null && m_animator.isHuman) - { - if (GUILayout.Button("Apply Pose")) - { - ApplyPose(clip); - } - - if (GUILayout.Button("Capture Current Pose")) - { - CapturePose(clip); - } - } - else if (m_animator != null) - { - EditorGUILayout.HelpBox("Selected animator must be humanoid!", MessageType.Warning); - } - } - - private void ApplyPose(HumanPoseClip clip) - { - if (m_animator == null || !m_animator.isHuman) return; - - // Create pose handler if needed - if (m_poseHandler == null) - { - m_poseHandler = new HumanPoseHandler(m_animator.avatar, m_animator.transform); - } - - var pose = clip.GetPose(); - m_poseHandler.SetHumanPose(ref pose); - - // Record undo - Undo.RegisterFullObjectHierarchyUndo(m_animator.gameObject, "Apply Pose"); - - // Ensure the changes are visible in the scene view - EditorUtility.SetDirty(m_animator.gameObject); - SceneView.RepaintAll(); - } - - private void CapturePose(HumanPoseClip clip) - { - if (m_animator == null || !m_animator.isHuman) return; - - // Create pose handler if needed - if (m_poseHandler == null) - { - m_poseHandler = new HumanPoseHandler(m_animator.avatar, m_animator.transform); - } - - var pose = new HumanPose(); - m_poseHandler.GetHumanPose(ref pose); - - Undo.RecordObject(clip, "Capture Pose"); - clip.ApplyPose(ref pose); - EditorUtility.SetDirty(clip); - } - } -} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseClipEditor.cs.meta b/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseClipEditor.cs.meta deleted file mode 100644 index d6770f297..000000000 --- a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseClipEditor.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c5041805cdf64014b9b1a045832c07bd \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseWindow.cs b/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseWindow.cs deleted file mode 100644 index 9789741c9..000000000 --- a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseWindow.cs +++ /dev/null @@ -1,259 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System.Collections.Generic; -using System.Linq; - -namespace UniHumanoid -{ - public class HumanPoseWindow : EditorWindow - { - private Vector2 scrollPosition; - private Animator targetAnimator; - private HumanPoseHandler poseHandler; - private Animator lastAnimator; - private List poseClips = new List(); - private string searchText = ""; - private bool showCreateNew = false; - private string newPoseName = "New Pose"; - - [MenuItem("Window/Animation/Human Pose Manager")] - static void ShowWindow() - { - var window = GetWindow("Human Pose Manager"); - window.Show(); - } - - void OnEnable() - { - RefreshPoseList(); - } - - void RefreshPoseList() - { - // Find all HumanPoseClip assets in the project - string[] guids = AssetDatabase.FindAssets("t:HumanPoseClip"); - poseClips = guids - .Select(guid => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid))) - .Where(clip => clip != null) - .ToList(); - } - - void OnGUI() - { - EditorGUILayout.Space(10); - - // Target Animator Selection - using (new EditorGUILayout.HorizontalScope()) - { - targetAnimator = (Animator)EditorGUILayout.ObjectField("Target Humanoid", targetAnimator, typeof(Animator), true); - - if (targetAnimator != lastAnimator) - { - poseHandler = null; - lastAnimator = targetAnimator; - } - } - - if (targetAnimator != null && !targetAnimator.isHuman) - { - EditorGUILayout.HelpBox("Selected animator must be humanoid!", MessageType.Warning); - return; - } - - EditorGUILayout.Space(10); - - // Search Bar - using (new EditorGUILayout.HorizontalScope()) - { - searchText = EditorGUILayout.TextField("Search", searchText, EditorStyles.toolbarSearchField); - if (GUILayout.Button("Refresh", GUILayout.Width(60))) - { - RefreshPoseList(); - } - } - - EditorGUILayout.Space(10); - - // Create New Pose Section - using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) - { - showCreateNew = EditorGUILayout.Foldout(showCreateNew, "Create New Pose", true); - if (showCreateNew) - { - EditorGUI.indentLevel++; - newPoseName = EditorGUILayout.TextField("Pose Name", newPoseName); - - using (new EditorGUI.DisabledScope(targetAnimator == null || !targetAnimator.isHuman)) - { - if (GUILayout.Button("Capture Current Pose")) - { - CreateNewPoseFromCurrent(); - } - } - EditorGUI.indentLevel--; - } - } - - EditorGUILayout.Space(10); - - // Pose List - EditorGUILayout.LabelField("Available Poses", EditorStyles.boldLabel); - scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); - - var filteredPoses = poseClips - .Where(p => string.IsNullOrEmpty(searchText) || - p.name.ToLower().Contains(searchText.ToLower())) - .ToList(); - - foreach (var pose in filteredPoses) - { - DrawPoseEntry(pose); - } - - EditorGUILayout.EndScrollView(); - } - - void DrawPoseEntry(HumanPoseClip pose) - { - using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) - { - // Pose name and buttons - using (new EditorGUILayout.HorizontalScope()) - { - EditorGUILayout.LabelField(pose.name, EditorStyles.boldLabel); - - using (new EditorGUI.DisabledScope(targetAnimator == null || !targetAnimator.isHuman)) - { - if (GUILayout.Button("Apply", GUILayout.Width(60))) - { - ApplyPose(pose); - } - if (GUILayout.Button("Update", GUILayout.Width(60))) - { - UpdatePose(pose); - } - } - - if (GUILayout.Button("Select", GUILayout.Width(60))) - { - Selection.activeObject = pose; - } - } - } - } - - void CreateNewPoseFromCurrent() - { - if (targetAnimator == null || !targetAnimator.isHuman) return; - - // Ensure animator is properly initialized - PrepareAnimator(); - - // Create new pose asset - var newPose = CreateInstance(); - - // Capture current pose - CreatePoseHandler(); - - var pose = new HumanPose(); - poseHandler.GetHumanPose(ref pose); - newPose.ApplyPose(ref pose); - - // Save asset - string path = EditorUtility.SaveFilePanel( - "Save Pose Asset", - "Assets", - newPoseName + ".asset", - "asset" - ); - - if (string.IsNullOrEmpty(path)) return; - - path = FileUtil.GetProjectRelativePath(path); - AssetDatabase.CreateAsset(newPose, path); - AssetDatabase.SaveAssets(); - - RefreshPoseList(); - newPoseName = "New Pose"; - } - - void ApplyPose(HumanPoseClip clip) - { - if (targetAnimator == null || !targetAnimator.isHuman) return; - - // Ensure animator is properly initialized - PrepareAnimator(); - - // Record undo before applying - Undo.RegisterFullObjectHierarchyUndo(targetAnimator.gameObject, "Apply Pose"); - - CreatePoseHandler(); - - var pose = clip.GetPose(); - - // Apply the pose - poseHandler.SetHumanPose(ref pose); - - // Force update the animator - ForceAnimatorUpdate(); - - EditorUtility.SetDirty(targetAnimator.gameObject); - SceneView.RepaintAll(); - } - - void UpdatePose(HumanPoseClip clip) - { - if (targetAnimator == null || !targetAnimator.isHuman) return; - - // Ensure animator is properly initialized - PrepareAnimator(); - - CreatePoseHandler(); - - var pose = new HumanPose(); - poseHandler.GetHumanPose(ref pose); - - Undo.RecordObject(clip, "Update Pose"); - clip.ApplyPose(ref pose); - EditorUtility.SetDirty(clip); - AssetDatabase.SaveAssets(); - } - - void PrepareAnimator() - { - if (targetAnimator == null) return; - - // Ensure the animator is enabled and active - targetAnimator.enabled = true; - - // Force animator to update - targetAnimator.Rebind(); - targetAnimator.Update(0); - } - - void CreatePoseHandler() - { - if (poseHandler == null) - { - poseHandler = new HumanPoseHandler(targetAnimator.avatar, targetAnimator.transform); - } - } - - void ForceAnimatorUpdate() - { - if (targetAnimator == null) return; - - // Force the animator to update its internal state - targetAnimator.Update(0); - - // Also update the transform hierarchy - targetAnimator.transform.hasChanged = true; - - // Force a physics update if needed - if (targetAnimator.updateMode == AnimatorUpdateMode.Fixed) - { - targetAnimator.Update(Time.fixedDeltaTime); - } - } - } -} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseWindow.cs.meta b/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseWindow.cs.meta deleted file mode 100644 index 56268420a..000000000 --- a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanPoseWindow.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: faaa48d88f3baf94b89ba5238f36d967 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanoidEditor.cs b/Assets/External/UniGLTF/Editor/UniHumanoid/HumanoidEditor.cs index 886ce1257..e1191d6d4 100644 --- a/Assets/External/UniGLTF/Editor/UniHumanoid/HumanoidEditor.cs +++ b/Assets/External/UniGLTF/Editor/UniHumanoid/HumanoidEditor.cs @@ -173,7 +173,35 @@ namespace UniHumanoid } } - static void HorizontalFields(string label, params SerializedProperty[] props) + static int? HorizontalFields(string label, params SerializedProperty[] props) + { + int? changed = default; + try + { + EditorGUILayout.BeginHorizontal(); + + GUILayout.Label(label, GUILayout.Width(LABEL_WIDTH)); + GUILayout.FlexibleSpace(); + + for (int i = 0; i < props.Length; ++i) + { + var prop = props[i]; + var prev = prop.objectReferenceValue; + EditorGUILayout.PropertyField(prop, GUIContent.none, true, GUILayout.MinWidth(100)); + if (prev != prop.objectReferenceValue) + { + changed = i; + } + } + } + finally + { + EditorGUILayout.EndHorizontal(); + } + return changed; + } + + static void FingerFields(string label, params SerializedProperty[] props) { try { @@ -182,9 +210,15 @@ namespace UniHumanoid GUILayout.Label(label, GUILayout.Width(LABEL_WIDTH)); GUILayout.FlexibleSpace(); - foreach (var prop in props) + for (int i = 0; i < props.Length; ++i) { + var prop = props[i]; + var prev = prop.objectReferenceValue; EditorGUILayout.PropertyField(prop, GUIContent.none, true, GUILayout.MinWidth(100)); + if (prev != prop.objectReferenceValue) + { + SetFirstChildrenIfNull(prop, props.Skip(1).ToArray()); + } } } finally @@ -197,7 +231,7 @@ namespace UniHumanoid static bool s_legFold; static bool s_armFold; static bool s_fingerFold; - static string GetDialogDir(UnityEngine.Object obj) + static string GetDialogDir(GameObject obj) { var prefab = PrefabUtility.GetCorrespondingObjectFromSource(obj); if (prefab == null) @@ -221,6 +255,62 @@ namespace UniHumanoid return true; } + static void SetFirstChildrenIfNull(SerializedProperty start, params SerializedProperty[] children) + { + var parent = start.objectReferenceValue as Transform; + if (parent == null) + { + return; + } + var current = parent; + foreach (var prop in children) + { + if (prop.objectReferenceValue != null) + { + // already assigned. exit + break; + } + + if (current.childCount == 0) + { + // no child. exit + break; + } + current = current.GetChild(0); + prop.objectReferenceValue = current; + } + } + + static bool PropFieldIsUpdated(SerializedProperty prop) + { + var prev = prop.objectReferenceValue; + EditorGUILayout.PropertyField(prop); + return prop.objectReferenceValue != prev; + } + + static void LRProps(params (string Name, SerializedProperty L, SerializedProperty R)[] fields) + { + + for (int i = 0; i < fields.Length; ++i) + { + var field = fields[i]; + var changed = HorizontalFields(field.Name, field.L, field.R); + if (i == 0) + { + if (changed == 0) + { + // left + SetFirstChildrenIfNull(field.L, fields.Skip(1).Select(x => x.L).ToArray()); + } + else if (changed == 1) + { + // right + SetFirstChildrenIfNull(field.R, fields.Skip(1).Select(x => x.R).ToArray()); + } + } + } + } + public override void OnInspectorGUI() { foreach (var validation in m_target.Validate()) @@ -236,10 +326,16 @@ namespace UniHumanoid s_spineFold = EditorGUILayout.Foldout(s_spineFold, "Body"); if (s_spineFold) { - EditorGUILayout.PropertyField(m_Spine); + if (PropFieldIsUpdated(m_Spine)) + { + SetFirstChildrenIfNull(m_Spine, m_Chest, m_UpperChest); + } EditorGUILayout.PropertyField(m_Chest); EditorGUILayout.PropertyField(m_UpperChest); - EditorGUILayout.PropertyField(m_Neck); + if (PropFieldIsUpdated(m_Neck)) + { + SetFirstChildrenIfNull(m_Neck, m_Head); + } EditorGUILayout.PropertyField(m_Head); EditorGUILayout.PropertyField(m_Jaw); HorizontalFields("Eye", m_LeftEye, m_RightEye); @@ -248,34 +344,38 @@ namespace UniHumanoid s_legFold = EditorGUILayout.Foldout(s_legFold, "Leg"); if (s_legFold) { - HorizontalFields("UpperLeg", m_LeftUpperLeg, m_RightUpperLeg); - HorizontalFields("LowerLeg", m_LeftLowerLeg, m_RightLowerLeg); - HorizontalFields("Foot", m_LeftFoot, m_RightFoot); - HorizontalFields("Toes", m_LeftToes, m_RightToes); + LRProps( + ("UpperLeg", m_LeftUpperLeg, m_RightUpperLeg), + ("LowerLeg", m_LeftLowerLeg, m_RightLowerLeg), + ("Foot", m_LeftFoot, m_RightFoot), + ("Toes", m_LeftToes, m_RightToes) + ); } s_armFold = EditorGUILayout.Foldout(s_armFold, "Arm"); if (s_armFold) { - HorizontalFields("Shoulder", m_LeftShoulder, m_RightShoulder); - HorizontalFields("UpperArm", m_LeftUpperArm, m_RightUpperArm); - HorizontalFields("LowerArm", m_LeftLowerArm, m_RightLowerArm); - HorizontalFields("Hand", m_LeftHand, m_RightHand); + LRProps( + ("Shoulder", m_LeftShoulder, m_RightShoulder), + ("UpperArm", m_LeftUpperArm, m_RightUpperArm), + ("LowerArm", m_LeftLowerArm, m_RightLowerArm), + ("Hand", m_LeftHand, m_RightHand) + ); } s_fingerFold = EditorGUILayout.Foldout(s_fingerFold, "Finger"); if (s_fingerFold) { - HorizontalFields("LeftThumb", m_LeftThumbProximal, m_LeftThumbIntermediate, m_LeftThumbDistal); - HorizontalFields("LeftIndex", m_LeftIndexProximal, m_LeftIndexIntermediate, m_LeftIndexDistal); - HorizontalFields("LeftMiddle", m_LeftMiddleProximal, m_LeftMiddleIntermediate, m_LeftMiddleDistal); - HorizontalFields("LeftRing", m_LeftRingProximal, m_LeftRingIntermediate, m_LeftRingDistal); - HorizontalFields("LeftLittle", m_LeftLittleProximal, m_LeftLittleIntermediate, m_LeftLittleDistal); - HorizontalFields("RightThumb", m_RightThumbProximal, m_RightThumbIntermediate, m_RightThumbDistal); - HorizontalFields("RightIndex", m_RightIndexProximal, m_RightIndexIntermediate, m_RightIndexDistal); - HorizontalFields("RightMiddle", m_RightMiddleProximal, m_RightMiddleIntermediate, m_RightMiddleDistal); - HorizontalFields("RightRing", m_RightRingProximal, m_RightRingIntermediate, m_RightRingDistal); - HorizontalFields("RightLittle", m_RightLittleProximal, m_RightLittleIntermediate, m_RightLittleDistal); + FingerFields("LeftThumb", m_LeftThumbProximal, m_LeftThumbIntermediate, m_LeftThumbDistal); + FingerFields("LeftIndex", m_LeftIndexProximal, m_LeftIndexIntermediate, m_LeftIndexDistal); + FingerFields("LeftMiddle", m_LeftMiddleProximal, m_LeftMiddleIntermediate, m_LeftMiddleDistal); + FingerFields("LeftRing", m_LeftRingProximal, m_LeftRingIntermediate, m_LeftRingDistal); + FingerFields("LeftLittle", m_LeftLittleProximal, m_LeftLittleIntermediate, m_LeftLittleDistal); + FingerFields("RightThumb", m_RightThumbProximal, m_RightThumbIntermediate, m_RightThumbDistal); + FingerFields("RightIndex", m_RightIndexProximal, m_RightIndexIntermediate, m_RightIndexDistal); + FingerFields("RightMiddle", m_RightMiddleProximal, m_RightMiddleIntermediate, m_RightMiddleDistal); + FingerFields("RightRing", m_RightRingProximal, m_RightRingIntermediate, m_RightRingDistal); + FingerFields("RightLittle", m_RightLittleProximal, m_RightLittleIntermediate, m_RightLittleDistal); } serializedObject.ApplyModifiedProperties(); @@ -285,7 +385,7 @@ namespace UniHumanoid { var path = EditorUtility.SaveFilePanel( "Save avatar", - GetDialogDir(m_target), + GetDialogDir(m_target.gameObject), string.Format("{0}.avatar.asset", serializedObject.targetObject.name), "asset"); if (TryGetAssetPath(path, out string unityPath)) diff --git a/Assets/External/UniGLTF/Runtime/AssemblyInfo.cs b/Assets/External/UniGLTF/Runtime/AssemblyInfo.cs new file mode 100644 index 000000000..67e2c8115 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/AssemblyInfo.cs @@ -0,0 +1,5 @@ +#if UNITY_EDITOR +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("UniGLTF.Tests")] +#endif \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/AssemblyInfo.cs.meta b/Assets/External/UniGLTF/Runtime/AssemblyInfo.cs.meta new file mode 100644 index 000000000..97a459ad4 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7aed15fa830416246b0c408322cd4099 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/Extensions/ColorConversionExtensions.cs b/Assets/External/UniGLTF/Runtime/Extensions/ColorConversionExtensions.cs index 1e6daabe7..e78ab1556 100644 --- a/Assets/External/UniGLTF/Runtime/Extensions/ColorConversionExtensions.cs +++ b/Assets/External/UniGLTF/Runtime/Extensions/ColorConversionExtensions.cs @@ -40,6 +40,11 @@ namespace UniGLTF return new Color(src[0], src[1], src[2], 1f).ConvertColorSpace(srcColorSpace, dstColorSpace); } + public static Color ToColor3(this Vector3 src, ColorSpace srcColorSpace, ColorSpace dstColorSpace) + { + return new Color(src.x, src.y, src.z).ConvertColorSpace(srcColorSpace, dstColorSpace); + } + private static Color ConvertColorSpace(this Color srcColor, ColorSpace srcColorSpace, ColorSpace dstColorSpace) { // Need pattern matching :( diff --git a/Assets/External/UniGLTF/Runtime/Extensions/IndexExtensions.cs b/Assets/External/UniGLTF/Runtime/Extensions/IndexExtensions.cs new file mode 100644 index 000000000..7599e5b95 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Extensions/IndexExtensions.cs @@ -0,0 +1,19 @@ +namespace UniGLTF +{ + public static class IndexExtensions + { + public static bool HasValidIndex(this int? self) + { + if (!self.HasValue) + { + return false; + } + if (self.Value < 0) + { + // 古いモデルで index の無効値に -1 を使っている場合がある + return false; + } + return true; + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/Extensions/IndexExtensions.cs.meta b/Assets/External/UniGLTF/Runtime/Extensions/IndexExtensions.cs.meta new file mode 100644 index 000000000..c34759131 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Extensions/IndexExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0989fbb259f59149ab310387ea69835 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/Extensions/StringExtensions.cs b/Assets/External/UniGLTF/Runtime/Extensions/StringExtensions.cs index 635e1e0d2..f06bba77b 100644 --- a/Assets/External/UniGLTF/Runtime/Extensions/StringExtensions.cs +++ b/Assets/External/UniGLTF/Runtime/Extensions/StringExtensions.cs @@ -70,6 +70,13 @@ namespace UniGLTF { path = path.Replace(x, '+'); } + + if (path.StartsWith('.')) + path = '+' + path; + + if (path == "") + path = "(empty)"; + return path; } diff --git a/Assets/External/UniGLTF/Runtime/Extensions/UnityExtensions.cs b/Assets/External/UniGLTF/Runtime/Extensions/UnityExtensions.cs index 58321b08f..17bbb3bba 100644 --- a/Assets/External/UniGLTF/Runtime/Extensions/UnityExtensions.cs +++ b/Assets/External/UniGLTF/Runtime/Extensions/UnityExtensions.cs @@ -449,5 +449,40 @@ namespace UniGLTF } return true; } + + public enum PrefabType + { + PrefabAsset, + PrefabInstance, + NotPrefab, + } + + /// + /// Scene と Prefab で挙動をスイッチする。 + /// + /// - Scene: ヒエラルキーを操作する。Asset の 書き出しはしない。UNDO はする。TODO: 明示的な Asset の書き出し。 + /// - Prefab: 対象をコピーして処理する。Undo は実装しない。結果を Asset として書き出し、処理後にコピーは削除する。 + /// + /// + public static PrefabType GetPrefabType(this GameObject go) + { + if (go == null) + { + throw new ArgumentNullException(); + } + if (!go.scene.IsValid()) + { + return PrefabType.PrefabAsset; + } + +#if UNITY_EDITOR + if (PrefabUtility.GetOutermostPrefabInstanceRoot(go) != null) + { + return PrefabType.PrefabInstance; + } +#endif + + return PrefabType.NotPrefab; + } } -} +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/Extensions/glTFExtensions.cs b/Assets/External/UniGLTF/Runtime/Extensions/glTFExtensions.cs index fce7d3dca..29a9ec703 100644 --- a/Assets/External/UniGLTF/Runtime/Extensions/glTFExtensions.cs +++ b/Assets/External/UniGLTF/Runtime/Extensions/glTFExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using UnityEngine; using System.IO; using UniJSON; +using System.Collections.Concurrent; namespace UniGLTF { @@ -25,6 +26,7 @@ namespace UniGLTF { typeof(Vector2), new ComponentVec(glComponentType.FLOAT, 2) }, { typeof(Vector3), new ComponentVec(glComponentType.FLOAT, 3) }, { typeof(Vector4), new ComponentVec(glComponentType.FLOAT, 4) }, + { typeof(Quaternion), new ComponentVec(glComponentType.FLOAT, 4) }, { typeof(UShort4), new ComponentVec(glComponentType.UNSIGNED_SHORT, 4) }, { typeof(Matrix4x4), new ComponentVec(glComponentType.FLOAT, 16) }, { typeof(Color), new ComponentVec(glComponentType.FLOAT, 4) }, @@ -135,7 +137,7 @@ namespace UniGLTF } } - static Dictionary<(string, int, int), bool> s_cache = new Dictionary<(string, int, int), bool>(); + static ConcurrentDictionary<(string, int, int), bool> s_cache = new ConcurrentDictionary<(string, int, int), bool>(); public static bool IsGeneratedUniGLTFAndOlder(this glTF gltf, int major, int minor) { @@ -149,7 +151,7 @@ namespace UniGLTF } var result = IsGeneratedUniGLTFAndOlderThan(gltf.asset.generator, major, minor); - s_cache.Add(key, result); + s_cache[key] = result; return result; } } diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/BlendShapeReport.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/BlendShapeReport.cs new file mode 100644 index 000000000..61ce87f14 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/BlendShapeReport.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + class BlendShapeReport + { + string m_name; + int m_count; + struct BlendShapeStat + { + public int Index; + public string Name; + public int VertexCount; + public int NormalCount; + public int TangentCount; + + public override string ToString() + { + return string.Format("[{0}]{1}: {2}, {3}, {4}\n", Index, Name, VertexCount, NormalCount, TangentCount); + } + } + List m_stats = new List(); + public int Count + { + get { return m_stats.Count; } + } + public BlendShapeReport(Mesh mesh) + { + m_name = mesh.name; + m_count = mesh.vertexCount; + } + public void SetCount(int index, string name, int v, int n, int t) + { + m_stats.Add(new BlendShapeStat + { + Index = index, + Name = name, + VertexCount = v, + NormalCount = n, + TangentCount = t, + }); + } + public override string ToString() + { + return String.Format("NormalizeSkinnedMesh: {0}({1}verts)\n{2}", + m_name, + m_count, + String.Join("", m_stats.Select(x => x.ToString()).ToArray())); + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/BlendShapeReport.cs.meta b/Assets/External/UniGLTF/Runtime/MeshUtility/BlendShapeReport.cs.meta new file mode 100644 index 000000000..491cfc2c5 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/BlendShapeReport.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ab7e7ef8eaac5b4593a6a1102c15012 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/BoneMeshEraser.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/BoneMeshEraser.cs index fd34c2584..17794ca78 100644 --- a/Assets/External/UniGLTF/Runtime/MeshUtility/BoneMeshEraser.cs +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/BoneMeshEraser.cs @@ -56,7 +56,7 @@ namespace UniGLTF.MeshUtility { var bw = bws[a]; - var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3); + var eb = AreBoneContains(exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3); if (bw.weight0 > 0 && eb.Bone0) continue; if (bw.weight1 > 0 && eb.Bone1) continue; if (bw.weight2 > 0 && eb.Bone2) continue; @@ -64,7 +64,7 @@ namespace UniGLTF.MeshUtility } { var bw = bws[b]; - var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3); + var eb = AreBoneContains(exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3); if (bw.weight0 > 0 && eb.Bone0) continue; if (bw.weight1 > 0 && eb.Bone1) continue; if (bw.weight2 > 0 && eb.Bone2) continue; @@ -72,7 +72,7 @@ namespace UniGLTF.MeshUtility } { var bw = bws[c]; - var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3); + var eb = AreBoneContains(exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3); if (bw.weight0 > 0 && eb.Bone0) continue; if (bw.weight1 > 0 && eb.Bone1) continue; if (bw.weight2 > 0 && eb.Bone2) continue; @@ -88,7 +88,7 @@ namespace UniGLTF.MeshUtility return count; } - private static ExcludeBoneIndex AreBoneContains(ref int[] exclude, int boneIndex0, int boneIndex1, + private static ExcludeBoneIndex AreBoneContains(in int[] exclude, int boneIndex0, int boneIndex1, int boneIndex2, int boneIndex3) { var b0 = false; @@ -131,7 +131,7 @@ namespace UniGLTF.MeshUtility /// /// /// - public static int[] GetExcludedIndices(int[] indices, BoneWeight[] boneWeights, int[] eraseBoneIndices) + static int[] GetExcludedIndices(int[] indices, BoneWeight[] boneWeights, int[] eraseBoneIndices) { var count = ExcludeTriangles(indices, boneWeights, eraseBoneIndices); var dst = new int[count]; diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index 3fe17d482..191d3f522 100644 --- a/Assets/External/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using UniGLTF.Utils; using UnityEngine; @@ -8,507 +9,98 @@ namespace UniGLTF.MeshUtility { public static class BoneNormalizer { - public delegate Avatar CreateAvatarFunc(GameObject original, GameObject normalized, Dictionary boneMap); - - static (GameObject, Dictionary) NormalizeHierarchy(GameObject go, CreateAvatarFunc createAvatar) + private static MeshAttachInfo CreateMeshInfo(Transform src) { - var boneMap = new Dictionary(); - - // - // 回転・スケールの無いヒエラルキーをコピーする - // - var normalized = new GameObject(go.name + "(normalized)"); - normalized.transform.position = go.transform.position; - CopyAndBuild(go.transform, normalized.transform, boneMap); - - // - // 新しいヒエラルキーからAvatarを作る - // + // SkinnedMeshRenderer + var smr = src.GetComponent(); + var mesh = MeshFreezer.NormalizeSkinnedMesh(smr); + if (mesh != null) { - var animator = normalized.AddComponent(); - var avatar = createAvatar(go, normalized, boneMap); - avatar.name = go.name + ".normalized"; - animator.avatar = avatar; + return new MeshAttachInfo + { + Mesh = mesh, + Materials = smr.sharedMaterials, + Bones = smr.bones, + RootBone = smr.rootBone, + }; } - return (normalized, boneMap); - } - - /// - /// 回転とスケールを除去したヒエラルキーをコピーする。 - /// - /// - /// - static void CopyAndBuild(Transform src, Transform dst, Dictionary boneMap) - { - boneMap[src] = dst; - - foreach (Transform child in src) + // MeshRenderer + var mr = src.GetComponent(); + if (mr != null) { - if (child.gameObject.activeSelf) + var dstMesh = MeshFreezer.NormalizeNoneSkinnedMesh(mr, true); + if (dstMesh != null) { - var dstChild = new GameObject(child.name); - dstChild.transform.SetParent(dst); - dstChild.transform.position = child.position; // copy position only - - CopyAndBuild(child, dstChild.transform, boneMap); + return new MeshAttachInfo + { + Mesh = dstMesh, + Materials = mr.sharedMaterials, + }; } } + + return default; } - class BlendShapeReport - { - string m_name; - int m_count; - struct BlendShapeStat - { - public int Index; - public string Name; - public int VertexCount; - public int NormalCount; - public int TangentCount; - public override string ToString() + /// + /// 各レンダラー(SkinnedMeshRenderer と MeshRenderer)にアタッチされた sharedMesh に対して + /// 回転とスケールを除去し、BlendShape の現状を焼き付けた版を作成する(まだ、アタッチしない) + /// + public static Dictionary NormalizeHierarchyFreezeMesh( + GameObject go) + { + var result = new Dictionary(); + foreach (var src in go.transform.Traverse()) + { + var info = CreateMeshInfo(src); + if (info != null) { - return string.Format("[{0}]{1}: {2}, {3}, {4}\n", Index, Name, VertexCount, NormalCount, TangentCount); + result.Add(src, info); } } - List m_stats = new List(); - public int Count - { - get { return m_stats.Count; } - } - public BlendShapeReport(Mesh mesh) - { - m_name = mesh.name; - m_count = mesh.vertexCount; - } - public void SetCount(int index, string name, int v, int n, int t) - { - m_stats.Add(new BlendShapeStat - { - Index = index, - Name = name, - VertexCount = v, - NormalCount = n, - TangentCount = t, - }); - } - public override string ToString() - { - return String.Format("NormalizeSkinnedMesh: {0}({1}verts)\n{2}", - m_name, - m_count, - String.Join("", m_stats.Select(x => x.ToString()).ToArray())); - } + return result; } - /// - /// index が 有効であれば、setter に weight を渡す。無効であれば setter に 0 を渡す。 - /// - /// - /// - /// - /// - static bool CopyOrDropWeight(int[] indexMap, int srcIndex, float weight, Action setter) + public static void Replace(GameObject go, Dictionary meshMap, + bool FreezeRotation, bool FreezeScaling) { - if (srcIndex < 0 || srcIndex >= indexMap.Length) - { - // ありえるかどうかわからないが BoneWeight.boneIndexN に変な値が入っている. - setter(0, 0); - return false; - } + var boneMap = go.transform.Traverse().ToDictionary(x => x, x => new EuclideanTransform(x.rotation, x.position)); - var dstIndex = indexMap[srcIndex]; - if (dstIndex != -1) + // first, update hierarchy + foreach (var src in go.transform.Traverse()) { - // 有効なindex。weightをコピーする - setter(dstIndex, weight); - return true; - } - else - { - // 無効なindex。0でクリアする - setter(0, 0); - return false; - } - } - - /// - /// BoneWeight[] src から新しいボーンウェイトを作成する。 - /// - /// 変更前のBoneWeight[] - /// 新旧のボーンの対応表。新しい方は無効なボーンが除去されてnullの部分がある - /// 変更前のボーン配列 - /// 変更後のボーン配列。除去されたボーンがある場合、変更前より短い - /// - public static BoneWeight[] MapBoneWeight(BoneWeight[] src, - Dictionary boneMap, - Transform[] srcBones, - Transform[] dstBones - ) - { - // 処理前後の index の対応表を作成する - var indexMap = new int[srcBones.Length]; - for (int i = 0; i < srcBones.Length; ++i) - { - var srcBone = srcBones[i]; - if (srcBone == null) + var tr = boneMap[src]; + if (FreezeScaling) { - // 元のボーンが無い - indexMap[i] = -1; - Debug.LogWarningFormat("bones[{0}] is null", i); + src.localScale = Vector3.one; } else { - if (boneMap.TryGetValue(srcBone, out Transform dstBone)) - { - // 対応するボーンが存在する - var dstIndex = Array.IndexOf(dstBones, dstBone); - if (dstIndex == -1) - { - // ありえない。バグ - throw new Exception(); - } - indexMap[i] = dstIndex; - } - else - { - // 先のボーンが無い - indexMap[i] = -1; - Debug.LogWarningFormat("{0} is removed", srcBone.name); - } - } - } - - // 新しいBoneWeightを作成する - var newBoneWeights = new BoneWeight[src.Length]; - for (int i = 0; i < src.Length; ++i) - { - BoneWeight srcBoneWeight = src[i]; - - // 0 - CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex0, srcBoneWeight.weight0, (newIndex, newWeight) => - { - newBoneWeights[i].boneIndex0 = newIndex; - newBoneWeights[i].weight0 = newWeight; - }); - // 1 - CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex1, srcBoneWeight.weight1, (newIndex, newWeight) => - { - newBoneWeights[i].boneIndex1 = newIndex; - newBoneWeights[i].weight1 = newWeight; - }); - // 2 - CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex2, srcBoneWeight.weight2, (newIndex, newWeight) => - { - newBoneWeights[i].boneIndex2 = newIndex; - newBoneWeights[i].weight2 = newWeight; - }); - // 3 - CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex3, srcBoneWeight.weight3, (newIndex, newWeight) => - { - newBoneWeights[i].boneIndex3 = newIndex; - newBoneWeights[i].weight3 = newWeight; - }); - } - - return newBoneWeights; - } - - /// - /// srcのSkinnedMeshRendererを正規化して、dstにアタッチする - /// - /// 正規化前のSkinnedMeshRendererのTransform - /// 正規化後のSkinnedMeshRendererのTransform - /// 正規化前のボーンから正規化後のボーンを得る - static void NormalizeSkinnedMesh(Transform src, Transform dst, Dictionary boneMap) - { - var srcRenderer = src.GetComponent(); - if (srcRenderer == null - || !srcRenderer.enabled - || srcRenderer.sharedMesh == null - || srcRenderer.sharedMesh.vertexCount == 0) - { - // 有効なSkinnedMeshRendererが無かった - return; - } - - var srcMesh = srcRenderer.sharedMesh; - var originalSrcMesh = srcMesh; - - // 元の Transform[] bones から、無効なboneを取り除いて前に詰めた配列を作る - var dstBones = srcRenderer.bones - .Where(x => x != null && boneMap.ContainsKey(x)) - .Select(x => boneMap[x]) - .ToArray(); - - var hasBoneWeight = srcRenderer.bones != null && srcRenderer.bones.Length > 0; - if (!hasBoneWeight) - { - // Before bake, bind no weight bones - //Debug.LogFormat("no weight: {0}", srcMesh.name); - - srcMesh = srcMesh.Copy(true); - var bw = new BoneWeight - { - boneIndex0 = 0, - boneIndex1 = 0, - boneIndex2 = 0, - boneIndex3 = 0, - weight0 = 1.0f, - weight1 = 0.0f, - weight2 = 0.0f, - weight3 = 0.0f, - }; - srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray(); - srcMesh.bindposes = new Matrix4x4[] { Matrix4x4.identity }; - - srcRenderer.rootBone = srcRenderer.transform; - dstBones = new[] { boneMap[srcRenderer.transform] }; - srcRenderer.bones = new[] { srcRenderer.transform }; - srcRenderer.sharedMesh = srcMesh; - } - - // BakeMesh - var mesh = srcMesh.Copy(false); - mesh.name = srcMesh.name + ".baked"; - srcRenderer.BakeMesh(mesh); - - var blendShapeValues = new Dictionary(); - for (int i = 0; i < srcMesh.blendShapeCount; i++) - { - var val = srcRenderer.GetBlendShapeWeight(i); - if (val > 0) blendShapeValues.Add(i, val); - } - - // 新しい骨格のボーンウェイトを作成する - mesh.boneWeights = MapBoneWeight(srcMesh.boneWeights, boneMap, srcRenderer.bones, dstBones); - - // recalc bindposes - mesh.bindposes = dstBones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); - - //var m = src.localToWorldMatrix; // include scaling - var m = default(Matrix4x4); - m.SetTRS(Vector3.zero, src.rotation, Vector3.one); // rotation only - mesh.ApplyMatrix(m); - - // - // BlendShapes - // - - // clear blendShape always - var backcup = new List(); - for (int i = 0; i < srcMesh.blendShapeCount; ++i) - { - backcup.Add(srcRenderer.GetBlendShapeWeight(i)); - srcRenderer.SetBlendShapeWeight(i, 0); - } - - var meshVertices = mesh.vertices; - var meshNormals = mesh.normals; -#if VRM_NORMALIZE_BLENDSHAPE_TANGENT - var meshTangents = mesh.tangents.Select(x => (Vector3)x).ToArray(); -#endif - - var originalBlendShapePositions = new Vector3[meshVertices.Length]; - var originalBlendShapeNormals = new Vector3[meshVertices.Length]; - var originalBlendShapeTangents = new Vector3[meshVertices.Length]; - - var report = new BlendShapeReport(srcMesh); - var blendShapeMesh = new Mesh(); - for (int i = 0; i < srcMesh.blendShapeCount; ++i) - { - // check blendShape - srcRenderer.sharedMesh.GetBlendShapeFrameVertices(i, 0, originalBlendShapePositions, originalBlendShapeNormals, originalBlendShapeTangents); - var hasVertices = originalBlendShapePositions.Count(x => x != Vector3.zero); - var hasNormals = originalBlendShapeNormals.Count(x => x != Vector3.zero); -#if VRM_NORMALIZE_BLENDSHAPE_TANGENT - var hasTangents = originalBlendShapeTangents.Count(x => x != Vector3.zero); -#else - var hasTangents = 0; -#endif - var name = srcMesh.GetBlendShapeName(i); - if (string.IsNullOrEmpty(name)) - { - name = String.Format("{0}", i); + throw new NotImplementedException(); } - report.SetCount(i, name, hasVertices, hasNormals, hasTangents); - - srcRenderer.SetBlendShapeWeight(i, 100.0f); - srcRenderer.BakeMesh(blendShapeMesh); - if (blendShapeMesh.vertices.Length != mesh.vertices.Length) + if (FreezeRotation) { - throw new Exception("different vertex count"); + src.rotation = Quaternion.identity; + } + else + { + src.rotation = tr.Rotation; } - var value = blendShapeValues.ContainsKey(i) ? blendShapeValues[i] : 0; - srcRenderer.SetBlendShapeWeight(i, value); + src.position = tr.Translation; + } - Vector3[] vertices = blendShapeMesh.vertices; - - for (int j = 0; j < vertices.Length; ++j) + // second, replace mesh + foreach (var (src, tr) in boneMap) + { + if (meshMap.TryGetValue(src, out var info)) { - if (originalBlendShapePositions[j] == Vector3.zero) - { - vertices[j] = Vector3.zero; - } - else - { - vertices[j] = m.MultiplyPoint(vertices[j]) - meshVertices[j]; - } - } - - Vector3[] normals = blendShapeMesh.normals; - for (int j = 0; j < normals.Length; ++j) - { - if (originalBlendShapeNormals[j] == Vector3.zero) - { - normals[j] = Vector3.zero; - - } - else - { - normals[j] = m.MultiplyVector(normals[j].normalized) - meshNormals[j]; - } - } - - Vector3[] tangents = blendShapeMesh.tangents.Select(x => (Vector3)x).ToArray(); -#if VRM_NORMALIZE_BLENDSHAPE_TANGENT - for (int j = 0; j < tangents.Length; ++j) - { - if (originalBlendShapeTangents[j] == Vector3.zero) - { - tangents[j] = Vector3.zero; - } - else - { - tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j]; - } - } -#endif - - var frameCount = srcMesh.GetBlendShapeFrameCount(i); - for (int f = 0; f < frameCount; f++) - { - - var weight = srcMesh.GetBlendShapeFrameWeight(i, f); - - try - { - mesh.AddBlendShapeFrame(name, - weight, - vertices, - hasNormals > 0 ? normals : null, - hasTangents > 0 ? tangents : null - ); - } - catch (Exception) - { - Debug.LogErrorFormat("fail to mesh.AddBlendShapeFrame {0}.{1}", - mesh.name, - srcMesh.GetBlendShapeName(i) - ); - throw; - } + info.ReplaceMesh(src.gameObject); } } - - if (report.Count > 0) - { - Debug.LogFormat("{0}", report.ToString()); - } - - var dstRenderer = dst.gameObject.AddComponent(); - dstRenderer.sharedMaterials = srcRenderer.sharedMaterials; - if (srcRenderer.rootBone != null) - { - if (boneMap.TryGetValue(srcRenderer.rootBone, out Transform found)) - { - dstRenderer.rootBone = found; - } - } - dstRenderer.bones = dstBones; - dstRenderer.sharedMesh = mesh; - - if (!hasBoneWeight) - { - // restore bones - srcRenderer.bones = new Transform[] { }; - srcRenderer.sharedMesh = originalSrcMesh; - } - // restore blendshape weights - for (int i = 0; i < backcup.Count; ++i) - { - srcRenderer.SetBlendShapeWeight(i, backcup[i]); - } - } - - /// - /// - /// - /// - /// - static void NormalizeNoneSkinnedMesh(Transform src, Transform dst) - { - var srcFilter = src.GetComponent(); - if (srcFilter == null - || srcFilter.sharedMesh == null - || srcFilter.sharedMesh.vertexCount == 0) - { - return; - } - - var srcRenderer = src.GetComponent(); - if (srcRenderer == null || !srcRenderer.enabled) - { - return; - } - - // Meshに乗っているボーンの姿勢を適用する - var dstFilter = dst.gameObject.AddComponent(); - - var dstMesh = srcFilter.sharedMesh.Copy(false); - dstMesh.ApplyRotationAndScale(src.localToWorldMatrix); - dstFilter.sharedMesh = dstMesh; - - // Materialをコピー - var dstRenderer = dst.gameObject.AddComponent(); - dstRenderer.sharedMaterials = srcRenderer.sharedMaterials; - } - - /// - /// 回転とスケールを除去したヒエラルキーのコピーを作成する(MeshをBakeする) - /// - /// 対象のヒエラルキーのルート - /// BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する - /// Avatarを作る関数 - /// - public static (GameObject, Dictionary) Execute(GameObject go, CreateAvatarFunc createAvatar) - { - // - // 正規化されたヒエラルキーを作る - // - var (normalized, boneMap) = NormalizeHierarchy(go, createAvatar); - - // - // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する - // - foreach (var src in go.transform.Traverse()) - { - Transform dst; - if (!boneMap.TryGetValue(src, out dst)) - { - continue; - } - - NormalizeSkinnedMesh(src, dst, boneMap); - - NormalizeNoneSkinnedMesh(src, dst); - } - - return (normalized, boneMap); } } } diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs new file mode 100644 index 000000000..32b5d30cc --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + + +namespace UniGLTF.MeshUtility +{ + /// + /// - Freeze + /// - Integration + /// - Split + /// + /// - Implement runtime logic => Process a hierarchy in scene. Do not process prefab. + /// - Implement undo + /// + /// + public class GltfMeshUtility + { + /// + /// Same as VRM-0 normalization + /// - Mesh + /// - Node + /// - InverseBindMatrices + /// + public bool FreezeBlendShapeRotationAndScaling = false; + + public List MeshIntegrationGroups = new List(); + + /// + /// Create a headless model and solve VRM.FirstPersonFlag.Auto + /// + public bool GenerateMeshForFirstPersonAuto = false; + + /// + /// Split into having and not having BlendShape + /// + public bool SplitByBlendShape = false; + + static MeshIntegrationGroup.MeshIntegrationTypes TypeFromName(string name) + { + var key = name.ToLower(); + if (key.Contains("first")) + { + return MeshIntegrationGroup.MeshIntegrationTypes.FirstPersonOnly; + } + if (key.Contains("third")) + { + return MeshIntegrationGroup.MeshIntegrationTypes.ThirdPersonOnly; + } + if (key.Contains("auto")) + { + return MeshIntegrationGroup.MeshIntegrationTypes.Auto; + } + return MeshIntegrationGroup.MeshIntegrationTypes.Both; + } + + protected MeshIntegrationGroup _GetOrCreateGroup(string name) + { + foreach (var g in MeshIntegrationGroups) + { + if (g.Name == name) + { + return g; + } + } + MeshIntegrationGroups.Add(new MeshIntegrationGroup + { + Name = name, + IntegrationType = TypeFromName(name), + }); + return MeshIntegrationGroups.Last(); + } + + protected bool _HasRenderer(Renderer r) + { + foreach (var g in MeshIntegrationGroups) + { + foreach (var x in g.Renderers) + { + if (x == r) + { + return true; + } + } + } + return false; + } + + public virtual void UpdateMeshIntegrationGroups(GameObject root) + { + MeshIntegrationGroups.Clear(); + if (root == null) + { + return; + } + var group = _GetOrCreateGroup("all mesh"); + group.Renderers.AddRange(root.GetComponentsInChildren()); + } + + public void IntegrateAll(GameObject root) + { + if (root == null) + { + return; + } + MeshIntegrationGroups.Add(new MeshIntegrationGroup + { + Name = "All", + IntegrationType = MeshIntegrationGroup.MeshIntegrationTypes.Both, + Renderers = root.GetComponentsInChildren().ToList(), + }); + } + + static GameObject GetOrCreateEmpty(GameObject go, string name) + { + foreach (var child in go.transform.GetChildren()) + { + if (child.name == name + && child.localPosition == Vector3.zero + && child.localScale == Vector3.one + && child.localRotation == Quaternion.identity) + { + return child.gameObject; + } + } + var empty = new GameObject(name); + empty.transform.SetParent(go.transform, false); + return empty; + } + + /// + /// + /// + /// MeshIntegrationGroup を作ったとき root + /// go が prefab だった場合に instance されたもの + /// + public virtual IEnumerable CopyInstantiate(GameObject go, GameObject instance) + { + if (instance == null) + { + foreach (var g in MeshIntegrationGroups) + { + yield return g; + } + } + else + { + foreach (var g in MeshIntegrationGroups) + { + yield return g.CopyInstantiate(go, instance); + } + } + } + + public virtual (List, List) Process( + GameObject target, IEnumerable groupCopy) + { + if (FreezeBlendShapeRotationAndScaling) + { + // MeshをBakeする + var meshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(target); + + // - ヒエラルキーから回転・拡縮を除去する + // - BakeされたMeshで置き換える + // - bindPoses を再計算する + BoneNormalizer.Replace(target, meshMap, true, true); + } + + var newList = new List(); + + var empty = GetOrCreateEmpty(target, "mesh"); + + var results = new List(); + foreach (var group in groupCopy) + { + if (TryIntegrate(empty, group, out var resultAndAdded)) + { + var (result, newGo) = resultAndAdded; + results.Add(result); + newList.AddRange(newGo); + } + } + + return (results, newList); + } + + public void Clear(List results) + { + // 用が済んだ 統合前 の renderer を削除する + foreach (var result in results) + { + foreach (var r in result.SourceMeshRenderers) + { + if (Application.isPlaying) + { + GameObject.Destroy(r.gameObject.GetComponent()); + GameObject.Destroy(r); + } + else + { + GameObject.DestroyImmediate(r.gameObject.GetComponent()); + GameObject.DestroyImmediate(r); + } + } + foreach (var r in result.SourceSkinnedMeshRenderers) + { + if (Application.isPlaying) + { + GameObject.Destroy(r); + } + else + { + GameObject.DestroyImmediate(r, true); + } + } + } + + MeshIntegrationGroups.Clear(); + } + + protected virtual bool TryIntegrate(GameObject empty, + MeshIntegrationGroup group, out (MeshIntegrationResult, GameObject[]) resultAndAdded) + { + if (MeshIntegrator.TryIntegrate(group, SplitByBlendShape + ? MeshIntegrator.BlendShapeOperation.Split + : MeshIntegrator.BlendShapeOperation.Use, out var result)) + { + var newGo = result.AddIntegratedRendererTo(empty).ToArray(); + resultAndAdded = (result, newGo); + return true; + } + + resultAndAdded = default; + return false; + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs.meta b/Assets/External/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs.meta new file mode 100644 index 000000000..0ad3bff31 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2425cf6ac1f2434986968ff0d4a4755 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs new file mode 100644 index 000000000..54f36ee4f --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs @@ -0,0 +1,58 @@ +using System; +using System.Linq; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public class MeshAttachInfo + { + public Mesh Mesh; + public Material[] Materials; + public Transform[] Bones; + public Transform RootBone; + public void ReplaceMesh(GameObject dst) + { + if (dst == null) + { + throw new ArgumentNullException(); + } + + if (Bones != null) + { + // recalc bindposes + Mesh.bindposes = Bones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); + + if (dst.GetComponent() is SkinnedMeshRenderer dstRenderer) + { + dstRenderer.sharedMesh = Mesh; + dstRenderer.sharedMaterials = Materials; + dstRenderer.bones = Bones; + dstRenderer.rootBone = RootBone; + } + else + { + Debug.LogError($"SkinnedMeshRenderer not found", dst); + } + } + else + { + if (dst.GetComponent() is MeshFilter dstFilter) + { + dstFilter.sharedMesh = Mesh; + if (dst.gameObject.GetComponent() is MeshRenderer dstRenderer) + { + dstRenderer.sharedMaterials = Materials; + } + else + { + Debug.LogError($"MeshRenderer not found", dst); + } + } + else + { + Debug.LogError($"MeshFilter not found", dst); + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs.meta b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs.meta new file mode 100644 index 000000000..0db6210ad --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e6eff3bee96e61849ac190387ec28542 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs index 9f28ce281..736a63645 100644 --- a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs @@ -1,5 +1,6 @@ using UnityEngine; using System.Linq; +using VRMShaders; namespace UniGLTF.MeshUtility @@ -53,11 +54,11 @@ namespace UniGLTF.MeshUtility { var vertices = src.vertices; var normals = src.normals; -#if VRM_NORMALIZE_BLENDSHAPE_TANGENT - var tangents = src.tangents.Select(x => (Vector3)x).ToArray(); -#else Vector3[] tangents = null; -#endif + if (Symbols.VRM_NORMALIZE_BLENDSHAPE_TANGENT) + { + tangents = src.tangents.Select(x => (Vector3)x).ToArray(); + } for (int i = 0; i < src.blendShapeCount; ++i) { @@ -75,9 +76,19 @@ namespace UniGLTF.MeshUtility return dst; } - public static void ApplyRotationAndScale(this Mesh src, Matrix4x4 m) + public static void ApplyRotationAndScale(this Mesh src, Matrix4x4 m, bool removeTranslation = true) { - m.SetColumn(3, new Vector4(0, 0, 0, 1)); // remove translation + if (removeTranslation) + { + m.SetColumn(3, new Vector4(0, 0, 0, 1)); // remove translation + } + src.ApplyMatrix(m); + } + + public static void ApplyTranslation(this Mesh src, Vector3 p) + { + var m = Matrix4x4.identity; + m.SetColumn(3, new Vector4(p.x, p.y, p.z, 1)); src.ApplyMatrix(m); } diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs new file mode 100644 index 000000000..3bd3c45e9 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs @@ -0,0 +1,363 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UIElements; +using VRMShaders; + +namespace UniGLTF.MeshUtility +{ + public static class MeshFreezer + { + /// + /// index が 有効であれば、setter に weight を渡す。無効であれば setter に 0 を渡す。 + /// + /// + /// + /// + /// + static bool CopyOrDropWeight(int[] indexMap, int srcIndex, float weight, Action setter) + { + if (srcIndex < 0 || srcIndex >= indexMap.Length) + { + // ありえるかどうかわからないが BoneWeight.boneIndexN に変な値が入っている. + setter(0, 0); + return false; + } + + var dstIndex = indexMap[srcIndex]; + if (dstIndex != -1) + { + // 有効なindex。weightをコピーする + setter(dstIndex, weight); + return true; + } + else + { + // 無効なindex。0でクリアする + setter(0, 0); + return false; + } + } + + /// + /// BoneWeight[] src から新しいボーンウェイトを作成する。 + /// + /// 変更前のBoneWeight[] + /// 新旧のボーンの対応表。新しい方は無効なボーンが除去されてnullの部分がある + /// 変更前のボーン配列 + /// 変更後のボーン配列。除去されたボーンがある場合、変更前より短い + /// + public static BoneWeight[] MapBoneWeight(BoneWeight[] src, + Dictionary boneMap, + Transform[] srcBones, + Transform[] dstBones + ) + { + // 処理前後の index の対応表を作成する + var indexMap = new int[srcBones.Length]; + for (int i = 0; i < srcBones.Length; ++i) + { + var srcBone = srcBones[i]; + if (srcBone == null) + { + // 元のボーンが無い + indexMap[i] = -1; + Debug.LogWarningFormat("bones[{0}] is null", i); + } + else + { + if (boneMap.TryGetValue(srcBone, out Transform dstBone)) + { + // 対応するボーンが存在する + var dstIndex = Array.IndexOf(dstBones, dstBone); + if (dstIndex == -1) + { + // ありえない。バグ + throw new Exception(); + } + indexMap[i] = dstIndex; + } + else + { + // 先のボーンが無い + indexMap[i] = -1; + Debug.LogWarningFormat("{0} is removed", srcBone.name); + } + } + } + + // 新しいBoneWeightを作成する + var newBoneWeights = new BoneWeight[src.Length]; + for (int i = 0; i < src.Length; ++i) + { + BoneWeight srcBoneWeight = src[i]; + + // 0 + CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex0, srcBoneWeight.weight0, (newIndex, newWeight) => + { + newBoneWeights[i].boneIndex0 = newIndex; + newBoneWeights[i].weight0 = newWeight; + }); + // 1 + CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex1, srcBoneWeight.weight1, (newIndex, newWeight) => + { + newBoneWeights[i].boneIndex1 = newIndex; + newBoneWeights[i].weight1 = newWeight; + }); + // 2 + CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex2, srcBoneWeight.weight2, (newIndex, newWeight) => + { + newBoneWeights[i].boneIndex2 = newIndex; + newBoneWeights[i].weight2 = newWeight; + }); + // 3 + CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex3, srcBoneWeight.weight3, (newIndex, newWeight) => + { + newBoneWeights[i].boneIndex3 = newIndex; + newBoneWeights[i].weight3 = newWeight; + }); + } + + return newBoneWeights; + } + + /// + /// + /// + /// + /// 正規化前のボーンから正規化後のボーンを得る + /// + /// + public static Mesh NormalizeSkinnedMesh(SkinnedMeshRenderer src) + { + if (src == null + || !src.enabled + || src.sharedMesh == null + || src.sharedMesh.vertexCount == 0) + { + // 有効なSkinnedMeshRendererが無かった + return default; + } + + var srcMesh = src.sharedMesh; + var originalSrcMesh = srcMesh; + + var hasBoneWeight = src.bones != null && src.bones.Length > 0; + if (!hasBoneWeight) + { + // Before bake, bind no weight bones + + srcMesh = srcMesh.Copy(true); + srcMesh.ApplyRotationAndScale(src.transform.localToWorldMatrix, false); + + var bw = new BoneWeight + { + boneIndex0 = 0, + boneIndex1 = 0, + boneIndex2 = 0, + boneIndex3 = 0, + weight0 = 1.0f, + weight1 = 0.0f, + weight2 = 0.0f, + weight3 = 0.0f, + }; + srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray(); + src.bones = new[] { src.rootBone ?? src.transform }; + srcMesh.bindposes = src.bones.Select(x => x.worldToLocalMatrix).ToArray(); + + src.sharedMesh = srcMesh; + } + + // BakeMesh + var mesh = srcMesh.Copy(false); + mesh.name = srcMesh.name + ".baked"; + src.BakeMesh(mesh); + + mesh.boneWeights = srcMesh.boneWeights; + + { + // apply SkinnedMesh.transform rotation + var m = Matrix4x4.TRS(Vector3.zero, src.transform.rotation, Vector3.one); + mesh.ApplyMatrix(m); + } + + // + // BlendShapes + // + { + var m = src.localToWorldMatrix; // include scaling + m.SetColumn(3, new Vector4(0, 0, 0, 1)); // no translation + CopyBlendShapes(src, srcMesh, mesh, m); + } + + return mesh; + } + + private static void CopyBlendShapes(SkinnedMeshRenderer src, Mesh srcMesh, Mesh mesh, Matrix4x4 m) + { + var blendShapeValues = new Dictionary(); + for (int i = 0; i < srcMesh.blendShapeCount; i++) + { + var val = src.GetBlendShapeWeight(i); + if (val > 0) blendShapeValues.Add(i, val); + } + + // clear blendShape always + var backcup = new List(); + for (int i = 0; i < srcMesh.blendShapeCount; ++i) + { + backcup.Add(src.GetBlendShapeWeight(i)); + src.SetBlendShapeWeight(i, 0); + } + + var meshVertices = mesh.vertices; + var meshNormals = mesh.normals; + var meshTangents = Array.Empty(); + if (Symbols.VRM_NORMALIZE_BLENDSHAPE_TANGENT) + { + meshTangents = mesh.tangents.Select(x => (Vector3)x).ToArray(); + } + + var originalBlendShapePositions = new Vector3[meshVertices.Length]; + var originalBlendShapeNormals = new Vector3[meshVertices.Length]; + var originalBlendShapeTangents = new Vector3[meshVertices.Length]; + + var report = new BlendShapeReport(srcMesh); + var blendShapeMesh = new Mesh(); + for (int i = 0; i < srcMesh.blendShapeCount; ++i) + { + // check blendShape + src.sharedMesh.GetBlendShapeFrameVertices(i, 0, originalBlendShapePositions, originalBlendShapeNormals, originalBlendShapeTangents); + var hasVertices = originalBlendShapePositions.Count(x => x != Vector3.zero); + var hasNormals = originalBlendShapeNormals.Count(x => x != Vector3.zero); + var hasTangents = 0; + if (Symbols.VRM_NORMALIZE_BLENDSHAPE_TANGENT) + { + hasTangents = originalBlendShapeTangents.Count(x => x != Vector3.zero); + } + var name = srcMesh.GetBlendShapeName(i); + if (string.IsNullOrEmpty(name)) + { + name = String.Format("{0}", i); + } + + report.SetCount(i, name, hasVertices, hasNormals, hasTangents); + + src.SetBlendShapeWeight(i, 100.0f); + src.BakeMesh(blendShapeMesh); + if (blendShapeMesh.vertices.Length != mesh.vertices.Length) + { + throw new Exception("different vertex count"); + } + + var value = blendShapeValues.ContainsKey(i) ? blendShapeValues[i] : 0; + src.SetBlendShapeWeight(i, value); + + Vector3[] vertices = blendShapeMesh.vertices; + + for (int j = 0; j < vertices.Length; ++j) + { + if (originalBlendShapePositions[j] == Vector3.zero) + { + vertices[j] = Vector3.zero; + } + else + { + vertices[j] = m.MultiplyPoint(vertices[j] - meshVertices[j]); + } + } + + Vector3[] normals = blendShapeMesh.normals; + for (int j = 0; j < normals.Length; ++j) + { + if (originalBlendShapeNormals[j] == Vector3.zero) + { + normals[j] = Vector3.zero; + + } + else + { + normals[j] = m.MultiplyVector(normals[j].normalized) - meshNormals[j]; + } + } + + Vector3[] tangents = blendShapeMesh.tangents.Select(x => (Vector3)x).ToArray(); + if (Symbols.VRM_NORMALIZE_BLENDSHAPE_TANGENT) + { + for (int j = 0; j < tangents.Length; ++j) + { + if (originalBlendShapeTangents[j] == Vector3.zero) + { + tangents[j] = Vector3.zero; + } + else + { + tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j]; + } + } + } + + var frameCount = srcMesh.GetBlendShapeFrameCount(i); + for (int f = 0; f < frameCount; f++) + { + + var weight = srcMesh.GetBlendShapeFrameWeight(i, f); + + try + { + mesh.AddBlendShapeFrame(name, + weight, + vertices, + hasNormals > 0 ? normals : null, + hasTangents > 0 ? tangents : null + ); + } + catch (Exception) + { + Debug.LogErrorFormat("fail to mesh.AddBlendShapeFrame {0}.{1}", + mesh.name, + srcMesh.GetBlendShapeName(i) + ); + throw; + } + } + } + + // restore blendshape weights + for (int i = 0; i < backcup.Count; ++i) + { + src.SetBlendShapeWeight(i, backcup[i]); + } + } + + public static Mesh NormalizeNoneSkinnedMesh(MeshRenderer srcRenderer, bool freezeRotation) + { + if (srcRenderer == null || !srcRenderer.enabled) + { + return default; + } + + var srcFilter = srcRenderer.GetComponent(); + if (srcFilter == null + || srcFilter.sharedMesh == null + || srcFilter.sharedMesh.vertexCount == 0) + { + return default; + } + + var dstMesh = srcFilter.sharedMesh.Copy(false); + // Meshに乗っているボーンの姿勢を適用する + if (freezeRotation) + { + dstMesh.ApplyRotationAndScale(srcRenderer.transform.localToWorldMatrix); + } + else + { + var (t, r, s) = srcRenderer.transform.localToWorldMatrix.Decompose(); + dstMesh.ApplyRotationAndScale(Matrix4x4.TRS(t, Quaternion.identity, s)); + } + return dstMesh; + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs.meta b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs.meta new file mode 100644 index 000000000..33f6e2041 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09547456fd06d7b419d7553beba6f58a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs new file mode 100644 index 000000000..301e1aa72 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public class MeshIntegrationGroup + { + public string Name; + + public enum MeshIntegrationTypes + { + Both, + FirstPersonOnly, + ThirdPersonOnly, + Auto, + } + + public MeshIntegrationTypes IntegrationType = default; + public List Renderers = new List(); + + public MeshIntegrationGroup CopyInstantiate(GameObject go, GameObject instance) + { + var copy = new MeshIntegrationGroup + { + Name = Name + }; + foreach (var r in Renderers) + { + var relative = r.transform.RelativePathFrom(go.transform); + if (r is SkinnedMeshRenderer smr) + { + copy.Renderers.Add(instance.transform.GetFromPath(relative).GetComponent()); + } + else if (r is MeshRenderer mr) + { + copy.Renderers.Add(instance.transform.GetFromPath(relative).GetComponent()); + } + } + return copy; + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs.meta b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs.meta new file mode 100644 index 000000000..b456cf085 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae366b97d8d020245bbdb5d25df09314 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs index 50e0d3679..30a657006 100644 --- a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs @@ -1,21 +1,72 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using UnityEngine; + namespace UniGLTF.MeshUtility { - [System.Serializable] - public class MeshMap + public struct DrawCount { - public List Sources = new List(); - public Mesh Integrated; + public int Count; + public Material Material; + } + + [Serializable] + public class MeshInfo + { + public Mesh Mesh; + public List SubMeshes = new List(); + + public SkinnedMeshRenderer IntegratedRenderer; + + public void AddIntegratedRendererTo(GameObject parent, Transform[] bones) + { + var go = new GameObject(Mesh.name); + go.transform.SetParent(parent.transform, false); + var smr = go.AddComponent(); + smr.sharedMesh = Mesh; + smr.sharedMaterials = SubMeshes.Where(x => x.Count > 0).Select(x => x.Material).ToArray(); + smr.bones = bones; + IntegratedRenderer = smr; + } } public class MeshIntegrationResult { public List SourceSkinnedMeshRenderers = new List(); public List SourceMeshRenderers = new List(); - public SkinnedMeshRenderer IntegratedRenderer; - public MeshMap MeshMap = new MeshMap(); + public List Sources = new List(); + public MeshInfo Integrated; + public MeshInfo IntegratedNoBlendShape; + public Transform[] Bones; + + public void DestroySourceRenderer() + { + throw new NotImplementedException(); + } + + public IEnumerable AddIntegratedRendererTo(GameObject parent) + { + int count = 0; + if (Integrated != null) + { + Integrated.AddIntegratedRendererTo(parent, Bones); + ++count; + yield return Integrated.IntegratedRenderer.gameObject; + } + if (IntegratedNoBlendShape != null) + { + IntegratedNoBlendShape.AddIntegratedRendererTo(parent, Bones); + ++count; + yield return IntegratedNoBlendShape.IntegratedRenderer.gameObject; + } + + if (count == 0) + { + throw new NotImplementedException(); + } + } } } diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs index 30fc53a90..b1db1d5dc 100644 --- a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs @@ -1,14 +1,22 @@ +using System; using System.Collections.Generic; using System.Linq; +using UnityEditor; using UnityEngine; namespace UniGLTF.MeshUtility { public class MeshIntegrator { - public const string INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME = "Integrated(WithoutBlendShape)"; - public const string INTEGRATED_MESH_WITH_BLENDSHAPE_NAME = "Integrated(WithBlendShape)"; - public const string INTEGRATED_MESH_ALL_NAME = "Integrated(All)"; + public enum BlendShapeOperation + { + // No BlendShape(drop if mesh has blendshape) + None, + // Use blendShape(keep blendshape) + Use, + // Integrate to two mesh that is with blendShape and is without blendshape + Split, + } struct SubMesh { @@ -16,14 +24,29 @@ namespace UniGLTF.MeshUtility public Material Material; } - class BlendShape + public class BlendShape { - public int VertexOffset; public string Name; - public float FrameWeight; - public Vector3[] Positions; - public Vector3[] Normals; - public Vector3[] Tangents; + public List Positions = new List(); + public List Normals = new List(); + public List Tangents = new List(); + + public BlendShape(string name) + { + Name = name; + } + + public void Fill(int count) + { + var size = count - Positions.Count; + if (size < 0) + { + throw new Exception(); + } + Positions.AddRange(Enumerable.Repeat(Vector3.zero, size)); + Normals.AddRange(Enumerable.Repeat(Vector3.zero, size)); + Tangents.AddRange(Enumerable.Repeat(Vector3.zero, size)); + } } MeshIntegrationResult Result { get; } = new MeshIntegrationResult(); @@ -33,54 +56,45 @@ namespace UniGLTF.MeshUtility List Tangents { get; } = new List(); List BoneWeights { get; } = new List(); List SubMeshes { get; } = new List(); - List BindPoses { get; } = new List(); - List Bones { get; } = new List(); + List _BindPoses { get; } = new List(); + List _Bones { get; } = new List(); List BlendShapes { get; } = new List(); void AddBlendShapesToMesh(Mesh mesh) { - Dictionary map = new Dictionary(); - foreach (var x in BlendShapes) - { - BlendShape bs = null; - if (!map.TryGetValue(x.Name, out bs)) - { - bs = new BlendShape(); - bs.Positions = new Vector3[Positions.Count]; - bs.Normals = new Vector3[Normals.Count]; - bs.Tangents = new Vector3[Tangents.Count]; - bs.Name = x.Name; - bs.FrameWeight = x.FrameWeight; - map.Add(x.Name, bs); - } - - var j = x.VertexOffset; - for (int i = 0; i < x.Positions.Length; ++i, ++j) - { - bs.Positions[j] = x.Positions[i]; - bs.Normals[j] = x.Normals[i]; - bs.Tangents[j] = x.Tangents[i]; - } - } - - foreach (var kv in map) { //Debug.LogFormat("AddBlendShapeFrame: {0}", kv.Key); - mesh.AddBlendShapeFrame(kv.Key, kv.Value.FrameWeight, - kv.Value.Positions, kv.Value.Normals, kv.Value.Tangents); + mesh.AddBlendShapeFrame(x.Name, 100.0f, + x.Positions.ToArray(), + x.Normals.ToArray(), + x.Tangents.ToArray()); } } - static BoneWeight AddBoneIndexOffset(BoneWeight bw, int boneIndexOffset) + int AddBoneIfUnique(Transform bone, Matrix4x4? pose = default) { - if (bw.weight0 > 0) bw.boneIndex0 += boneIndexOffset; - if (bw.weight1 > 0) bw.boneIndex1 += boneIndexOffset; - if (bw.weight2 > 0) bw.boneIndex2 += boneIndexOffset; - if (bw.weight3 > 0) bw.boneIndex3 += boneIndexOffset; - return bw; + var index = _Bones.IndexOf(bone); + if (index == -1) + { + index = _Bones.Count; + _Bones.Add(bone); + _BindPoses.Add(pose.HasValue ? pose.Value : bone.worldToLocalMatrix); + } + return index; } - public void Push(MeshRenderer renderer) + void AddBoneIfUnique(Transform[] bones, Matrix4x4[] bindPoses, int boneIndex, float weight, Action setter) + { + if (boneIndex < 0 || boneIndex >= bones.Length || weight <= 0) + { + setter(0, 0); + return; + } + var t = bones[boneIndex]; + setter(AddBoneIfUnique(t, bindPoses[boneIndex]), weight); + } + + void Push(MeshRenderer renderer) { var meshFilter = renderer.GetComponent(); if (meshFilter == null) @@ -95,10 +109,9 @@ namespace UniGLTF.MeshUtility return; } Result.SourceMeshRenderers.Add(renderer); - Result.MeshMap.Sources.Add(mesh); + Result.Sources.Add(mesh); var indexOffset = Positions.Count; - var boneIndexOffset = Bones.Count; Positions.AddRange(mesh.vertices .Select(x => renderer.transform.TransformPoint(x)) @@ -115,27 +128,24 @@ namespace UniGLTF.MeshUtility }) ); - var self = renderer.transform; - var bone = self.parent; + var bone = renderer.transform; if (bone == null) { - Debug.LogWarningFormat("{0} is root gameobject.", self.name); + Debug.LogWarningFormat("{0} is root gameobject.", bone.name); return; } - var bindpose = bone.worldToLocalMatrix; + var boneIndex = AddBoneIfUnique(bone); BoneWeights.AddRange(Enumerable.Range(0, mesh.vertices.Length) .Select(x => new BoneWeight() { - boneIndex0 = Bones.Count, + boneIndex0 = boneIndex, weight0 = 1, }) ); - BindPoses.Add(bindpose); - Bones.Add(bone); - for (int i = 0; i < mesh.subMeshCount; ++i) + for (int i = 0; i < mesh.subMeshCount && i < renderer.sharedMaterials.Length; ++i) { var indices = mesh.GetIndices(i).Select(x => x + indexOffset); var mat = renderer.sharedMaterials[i]; @@ -157,6 +167,12 @@ namespace UniGLTF.MeshUtility public void Push(SkinnedMeshRenderer renderer) { + if (renderer == null) + { + // Debug.LogWarningFormat("{0} was destroyed", renderer); + return; + } + var mesh = renderer.sharedMesh; if (mesh == null) { @@ -164,10 +180,10 @@ namespace UniGLTF.MeshUtility return; } Result.SourceSkinnedMeshRenderers.Add(renderer); - Result.MeshMap.Sources.Add(mesh); + Result.Sources.Add(mesh); - var indexOffset = Positions.Count; - var boneIndexOffset = Bones.Count; + var vertexOffset = Positions.Count; + // var boneIndexOffset = Bones.Count; Positions.AddRange(mesh.vertices); Normals.AddRange(mesh.normals); @@ -176,26 +192,31 @@ namespace UniGLTF.MeshUtility if (mesh.vertexCount == mesh.boneWeights.Length) { - BoneWeights.AddRange(mesh.boneWeights.Select(x => AddBoneIndexOffset(x, boneIndexOffset)).ToArray()); - BindPoses.AddRange(mesh.bindposes); - Bones.AddRange(renderer.bones); + // AddBone AddBoneIndexOffset(x, boneIndexOffset) + BoneWeights.AddRange(mesh.boneWeights.Select(x => + { + var bw = new BoneWeight(); + AddBoneIfUnique(renderer.bones, mesh.bindposes, x.boneIndex0, x.weight0, (i, w) => { bw.boneIndex0 = i; bw.weight0 = w; }); + AddBoneIfUnique(renderer.bones, mesh.bindposes, x.boneIndex1, x.weight1, (i, w) => { bw.boneIndex1 = i; bw.weight1 = w; }); + AddBoneIfUnique(renderer.bones, mesh.bindposes, x.boneIndex2, x.weight2, (i, w) => { bw.boneIndex2 = i; bw.weight2 = w; }); + AddBoneIfUnique(renderer.bones, mesh.bindposes, x.boneIndex3, x.weight3, (i, w) => { bw.boneIndex3 = i; bw.weight3 = w; }); + return bw; + }).ToArray()); } else { // Bone Count 0 の SkinnedMeshRenderer var rigidBoneWeight = new BoneWeight { - boneIndex0 = boneIndexOffset, + boneIndex0 = AddBoneIfUnique(renderer.transform), weight0 = 1f, }; BoneWeights.AddRange(Enumerable.Range(0, mesh.vertexCount).Select(x => rigidBoneWeight).ToArray()); - BindPoses.Add(renderer.transform.localToWorldMatrix); - Bones.Add(renderer.transform); } - for (int i = 0; i < mesh.subMeshCount; ++i) + for (int i = 0; i < mesh.subMeshCount && i < renderer.sharedMaterials.Length; ++i) { - var indices = mesh.GetIndices(i).Select(x => x + indexOffset); + var indices = mesh.GetIndices(i).Select(x => x + vertexOffset); var mat = renderer.sharedMaterials[i]; var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat)); if (sameMaterialSubMeshIndex >= 0) @@ -214,96 +235,198 @@ namespace UniGLTF.MeshUtility for (int i = 0; i < mesh.blendShapeCount; ++i) { - var positions = (Vector3[])mesh.vertices.Clone(); - var normals = (Vector3[])mesh.normals.Clone(); - var tangents = mesh.tangents.Select(x => (Vector3)x).ToArray(); - + // arrays size must match mesh vertex count + var positions = new Vector3[mesh.vertexCount]; + var normals = new Vector3[mesh.vertexCount]; + var tangents = new Vector3[mesh.vertexCount]; mesh.GetBlendShapeFrameVertices(i, 0, positions, normals, tangents); - BlendShapes.Add(new BlendShape - { - VertexOffset = indexOffset, - FrameWeight = mesh.GetBlendShapeFrameWeight(i, 0), - Name = mesh.GetBlendShapeName(i), - Positions = positions, - Normals = normals, - Tangents = tangents, - }); + + var blendShape = GetOrCreateBlendShape(mesh.GetBlendShapeName(i), vertexOffset); + blendShape.Positions.AddRange(positions); + blendShape.Normals.AddRange(normals); + blendShape.Tangents.AddRange(tangents); + } + foreach (var blendShape in BlendShapes) + { + blendShape.Fill(Positions.Count); } } - public MeshIntegrationResult Integrate(MeshEnumerateOption onlyBlendShapeRenderers) + BlendShape GetOrCreateBlendShape(string name, int vertexOffset) + { + BlendShape found = null; + foreach (var blendshape in BlendShapes) + { + if (blendshape.Name == name) + { + found = blendshape; + break; + } + } + if (found == null) + { + found = new BlendShape(name); + BlendShapes.Add(found); + } + + found.Fill(vertexOffset); + + return found; + } + + public static bool TryIntegrate(MeshIntegrationGroup group, BlendShapeOperation op, + out MeshIntegrationResult result) + { + var integrator = new MeshUtility.MeshIntegrator(); + foreach (var x in group.Renderers) + { + if (x is SkinnedMeshRenderer smr) + { + integrator.Push(smr); + } + else if (x is MeshRenderer mr) + { + integrator.Push(mr); + } + } + result = integrator.Integrate(group.Name, op); + if (result.Integrated != null || result.IntegratedNoBlendShape != null) + { + return true; + } + else + { + return false; + } + } + + delegate bool TriangleFilter(int i0, int i1, int i2); + + static int[] GetFilteredIndices(List indices, TriangleFilter filter) + { + if (filter == null) + { + return indices.ToArray(); + } + + var filtered = new List(); + for (int i = 0; i < indices.Count; i += 3) + { + var i0 = indices[i]; + var i1 = indices[i + 1]; + var i2 = indices[i + 2]; + if (filter(i0, i1, i2)) + { + filtered.Add(i0); + filtered.Add(i1); + filtered.Add(i2); + } + } + return filtered.ToArray(); + } + + Mesh CreateMesh(string name, List dst, TriangleFilter filter) { var mesh = new Mesh(); - + mesh.name = name; if (Positions.Count > ushort.MaxValue) { Debug.LogFormat("exceed 65535 vertices: {0}", Positions.Count); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; } - mesh.vertices = Positions.ToArray(); mesh.normals = Normals.ToArray(); mesh.uv = UV.ToArray(); - mesh.tangents = Tangents.ToArray(); - mesh.boneWeights = BoneWeights.ToArray(); - mesh.subMeshCount = SubMeshes.Count; - for (var i = 0; i < SubMeshes.Count; ++i) + if (Tangents != null && Tangents.Count == Positions.Count) { - mesh.SetIndices(SubMeshes[i].Indices.ToArray(), MeshTopology.Triangles, i); + mesh.tangents = Tangents.ToArray(); } - mesh.bindposes = BindPoses.ToArray(); - - // blendshape - switch (onlyBlendShapeRenderers) + if (BoneWeights != null && BoneWeights.Count == Positions.Count) { - case MeshEnumerateOption.OnlyWithBlendShape: - { - AddBlendShapesToMesh(mesh); - mesh.name = INTEGRATED_MESH_WITH_BLENDSHAPE_NAME; - break; - } - - case MeshEnumerateOption.All: - { - AddBlendShapesToMesh(mesh); - mesh.name = INTEGRATED_MESH_ALL_NAME; - break; - } - - case MeshEnumerateOption.OnlyWithoutBlendShape: - { - mesh.name = INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME; - break; - } + mesh.boneWeights = BoneWeights.ToArray(); } - // meshName - var meshNode = new GameObject(); - switch (onlyBlendShapeRenderers) + int subMeshCount = 0; + foreach (var submesh in SubMeshes) { - case MeshEnumerateOption.OnlyWithBlendShape: + var indices = GetFilteredIndices(submesh.Indices, filter); + if (indices.Length > 0) + { + mesh.subMeshCount = (subMeshCount + 1); + mesh.SetIndices(indices, MeshTopology.Triangles, subMeshCount++); + dst.Add(new DrawCount { - meshNode.name = INTEGRATED_MESH_WITH_BLENDSHAPE_NAME; - break; - } - case MeshEnumerateOption.OnlyWithoutBlendShape: - { - meshNode.name = INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME; - break; - } - case MeshEnumerateOption.All: - { - meshNode.name = INTEGRATED_MESH_ALL_NAME; - break; - } + Count = indices.Length, + Material = submesh.Material, + }); + } } - var integrated = meshNode.AddComponent(); - integrated.sharedMesh = mesh; - integrated.sharedMaterials = SubMeshes.Select(x => x.Material).ToArray(); - integrated.bones = Bones.ToArray(); - Result.IntegratedRenderer = integrated; - Result.MeshMap.Integrated = mesh; + return mesh; + } + + MeshIntegrationResult Integrate(string name, BlendShapeOperation op) + { + if (_Bones.Count != _BindPoses.Count) + { + throw new ArgumentException(); + } + + var splitter = new TriangleSeparator(Positions.Count); + if (op == BlendShapeOperation.Split) + { + foreach (var blendShape in BlendShapes) + { + splitter.CheckPositions(blendShape.Positions); + } + } + + if (splitter.ShouldSplit) + { + // + // has BlendShape + // + Result.Integrated = new MeshInfo(); + var mesh = CreateMesh(name, Result.Integrated.SubMeshes, + splitter.TriangleHasBlendShape); + Result.Integrated.Mesh = mesh; + AddBlendShapesToMesh(mesh); + // skinning + mesh.bindposes = _BindPoses.ToArray(); + + // + // no BlendShape + // + Result.IntegratedNoBlendShape = new MeshInfo(); + var meshWithoutBlendShape = CreateMesh(name + ".no_blendshape", Result.IntegratedNoBlendShape.SubMeshes, + splitter.TriangleHasNotBlendShape); + Result.IntegratedNoBlendShape.Mesh = meshWithoutBlendShape; + // skinning + meshWithoutBlendShape.bindposes = _BindPoses.ToArray(); + } + else + { + var useBlendShape = op == BlendShapeOperation.Use && BlendShapes.Count > 0; + if (useBlendShape) + { + Result.Integrated = new MeshInfo(); + var mesh = CreateMesh(name, Result.Integrated.SubMeshes, null); + Result.Integrated.Mesh = mesh; + AddBlendShapesToMesh(mesh); + // skinning + mesh.bindposes = _BindPoses.ToArray(); + } + else + { + Result.IntegratedNoBlendShape = new MeshInfo(); + var mesh = CreateMesh(name, Result.IntegratedNoBlendShape.SubMeshes, null); + Result.IntegratedNoBlendShape.Mesh = mesh; + // skinning + mesh.bindposes = _BindPoses.ToArray(); + } + } + Result.Bones = _Bones.ToArray(); + return Result; } } diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs deleted file mode 100644 index 7050bcb99..000000000 --- a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using UnityEngine; - -namespace UniGLTF.MeshUtility -{ - public static class MeshIntegratorUtility - { - /// - /// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する - /// - /// - /// - /// true: BlendShapeを保持するSkinnedMeshRendererのみ - /// false: BlendShapeを保持しないSkinnedMeshRenderer + MeshRenderer - /// null: すべてのSkinnedMeshRenderer + MeshRenderer - /// - /// - public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption onlyBlendShapeRenderers, - IEnumerable excludes = null, - bool destroyIntegratedRenderer = false) - { - var exclude = new MeshExclude(excludes); - - var integrator = new MeshUtility.MeshIntegrator(); - - switch (onlyBlendShapeRenderers) - { - case MeshEnumerateOption.OnlyWithBlendShape: - { - foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, onlyBlendShapeRenderers)) - { - if (exclude.IsExcluded(x)) - { - continue; - } - integrator.Push(x); - } - break; - } - - case MeshEnumerateOption.OnlyWithoutBlendShape: - { - foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, onlyBlendShapeRenderers)) - { - if (exclude.IsExcluded(x)) - { - continue; - } - integrator.Push(x); - } - - foreach (var x in EnumerateMeshRenderer(go.transform)) - { - if (exclude.IsExcluded(x)) - { - continue; - } - integrator.Push(x); - } - - break; - } - - case MeshEnumerateOption.All: - { - foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, onlyBlendShapeRenderers)) - { - if (exclude.IsExcluded(x)) - { - continue; - } - integrator.Push(x); - } - - foreach (var x in EnumerateMeshRenderer(go.transform)) - { - if (exclude.IsExcluded(x)) - { - continue; - } - integrator.Push(x); - } - - break; - } - } - - return integrator.Integrate(onlyBlendShapeRenderers); - } - - public static IEnumerable EnumerateSkinnedMeshRenderer(Transform root, MeshEnumerateOption hasBlendShape) - { - foreach (var x in Traverse(root)) - { - var renderer = x.GetComponent(); - if (renderer != null && - renderer.gameObject.activeInHierarchy && - renderer.sharedMesh != null && - renderer.enabled) - { - switch (hasBlendShape) - { - case MeshEnumerateOption.OnlyWithBlendShape: - if (renderer.sharedMesh.blendShapeCount > 0) - { - yield return renderer; - } - break; - - case MeshEnumerateOption.OnlyWithoutBlendShape: - if (renderer.sharedMesh.blendShapeCount == 0) - { - yield return renderer; - } - break; - - case MeshEnumerateOption.All: - { - yield return renderer; - break; - } - } - } - } - } - - public static IEnumerable EnumerateMeshRenderer(Transform root) - { - foreach (var x in Traverse(root)) - { - var renderer = x.GetComponent(); - var filter = x.GetComponent(); - - if (renderer != null && - filter != null && - renderer.gameObject.activeInHierarchy && - filter.sharedMesh != null) - { - yield return renderer; - } - } - } - - private static IEnumerable Traverse(Transform parent) - { - if (parent.gameObject.activeSelf) - { - yield return parent; - - foreach (Transform child in parent) - { - foreach (var x in Traverse(child)) - { - yield return x; - } - } - } - } - - public static void ReplaceMeshWithResults(GameObject copy, List results) - { - // destroy original meshes - foreach (var skinnedMesh in copy.GetComponentsInChildren()) - { - GameObject.DestroyImmediate(skinnedMesh); - } - foreach (var normalMesh in copy.GetComponentsInChildren()) - { - if (normalMesh.gameObject.GetComponent()) - { - GameObject.DestroyImmediate(normalMesh.gameObject.GetComponent()); - } - GameObject.DestroyImmediate(normalMesh); - } - - // Add integrated - foreach (var result in results) - { - result.IntegratedRenderer.transform.SetParent(copy.transform, false); - } - } - } -} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs.meta b/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs.meta deleted file mode 100644 index b9075e71b..000000000 --- a/Assets/External/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: a982d9d30c0145038245b0214dc2f2e4 -timeCreated: 1560190306 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/TriangleSeparator.cs b/Assets/External/UniGLTF/Runtime/MeshUtility/TriangleSeparator.cs new file mode 100644 index 000000000..8ca08e604 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/TriangleSeparator.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + class TriangleSeparator + { + bool[] VertexHasBlendShape; + + public bool ShouldSplit + { + get + { + var count = VertexHasBlendShape.Count(x => x); + // すべて true か false の場合は分割しない + return count > 0 && count < VertexHasBlendShape.Length; + } + } + + public bool TriangleHasBlendShape(int i0, int i1, int i2) + { + return VertexHasBlendShape[i0] + || VertexHasBlendShape[i1] + || VertexHasBlendShape[i2]; + } + + public bool TriangleHasNotBlendShape(int i0, int i1, int i2) + { + return !TriangleHasBlendShape(i0, i1, i2); + } + + public TriangleSeparator(int vertexCount) + { + VertexHasBlendShape = new bool[vertexCount]; + } + + public void CheckPositions(IReadOnlyList positions) + { + for (int i = 0; i < positions.Count; ++i) + { + if (positions[i] != Vector3.zero) + { + VertexHasBlendShape[i] = true; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/MeshUtility/TriangleSeparator.cs.meta b/Assets/External/UniGLTF/Runtime/MeshUtility/TriangleSeparator.cs.meta new file mode 100644 index 000000000..29d1e3774 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/MeshUtility/TriangleSeparator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8936c9c948d10447a6899410bac3c07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/Resources.meta b/Assets/External/UniGLTF/Runtime/Resources.meta deleted file mode 100644 index 2285cdc60..000000000 --- a/Assets/External/UniGLTF/Runtime/Resources.meta +++ /dev/null @@ -1,10 +0,0 @@ -fileFormatVersion: 2 -guid: c61106d290c827b49b7a6e3f6497bd3f -folderAsset: yes -timeCreated: 1519379142 -licenseType: Free -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/Resources/I-Pose.pose.asset b/Assets/External/UniGLTF/Runtime/Resources/I-Pose.pose.asset deleted file mode 100644 index e87dc2c71..000000000 --- a/Assets/External/UniGLTF/Runtime/Resources/I-Pose.pose.asset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f7d87fe14c4d6657f4e6bb187c8516091c66d24fe726314f40446ea29a23de7 -size 1944 diff --git a/Assets/External/UniGLTF/Runtime/Resources/test_motion.txt b/Assets/External/UniGLTF/Runtime/Resources/test_motion.txt deleted file mode 100644 index 8be2e7424..000000000 --- a/Assets/External/UniGLTF/Runtime/Resources/test_motion.txt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a1f2b62a3c8c061dda794146865010034a002ae9632912655ae7c7f3578651cb -size 3420181 diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF.asmdef b/Assets/External/UniGLTF/Runtime/UniGLTF.asmdef index 7932fb6b1..b0a6d0090 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF.asmdef +++ b/Assets/External/UniGLTF/Runtime/UniGLTF.asmdef @@ -1,8 +1,10 @@ { "name": "UniGLTF", + "rootNamespace": "", "references": [ "GUID:da3e51d19d51a544fa14d43fee843098", - "GUID:60c8346e00a8ddd4cafc5a02eceeec57" + "GUID:60c8346e00a8ddd4cafc5a02eceeec57", + "GUID:1cd941934d098654fa21a13f28346412" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/ExtensionsAndExtras/gltf_mesh_extras_targetNames.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/ExtensionsAndExtras/gltf_mesh_extras_targetNames.cs index f1036bb61..4a276480a 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/ExtensionsAndExtras/gltf_mesh_extras_targetNames.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/ExtensionsAndExtras/gltf_mesh_extras_targetNames.cs @@ -91,7 +91,7 @@ namespace UniGLTF return new glTFExtensionExport().Add(ExtraName, f.GetStore().Bytes); } - public static void Serialize(glTFMesh gltfMesh, IEnumerable targetNames) + public static void Serialize(glTFMesh gltfMesh, IEnumerable targetNames, BlendShapeTargetNameLocationFlags blendShapeTargetNameLocation) { // targetNames var f = new JsonFormatter(); @@ -103,13 +103,21 @@ namespace UniGLTF f.EndList(); var targetNamesJson = f.GetStore().Bytes; - var meshExtras = glTFExtensionExport.GetOrCreate(ref gltfMesh.extras); - meshExtras.Add(ExtraName, targetNamesJson); - - foreach (var prim in gltfMesh.primitives) + // mesh + if (blendShapeTargetNameLocation.HasFlag(BlendShapeTargetNameLocationFlags.Mesh)) { - var primExtras = glTFExtensionExport.GetOrCreate(ref prim.extras); - primExtras.Add(ExtraName, targetNamesJson); + var meshExtras = glTFExtensionExport.GetOrCreate(ref gltfMesh.extras); + meshExtras.Add(ExtraName, targetNamesJson); + } + + // primitive + if (blendShapeTargetNameLocation.HasFlag(BlendShapeTargetNameLocationFlags.Primitives)) + { + foreach (var prim in gltfMesh.primitives) + { + var primExtras = glTFExtensionExport.GetOrCreate(ref prim.extras); + primExtras.Add(ExtraName, targetNamesJson); + } } } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/GltfSerializer.g.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/GltfSerializer.g.cs index 6268a60ee..326834f80 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/GltfSerializer.g.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/GltfSerializer.g.cs @@ -272,14 +272,14 @@ public static void Serialize_gltf_accessors_ITEM(JsonFormatter f, glTFAccessor v f.BeginMap(); - if(value.bufferView>=0){ + if(value.bufferView.HasValue){ f.Key("bufferView"); - f.Value(value.bufferView); + f.Value(value.bufferView.Value); } - if(value.byteOffset>=0){ + if(value.byteOffset.HasValue){ f.Key("byteOffset"); - f.Value(value.byteOffset); + f.Value(value.byteOffset.Value); } if(!string.IsNullOrEmpty(value.type)){ @@ -475,9 +475,9 @@ public static void Serialize_gltf_textures_ITEM(JsonFormatter f, glTFTexture val f.Value(value.sampler); } - if(value.source>=0){ + if(value.source.HasValue){ f.Key("source"); - f.Value(value.source); + f.Value(value.source.Value); } if(value.extensions!=null){ diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/UnityEngineCompatibility.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/UnityEngineCompatibility.cs deleted file mode 100644 index 3606ed0e3..000000000 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/UnityEngineCompatibility.cs +++ /dev/null @@ -1,52 +0,0 @@ -/// -/// Unity互換のためのダミー -/// - -#if UNITY_5_6_OR_NEWER -#else -using System; - -namespace UnityEngine -{ - public struct Vector2 - { - public float x; - public float y; - } - - public struct Vector3 : IEquatable - { - public float x; - public float y; - public float z; - - public static Vector3 zero => new Vector3(); - - public bool Equals(Vector3 other) - { - if (x != other.x) return false; - if (y != other.y) return false; - if (z != other.z) return false; - return true; - } - - public static bool operator ==(Vector3 lhs, Vector3 rhs) - { - return lhs.Equals(rhs); - } - - public static bool operator !=(Vector3 lhs, Vector3 rhs) - { - return !(lhs == rhs); - } - } - - public struct Vector4 - { - public float x; - public float y; - public float z; - public float w; - } -} -#endif diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/UnityEngineCompatibility.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/UnityEngineCompatibility.cs.meta deleted file mode 100644 index 520967fe6..000000000 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/UnityEngineCompatibility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 967f9ca5fbe35cc42b1b5a294958ab41 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/glTFBuffer.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/glTFBuffer.cs index 1721a95b8..99b5b8a4c 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/glTFBuffer.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/glTFBuffer.cs @@ -93,10 +93,10 @@ namespace UniGLTF public class glTFAccessor { [JsonSchema(Minimum = 0)] - public int bufferView = -1; + public int? bufferView; [JsonSchema(Minimum = 0, Dependencies = new string[] { "bufferView" })] - public int byteOffset; + public int? byteOffset; [JsonSchema(Required = true, EnumValues = new object[] { "SCALAR", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", "MAT4" }, EnumSerializationType = EnumSerializationType.AsString)] public string type; diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs index 7601237e6..c7dc033ae 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs @@ -58,8 +58,7 @@ namespace UniGLTF [JsonSchema(Minimum = 0)] public int sampler; - [JsonSchema(Minimum = 0)] - public int source; + public int? source; // empty schemas public glTFExtension extensions; diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs index 8c38c23a3..735a207ce 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs @@ -1,20 +1,22 @@ using System; using System.Linq; using System.Collections.Generic; +using System.Threading.Tasks; using UnityEngine; +using VRMShaders; namespace UniGLTF { public static class AnimationImporterUtil { - private enum TangentMode + public enum TangentMode { Linear, Constant, Cubicspline } - private static TangentMode GetTangentMode(string interpolation) + public static TangentMode GetTangentMode(string interpolation) { if (string.IsNullOrEmpty(interpolation) || interpolation == glTFAnimationTarget.Interpolations.LINEAR.ToString()) { @@ -34,13 +36,14 @@ namespace UniGLTF } } - private static void CalculateTanget(List keyframes, int current) + public static void CalculateTangent(List keyframes, int current) { int back = current - 1; if (back < 0) { return; } + if (current < keyframes.Count) { var rightTangent = (keyframes[current].value - keyframes[back].value) / (keyframes[current].time - keyframes[back].time); @@ -61,10 +64,10 @@ namespace UniGLTF { return new Quaternion(-rot.x, -rot.y, -rot.z, -rot.w); } - } public delegate float[] ReverseFunc(float[] current, float[] last); + public static void SetAnimationCurve( AnimationClip targetClip, string relativePath, @@ -89,6 +92,7 @@ namespace UniGLTF { last[3] = 1.0f; } + for (inputIndex = 0; inputIndex < input.Length; ++inputIndex) { var time = input[inputIndex]; @@ -101,6 +105,7 @@ namespace UniGLTF { value[i] = output[outputIndex + elementNum + i]; } + var reversed = reverse(value, last); last = reversed; for (int i = 0; i < keyframes.Length; i++) @@ -122,6 +127,7 @@ namespace UniGLTF { value[i] = output[outputIndex + i]; } + var reversed = reverse(value, last); last = reversed; @@ -134,7 +140,7 @@ namespace UniGLTF keyframes[i].Add(new Keyframe(time, reversed[i], 0, 0)); if (keyframes[i].Count > 0) { - CalculateTanget(keyframes[i], keyframes[i].Count - 1); + CalculateTangent(keyframes[i], keyframes[i].Count - 1); } } else if (tangentMode == TangentMode.Constant) @@ -185,7 +191,8 @@ namespace UniGLTF return string.Join("/", path); } - public static AnimationClip ConvertAnimationClip(GltfData data, glTFAnimation animation, IAxisInverter inverter, glTFNode root = null) + public static async Task ConvertAnimationClipAsync(GltfData data, glTFAnimation animation, + IAxisInverter inverter, IAwaitCaller awaitCaller, glTFNode root = null) { var clip = new AnimationClip(); clip.ClearCurves(); @@ -195,124 +202,150 @@ namespace UniGLTF foreach (var channel in animation.channels) { - var relativePath = RelativePathFrom(data.GLTF.nodes, root, data.GLTF.nodes[channel.target.node]); - switch (channel.target.path) + if (channel.target.node >= 0 && channel.target.node < data.GLTF.nodes.Count) { - case glTFAnimationTarget.PATH_TRANSLATION: - { - var sampler = animation.samplers[channel.sampler]; - var input = data.GetArrayFromAccessor(sampler.input); - var output = data.FlatternFloatArrayFromAccessor(sampler.output); + var relativePath = RelativePathFrom(data.GLTF.nodes, root, data.GLTF.nodes[channel.target.node]); + switch (channel.target.path) + { + case glTFAnimationTarget.PATH_TRANSLATION: + SetTranslationAnimationCurve(data, animation, inverter, channel, clip, relativePath); + break; + case glTFAnimationTarget.PATH_ROTATION: + SetRotationAnimationCurve(data, animation, inverter, channel, clip, relativePath); + break; + case glTFAnimationTarget.PATH_SCALE: + SetScaleAnimationCurve(data, animation, channel, clip, relativePath); + break; + case glTFAnimationTarget.PATH_WEIGHT: + SetBlendShapeAnimationCurve(data, animation, channel, clip, relativePath); + break; + default: + Debug.LogWarningFormat("unknown path: {0}", channel.target.path); + break; + } - AnimationImporterUtil.SetAnimationCurve( - clip, - relativePath, - new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }, - input.ToArray(), - output.ToArray(), - sampler.interpolation, - typeof(Transform), - (values, last) => - { - Vector3 temp = new Vector3(values[0], values[1], values[2]); - return inverter.InvertVector3(temp).ToArray(); - } - ); - } - break; - - case glTFAnimationTarget.PATH_ROTATION: - { - var sampler = animation.samplers[channel.sampler]; - var input = data.GetArrayFromAccessor(sampler.input); - var output = data.FlatternFloatArrayFromAccessor(sampler.output); - - AnimationImporterUtil.SetAnimationCurve( - clip, - relativePath, - new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }, - input.ToArray(), - output.ToArray(), - sampler.interpolation, - typeof(Transform), - (values, last) => - { - Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]); - Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]); - return AnimationImporterUtil.GetShortest(lastQuaternion, inverter.InvertQuaternion(currentQuaternion)).ToArray(); - } - ); - - clip.EnsureQuaternionContinuity(); - } - break; - - case glTFAnimationTarget.PATH_SCALE: - { - var sampler = animation.samplers[channel.sampler]; - var input = data.GetArrayFromAccessor(sampler.input); - var output = data.FlatternFloatArrayFromAccessor(sampler.output); - - AnimationImporterUtil.SetAnimationCurve( - clip, - relativePath, - new string[] { "localScale.x", "localScale.y", "localScale.z" }, - input.ToArray(), - output.ToArray(), - sampler.interpolation, - typeof(Transform), - (values, last) => values); - } - break; - - case glTFAnimationTarget.PATH_WEIGHT: - { - var node = data.GLTF.nodes[channel.target.node]; - var mesh = data.GLTF.meshes[node.mesh]; - var primitive = mesh.primitives.FirstOrDefault(); - var targets = primitive.targets; - - if (!gltf_mesh_extras_targetNames.TryGet(mesh, out List targetNames)) - { - throw new UniGLTFNotSupportedException("glTF BlendShape Animation. targetNames invalid."); - } - - var keyNames = targetNames - .Where(x => !string.IsNullOrEmpty(x)) - .Select(x => "blendShape." + x) - .ToArray(); - - var sampler = animation.samplers[channel.sampler]; - var input = data.GetArrayFromAccessor(sampler.input); - var output = data.GetArrayFromAccessor(sampler.output); - AnimationImporterUtil.SetAnimationCurve( - clip, - relativePath, - keyNames, - input.ToArray(), - output.ToArray(), - sampler.interpolation, - typeof(SkinnedMeshRenderer), - (values, last) => - { - for (int j = 0; j < values.Length; j++) - { - values[j] *= 100.0f; - } - return values; - }); - - } - break; - - default: - Debug.LogWarningFormat("unknown path: {0}", channel.target.path); - break; + await awaitCaller.NextFrameIfTimedOut(); + } + else + { + Debug.LogWarning($"ConvertAnimationClipAsync: channel.target.node: out of range: 0<[{channel.target.node}]<{data.GLTF.nodes.Count}"); } } + return clip; } + private static void SetTranslationAnimationCurve(GltfData data, glTFAnimation animation, IAxisInverter inverter, + glTFAnimationChannel channel, AnimationClip clip, string relativePath) + { + var sampler = animation.samplers[channel.sampler]; + var input = data.GetArrayFromAccessor(sampler.input); + var output = data.FlatternFloatArrayFromAccessor(sampler.output); + + SetAnimationCurve( + clip, + relativePath, + new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }, + input.ToArray(), + output.ToArray(), + sampler.interpolation, + typeof(Transform), + (values, last) => + { + Vector3 temp = new Vector3(values[0], values[1], values[2]); + return inverter.InvertVector3(temp).ToArray(); + } + ); + } + + private static void SetRotationAnimationCurve(GltfData data, glTFAnimation animation, IAxisInverter inverter, + glTFAnimationChannel channel, AnimationClip clip, string relativePath) + { + var sampler = animation.samplers[channel.sampler]; + var input = data.GetArrayFromAccessor(sampler.input); + var output = data.FlatternFloatArrayFromAccessor(sampler.output); + + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }, + input.ToArray(), + output.ToArray(), + sampler.interpolation, + typeof(Transform), + (values, last) => + { + Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]); + Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]); + return AnimationImporterUtil + .GetShortest(lastQuaternion, inverter.InvertQuaternion(currentQuaternion)) + .ToArray(); + } + ); + + clip.EnsureQuaternionContinuity(); + } + + + private static void SetScaleAnimationCurve(GltfData data, glTFAnimation animation, glTFAnimationChannel channel, + AnimationClip clip, string relativePath) + { + var sampler = animation.samplers[channel.sampler]; + var input = data.GetArrayFromAccessor(sampler.input); + var output = data.FlatternFloatArrayFromAccessor(sampler.output); + + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + new string[] { "localScale.x", "localScale.y", "localScale.z" }, + input.ToArray(), + output.ToArray(), + sampler.interpolation, + typeof(Transform), + (values, last) => values); + } + + private static void SetBlendShapeAnimationCurve(GltfData data, glTFAnimation animation, + glTFAnimationChannel channel, + AnimationClip clip, string relativePath) + { + var node = data.GLTF.nodes[channel.target.node]; + var mesh = data.GLTF.meshes[node.mesh]; + var primitive = mesh.primitives.FirstOrDefault(); + var targets = primitive.targets; + + if (!gltf_mesh_extras_targetNames.TryGet(mesh, out List targetNames)) + { + throw new UniGLTFNotSupportedException("glTF BlendShape Animation. targetNames invalid."); + } + + var keyNames = targetNames + .Where(x => !string.IsNullOrEmpty(x)) + .Select(x => "blendShape." + x) + .ToArray(); + + var sampler = animation.samplers[channel.sampler]; + var input = data.GetArrayFromAccessor(sampler.input); + var output = data.GetArrayFromAccessor(sampler.output); + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + keyNames, + input.ToArray(), + output.ToArray(), + sampler.interpolation, + typeof(SkinnedMeshRenderer), + (values, last) => + { + for (int j = 0; j < values.Length; j++) + { + values[j] *= 100.0f; + } + + return values; + }); + } + public static IEnumerable EnumerateSubAssetKeys(glTF gltf) { foreach (var gltfAnimation in gltf.animations) @@ -321,4 +354,4 @@ namespace UniGLTF } } } -} +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BlendShapeTargetNameLocationFlags.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BlendShapeTargetNameLocationFlags.cs new file mode 100644 index 000000000..ef71a92a7 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BlendShapeTargetNameLocationFlags.cs @@ -0,0 +1,19 @@ +using System; + +namespace UniGLTF +{ + /// + /// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes + /// + /// See Implementation Note about `mesh.extras.targetNames` + /// + [Flags] + public enum BlendShapeTargetNameLocationFlags + { + None = 0, + Mesh = 1, + Primitives = 2, + + Both = Mesh | Primitives, + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BlendShapeTargetNameLocationFlags.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BlendShapeTargetNameLocationFlags.cs.meta new file mode 100644 index 000000000..80e72f45c --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BlendShapeTargetNameLocationFlags.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 050edaae24c5b4e45b702dd150deee8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BufferAccessor.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BufferAccessor.cs index 6ead44a56..faf01bfe1 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BufferAccessor.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/BufferAccessor.cs @@ -318,7 +318,6 @@ namespace UniGLTF componentType = (glComponentType)ComponentType, type = AccessorType.ToString(), count = Count, - byteOffset = -1, sparse = new glTFSparse { count = sparseValuesWithIndex.Count, diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Byte3.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Byte3.cs new file mode 100644 index 000000000..6b79293c6 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Byte3.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.InteropServices; + +namespace UniGLTF +{ + [Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)] + public readonly struct Byte3 : IEquatable + { + public readonly byte x; + public readonly byte y; + public readonly byte z; + public Byte3(byte _x, byte _y, byte _z) + { + x = _x; + y = _y; + z = _z; + } + + public bool Equals(Byte3 other) + { + return x == other.x && y == other.y && z == other.z; + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Byte3.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Byte3.cs.meta new file mode 100644 index 000000000..8f28a2d50 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Byte3.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3aeebc68fc223f47801acd181ed116a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ExportingGltfData.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ExportingGltfData.cs index b5d535cc5..1788c7cd1 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ExportingGltfData.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ExportingGltfData.cs @@ -115,7 +115,7 @@ namespace UniGLTF var accessorIndex = Gltf.accessors.Count; Gltf.accessors.Add(new glTFAccessor { - byteOffset = 0, + byteOffset = default, componentType = glTFExtensions.GetComponentType(), type = glTFExtensions.GetAccessorType(), count = accessorCount, diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs index 899c6bde7..1a8103178 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs @@ -166,7 +166,28 @@ namespace UniGLTF NativeArray GetTypedFromAccessor(glTFAccessor accessor, glTFBufferView view) where T : struct { var bytes = GetBytesFromBufferView(view); - return bytes.GetSubArray(accessor.byteOffset, bytes.Length - accessor.byteOffset).Reinterpret(1).GetSubArray(0, accessor.count); + if (view.byteStride == 0 || view.byteStride == accessor.GetStride()) + { + // planar layout + return bytes.GetSubArray( + accessor.byteOffset.GetValueOrDefault(), + accessor.CalcByteSize()).Reinterpret(1); + } + else + { + // interleaved layout + // copy interleaved vertex to planar array + var src = GetBytesFromBufferView(view); + var dst = NativeArrayManager.CreateNativeArray(accessor.count); + var offset = accessor.byteOffset.GetValueOrDefault(); + var size = Marshal.SizeOf(); + for (int i = 0; i < accessor.count; ++i, offset += view.byteStride) + { + var values = src.GetSubArray(offset, size).Reinterpret(1); + dst[i] = values[0]; + } + return dst; + } } /// @@ -208,8 +229,8 @@ namespace UniGLTF public BufferAccessor GetIndicesFromAccessorIndex(int accessorIndex) { var accessor = GLTF.accessors[accessorIndex]; - var view = GLTF.bufferViews[accessor.bufferView]; - return GetIntIndicesFromView(view, accessor.count, accessor.byteOffset, accessor.componentType); + var view = GLTF.bufferViews[accessor.bufferView.Value]; + return GetIntIndicesFromView(view, accessor.count, accessor.byteOffset.GetValueOrDefault(), accessor.componentType); } public NativeArray GetArrayFromAccessor(int accessorIndex) where T : struct @@ -218,8 +239,8 @@ namespace UniGLTF if (vertexAccessor.count <= 0) return NativeArrayManager.CreateNativeArray(0); - var result = (vertexAccessor.bufferView != -1) - ? GetTypedFromAccessor(vertexAccessor, GLTF.bufferViews[vertexAccessor.bufferView]) + var result = (vertexAccessor.bufferView.HasValidIndex()) + ? GetTypedFromAccessor(vertexAccessor, GLTF.bufferViews[vertexAccessor.bufferView.Value]) : NativeArrayManager.CreateNativeArray(vertexAccessor.count) ; @@ -277,11 +298,11 @@ namespace UniGLTF var bufferCount = vertexAccessor.count * vertexAccessor.TypeCount; NativeArray result = default; - if (vertexAccessor.bufferView != -1) + if (vertexAccessor.bufferView.HasValidIndex()) { - var view = GLTF.bufferViews[vertexAccessor.bufferView]; + var view = GLTF.bufferViews[vertexAccessor.bufferView.Value]; var segment = GetBytesFromBuffer(view.buffer); - result = segment.GetSubArray(view.byteOffset + vertexAccessor.byteOffset, vertexAccessor.count * 4 * vertexAccessor.TypeCount).Reinterpret(1); + result = segment.GetSubArray(view.byteOffset + vertexAccessor.byteOffset.GetValueOrDefault(), vertexAccessor.count * 4 * vertexAccessor.TypeCount).Reinterpret(1); } else { @@ -333,6 +354,25 @@ namespace UniGLTF return result; } + static string GuessMimeFromUri(string uri) + { + if (string.IsNullOrEmpty(uri)) + { + return null; + } + var ext = System.IO.Path.GetExtension(uri).ToLowerInvariant(); + switch (ext) + { + case ".png": + return "image/png"; + case ".jpg": + case ".jpeg": + return "image/jpeg"; + default: + return null; + } + } + public (NativeArray binary, string mimeType)? GetBytesFromImage(int imageIndex) { if (imageIndex < 0 || imageIndex >= GLTF.images.Count) return default; @@ -340,11 +380,13 @@ namespace UniGLTF var image = GLTF.images[imageIndex]; if (string.IsNullOrEmpty(image.uri)) { + // use bufferView(glb) return (GetBytesFromBufferView(image.bufferView), image.mimeType); } else { - return (GetBytesFromUri(image.uri), image.mimeType); + // use uri(gltf) + return (GetBytesFromUri(image.uri), image.mimeType ?? GuessMimeFromUri(image.uri)); } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfExportSettings.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfExportSettings.cs index 1407cebfd..a82686460 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfExportSettings.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfExportSettings.cs @@ -29,7 +29,7 @@ namespace UniGLTF public bool ExportOnlyBlendShapePosition; /// - /// tangent を出力する + /// Export TANGENT /// public bool ExportTangents #if GLTF_EXPORT_TANGENTS @@ -38,9 +38,9 @@ namespace UniGLTF ; /// - /// Keep VertexColor + /// Export COLOR_0 /// - public bool KeepVertexColor; + public bool ExportVertexColor; /// /// https://github.com/vrm-c/UniVRM/issues/1582 @@ -48,5 +48,10 @@ namespace UniGLTF /// Allowed hide flags for MeshFilters to be exported /// public HideFlags MeshFilterAllowedHideFlags = HideFlags.None; + + /// + /// Export TEXCOORD_1 + /// + public bool ExportUvSecondary; } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfJsonUtil.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfJsonUtil.cs index c96e33e84..3ee9c9cf6 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfJsonUtil.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfJsonUtil.cs @@ -9,7 +9,7 @@ namespace UniGLTF { public static class GltfJsonUtil { - const string EXTENSION_USED_KEY = "extensionUsed"; + public const string EXTENSION_USED_KEY = "extensionsUsed"; /// /// JsonPath を 再帰的に列挙する @@ -96,14 +96,14 @@ namespace UniGLTF return false; } - static void CopyJson(IReadOnlyList extensionUsed, JsonFormatter dst, JsonNode src, int level) + static void CopyJson(IReadOnlyList extensionsUsed, JsonFormatter dst, JsonNode src, int level) { if (src.IsArray()) { dst.BeginList(); foreach (var v in src.ArrayItems()) { - CopyJson(extensionUsed, dst, v, level + 1); + CopyJson(extensionsUsed, dst, v, level + 1); } dst.EndList(); } @@ -119,7 +119,7 @@ namespace UniGLTF var key = kv.Key.GetString(); if (key == EXTENSION_USED_KEY) { - if (extensionUsed.Count == 0) + if (extensionsUsed.Count == 0) { // skip } @@ -128,7 +128,7 @@ namespace UniGLTF dst.Key(key); // replace dst.BeginList(); - foreach (var ex in extensionUsed) + foreach (var ex in extensionsUsed) { dst.Value(ex); } @@ -140,15 +140,15 @@ namespace UniGLTF else { dst.Key(key); - CopyJson(extensionUsed, dst, kv.Value, level + 1); + CopyJson(extensionsUsed, dst, kv.Value, level + 1); } } - if (!done && level == 0 && extensionUsed.Count > 0) + if (!done && level == 0 && extensionsUsed.Count > 0) { // add dst.Key(EXTENSION_USED_KEY); dst.BeginList(); - foreach (var ex in extensionUsed) + foreach (var ex in extensionsUsed) { dst.Value(ex); } @@ -162,7 +162,7 @@ namespace UniGLTF foreach (var kv in src.ObjectItems()) { dst.Key(kv.Key.GetUtf8String()); - CopyJson(extensionUsed, dst, kv.Value, level + 1); + CopyJson(extensionsUsed, dst, kv.Value, level + 1); } dst.EndMap(); } @@ -177,7 +177,7 @@ namespace UniGLTF /// /// https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/glTF.schema.json /// - /// extensionUsed の更新を各拡張自身にやらせるのは無駄だし、手動でコントロールするのも間違いの元である。 + /// extensionsUsed の更新を各拡張自身にやらせるのは無駄だし、手動でコントロールするのも間違いの元である。 /// 完成品の JSON から後付けで作ることにした。 /// /// * Exporter しか使わない処理なので、GC, 処理速度は気にしてない diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs index 881f74b0a..dd2238c18 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Threading.Tasks; using UnityEngine; @@ -14,12 +15,37 @@ namespace UniGLTF throw new FileNotFoundException(path); } - Debug.LogFormat("{0}", path); + if (awaitCaller == null) + { + Debug.LogWarning("GltfUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller."); + awaitCaller = new ImmediateCaller(); + } + using (GltfData data = new AutoGltfFileParser(path).Parse()) using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: materialGenerator)) { return await loader.LoadAsync(awaitCaller); } } + + public static async Task LoadBytesAsync(string path, byte[] bytes, IAwaitCaller awaitCaller = null, IMaterialDescriptorGenerator materialGenerator = null) + { + if (bytes == null) + { + throw new ArgumentNullException("bytes"); + } + + if (awaitCaller == null) + { + Debug.LogWarning("GltfUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller."); + awaitCaller = new ImmediateCaller(); + } + + using (GltfData data = new GlbBinaryParser(bytes, path).Parse()) + using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: materialGenerator)) + { + return await loader.LoadAsync(awaitCaller); + } + } } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 54bf0874f..ae0d35d5d 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -18,6 +18,8 @@ namespace UniGLTF public TextureFactory TextureFactory { get; } public MaterialFactory MaterialFactory { get; } public AnimationClipFactory AnimationClipFactory { get; } + public bool LoadAnimation { get; set; } = true; + public IReadOnlyDictionary ExternalObjectMap; /// @@ -36,7 +38,7 @@ namespace UniGLTF { Data = data; TextureDescriptorGenerator = new GltfTextureDescriptorGenerator(Data); - MaterialDescriptorGenerator = materialGenerator ?? new GltfMaterialDescriptorGenerator(); + MaterialDescriptorGenerator = materialGenerator ?? new BuiltInGltfMaterialDescriptorGenerator(); ExternalObjectMap = externalObjectMap ?? new Dictionary(); textureDeserializer = textureDeserializer ?? new UnityTextureDeserializer(); @@ -113,10 +115,13 @@ namespace UniGLTF await LoadGeometryAsync(awaitCaller, MeasureTime); - using (MeasureTime("AnimationImporter")) + if (LoadAnimation) { - await LoadAnimationAsync(awaitCaller); - await SetupAnimationsAsync(awaitCaller); + using (MeasureTime("AnimationImporter")) + { + await LoadAnimationAsync(awaitCaller); + await SetupAnimationsAsync(awaitCaller); + } } await OnLoadHierarchy(awaitCaller, MeasureTime); @@ -131,10 +136,7 @@ namespace UniGLTF foreach (var (key, gltfAnimation) in Enumerable.Zip(AnimationImporterUtil.EnumerateSubAssetKeys(GLTF), GLTF.animations, (x, y) => (x, y))) { await AnimationClipFactory.LoadAnimationClipAsync(key, () => - { - var clip = AnimationImporterUtil.ConvertAnimationClip(Data, gltfAnimation, InvertAxis.Create()); - return Task.FromResult(clip); - }); + AnimationImporterUtil.ConvertAnimationClipAsync(Data, gltfAnimation, InvertAxis.Create(), awaitCaller)); } await awaitCaller.NextFrame(); @@ -167,20 +169,32 @@ namespace UniGLTF { var inverter = InvertAxis.Create(); - var meshImporter = new MeshImporter(); if (GLTF.meshes.Count > 0) { - for (var i = 0; i < GLTF.meshes.Count; ++i) + var maxVertexCapacity = 0; + var maxIndexCapacity = 0; + foreach (var gltfMesh in GLTF.meshes) { - var index = i; - using (MeasureTime("ReadMesh")) + var (vertexCapacity, indexCapacity) = MeshData.GetCapacity(Data, gltfMesh); + maxVertexCapacity = Math.Max(maxVertexCapacity, vertexCapacity); + maxIndexCapacity = Math.Max(maxIndexCapacity, indexCapacity); + } + + // 一番長い VertexBuffer, IndexBuffer の長さでNativeArray を確保し、 + // 最後に Dispose する + using (var meshData = new MeshData(maxVertexCapacity, maxIndexCapacity)) + { + for (var i = 0; i < GLTF.meshes.Count; ++i) { - var meshContext = await awaitCaller.Run(() => meshImporter.ReadMesh(Data, index, inverter)); - var meshWithMaterials = await BuildMeshAsync(awaitCaller, MeasureTime, meshContext, index); + var index = i; + var gltfMesh = Data.GLTF.meshes[index]; + + using (MeasureTime("ReadMesh")) + await awaitCaller.Run(() => meshData.LoadFromGltf(Data, index, inverter)); + var meshWithMaterials = await BuildMeshAsync(awaitCaller, MeasureTime, meshData, index); Meshes.Add(meshWithMaterials); } } - await awaitCaller.NextFrame(); } @@ -188,12 +202,13 @@ namespace UniGLTF { using (MeasureTime("LoadNodes")) { - Profiler.BeginSample("ImporterContext.LoadNodes"); for (var i = 0; i < GLTF.nodes.Count; i++) { + await awaitCaller.NextFrameIfTimedOut(); + Profiler.BeginSample("ImporterContext.LoadNodes"); Nodes.Add(NodeImporter.ImportNode(GLTF.nodes[i], i).transform); + Profiler.EndSample(); } - Profiler.EndSample(); } await awaitCaller.NextFrame(); @@ -204,12 +219,13 @@ namespace UniGLTF var nodes = new List(); if (Nodes.Count > 0) { - Profiler.BeginSample("NodeImporter.BuildHierarchy"); for (var i = 0; i < Nodes.Count; ++i) { + await awaitCaller.NextFrameIfTimedOut(); + Profiler.BeginSample("NodeImporter.BuildHierarchy"); nodes.Add(NodeImporter.BuildHierarchy(GLTF, i, Nodes, Meshes)); + Profiler.EndSample(); } - Profiler.EndSample(); await awaitCaller.NextFrame(); } @@ -219,12 +235,13 @@ namespace UniGLTF // skinning if (nodes.Count > 0) { - Profiler.BeginSample("NodeImporter.SetupSkinning"); for (var i = 0; i < nodes.Count; ++i) { + await awaitCaller.NextFrameIfTimedOut(); + Profiler.BeginSample("NodeImporter.SetupSkinning"); NodeImporter.SetupSkinning(Data, nodes, i, inverter); + Profiler.EndSample(); } - Profiler.EndSample(); await awaitCaller.NextFrame(); } @@ -256,6 +273,7 @@ namespace UniGLTF var textures = TextureDescriptorGenerator.Get().GetEnumerable(); foreach (var param in textures) { + await awaitCaller.NextFrameIfTimedOut(); var tex = await TextureFactory.GetTextureAsync(param, awaitCaller); } } @@ -271,15 +289,16 @@ namespace UniGLTF { // no material. work around. // TODO: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#default-material - var param = MaterialDescriptor.Default; - var material = await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync, awaitCaller); + var param = MaterialDescriptorGenerator.GetGltfDefault(); + await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync, awaitCaller); } else { for (int i = 0; i < Data.GLTF.materials.Count; ++i) { + await awaitCaller.NextFrameIfTimedOut(); var param = MaterialDescriptorGenerator.Get(Data, i); - var material = await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync, awaitCaller); + await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync, awaitCaller); } } } @@ -290,11 +309,11 @@ namespace UniGLTF return Task.FromResult(null); } - async Task BuildMeshAsync(IAwaitCaller awaitCaller, Func MeasureTime, MeshContext x, int i) + async Task BuildMeshAsync(IAwaitCaller awaitCaller, Func MeasureTime, MeshData meshData, int i) { using (MeasureTime("BuildMesh")) { - var meshWithMaterials = await MeshImporter.BuildMeshAsync(awaitCaller, MaterialFactory.GetMaterial, x); + var meshWithMaterials = await MeshUploader.BuildMeshAndUploadAsync(awaitCaller, meshData, MaterialFactory.GetMaterial); var mesh = meshWithMaterials.Mesh; // mesh name @@ -316,6 +335,17 @@ namespace UniGLTF #region Imported protected GameObject Root; public List Nodes = new List(); + protected bool TryGetNode(int index, out Transform node) + { + if (index < 0 || index >= Nodes.Count) + { + Debug.LogWarning($"nodes[{index}] is not found !"); + node = default; + return false; + } + node = Nodes[index]; + return true; + } public List Meshes = new List(); #endregion @@ -327,7 +357,7 @@ namespace UniGLTF { foreach (var x in Meshes) { - UnityObjectDestoyer.DestroyRuntimeOrEditor(x.Mesh); + UnityObjectDestroyer.DestroyRuntimeOrEditor(x.Mesh); } Meshes.Clear(); diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs index 48b488e35..e804697f5 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/ImporterContextExtensions.cs @@ -22,9 +22,10 @@ namespace UniGLTF throw new AggregateException(task.Exception); } -#if VRM_DEVELOP - Debug.Log($"{self.Data.TargetPath}: {meassureTime.GetSpeedLog()}"); -#endif + if (Symbols.VRM_DEVELOP) + { + Debug.Log($"{self.Data.TargetPath}: {meassureTime.GetSpeedLog()}"); + } return task.Result; } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP.meta new file mode 100644 index 000000000..3b42e31e0 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6acece60316c4e7ba14451e4cd8b3e71 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export.meta new file mode 100644 index 000000000..bf58e9b5c --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4f05bf2dc2fe432da17c137e3579d67b +timeCreated: 1667543489 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/BuiltInGltfMaterialExporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/BuiltInGltfMaterialExporter.cs new file mode 100644 index 000000000..fe42f516d --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/BuiltInGltfMaterialExporter.cs @@ -0,0 +1,47 @@ +using UnityEngine; +using VRMShaders; + +namespace UniGLTF +{ + public class BuiltInGltfMaterialExporter : IMaterialExporter + { + public static readonly string[] SupportedShaderNames = + { + BuiltInStandardMaterialExporter.TargetShaderName, + BuiltInUniUnlitMaterialExporter.TargetShaderName, + "Unlit/Color", + "Unlit/Texture", + "Unlit/Transparent", + "Unlit/Transparent Cutout", + }; + + public glTFMaterial ExportMaterial(Material m, ITextureExporter textureExporter, GltfExportSettings settings) + { + glTFMaterial dst; + switch (m.shader.name) + { + case BuiltInStandardMaterialExporter.TargetShaderName: + if (BuiltInStandardMaterialExporter.TryExportMaterial(m, textureExporter, out dst)) return dst; + break; + case BuiltInUniUnlitMaterialExporter.TargetShaderName: + if (BuiltInUniUnlitMaterialExporter.TryExportMaterial(m, textureExporter, out dst)) return dst; + break; + case "Unlit/Color": + if (BuiltInGenericUnlitMaterialExporter.TryExportMaterial(m, glTFBlendMode.OPAQUE, textureExporter, out dst)) return dst; + break; + case "Unlit/Texture": + if (BuiltInGenericUnlitMaterialExporter.TryExportMaterial(m, glTFBlendMode.OPAQUE, textureExporter, out dst)) return dst; + break; + case "Unlit/Transparent": + if (BuiltInGenericUnlitMaterialExporter.TryExportMaterial(m, glTFBlendMode.BLEND, textureExporter, out dst)) return dst; + break; + case "Unlit/Transparent Cutout": + if (BuiltInGenericUnlitMaterialExporter.TryExportMaterial(m, glTFBlendMode.MASK, textureExporter, out dst)) return dst; + break; + } + + Debug.Log($"Material `{m.name}` fallbacks."); + return BuiltInFallbackMaterialExporter.ExportMaterial(m, textureExporter); + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/BuiltInGltfMaterialExporter.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/BuiltInGltfMaterialExporter.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials.meta new file mode 100644 index 000000000..d0444b636 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8e01e754e0a34a269004b8b4643c0612 +timeCreated: 1667543678 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInFallbackMaterialExporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInFallbackMaterialExporter.cs new file mode 100644 index 000000000..73e093d76 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInFallbackMaterialExporter.cs @@ -0,0 +1,41 @@ +using System; +using UnityEngine; +using VRMShaders; +using ColorSpace = VRMShaders.ColorSpace; + +namespace UniGLTF +{ + /// + /// 非対応のシェーダでも、baseColor だけ読み取ったマテリアルにする. + /// + public static class BuiltInFallbackMaterialExporter + { + private const string ColorPropertyName = "_Color"; + private const string ColorTexturePropertyName = "_MainTex"; + + public static glTFMaterial ExportMaterial(Material src, ITextureExporter textureExporter) + { + var dst = new glTFMaterial + { + name = src.name, + pbrMetallicRoughness = new glTFPbrMetallicRoughness(), + }; + + if (src.HasProperty(ColorPropertyName)) + { + dst.pbrMetallicRoughness.baseColorFactor = src.GetColor(ColorPropertyName).ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); + } + + if (src.HasProperty(ColorTexturePropertyName) && src.GetTexture(ColorTexturePropertyName) != null) + { + dst.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo() + { + index = textureExporter.RegisterExportingAsSRgb(src.GetTexture(ColorTexturePropertyName), false), + }; + GltfMaterialExportUtils.ExportTextureTransform(src, dst.pbrMetallicRoughness.baseColorTexture, ColorTexturePropertyName); + } + + return dst; + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInFallbackMaterialExporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInFallbackMaterialExporter.cs.meta new file mode 100644 index 000000000..274b1ebd8 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInFallbackMaterialExporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 983277a982364497b7491610ac4868f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInGenericUnlitMaterialExporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInGenericUnlitMaterialExporter.cs new file mode 100644 index 000000000..2692b32af --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInGenericUnlitMaterialExporter.cs @@ -0,0 +1,72 @@ +using System; +using UnityEngine; +using VRMShaders; +using ColorSpace = VRMShaders.ColorSpace; + +namespace UniGLTF +{ + /// + /// Built-in RP で一般的に用いられる Unlit Shader をエクスポートすることを試みる。 + /// + public static class BuiltInGenericUnlitMaterialExporter + { + private const string ColorFactorPropertyName = "_Color"; + private const string ColorTexturePropertyName = "_MainTex"; + private const string CutoffPropertyName = "_Cutoff"; + + public static bool TryExportMaterial(Material src, glTFBlendMode blendMode, ITextureExporter textureExporter, out glTFMaterial dst) + { + dst = glTF_KHR_materials_unlit.CreateDefault(); + dst.name = src.name; + + ExportRenderingSettings(src, blendMode, dst); + ExportBaseColor(src, blendMode, textureExporter, dst); + + return true; + } + + private static void ExportRenderingSettings(Material src, glTFBlendMode blendMode, glTFMaterial dst) + { + switch (blendMode) + { + case glTFBlendMode.OPAQUE: + dst.alphaMode = glTFBlendMode.OPAQUE.ToString(); + break; + case glTFBlendMode.MASK: + dst.alphaMode = glTFBlendMode.MASK.ToString(); + dst.alphaCutoff = src.GetFloat(CutoffPropertyName); + break; + case glTFBlendMode.BLEND: + dst.alphaMode = glTFBlendMode.BLEND.ToString(); + break; + default: + throw new ArgumentOutOfRangeException(nameof(blendMode), blendMode, null); + } + } + + private static void ExportBaseColor(Material src, glTFBlendMode blendMode, ITextureExporter textureExporter, glTFMaterial dst) + { + if (src.HasProperty(ColorFactorPropertyName)) + { + dst.pbrMetallicRoughness.baseColorFactor = src.GetColor(ColorFactorPropertyName).ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); + } + + if (src.HasProperty(ColorTexturePropertyName)) + { + // Don't export alpha channel if material was OPAQUE + var unnecessaryAlpha = blendMode == glTFBlendMode.OPAQUE; + + var index = textureExporter.RegisterExportingAsSRgb(src.GetTexture(ColorTexturePropertyName), !unnecessaryAlpha); + if (index != -1) + { + dst.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo() + { + index = index, + }; + + GltfMaterialExportUtils.ExportTextureTransform(src, dst.pbrMetallicRoughness.baseColorTexture, ColorTexturePropertyName); + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInGenericUnlitMaterialExporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInGenericUnlitMaterialExporter.cs.meta new file mode 100644 index 000000000..4de48184d --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInGenericUnlitMaterialExporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c4ed66ba3f44b28a1d303cdf073dc2b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInStandardMaterialExporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInStandardMaterialExporter.cs new file mode 100644 index 000000000..d0dd69208 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInStandardMaterialExporter.cs @@ -0,0 +1,217 @@ +using System; +using System.Linq; +using UnityEngine; +using VRMShaders; +using ColorSpace = VRMShaders.ColorSpace; + +namespace UniGLTF +{ + public static class BuiltInStandardMaterialExporter + { + public const string TargetShaderName = "Standard"; + + private const string ColorTexturePropertyName = "_MainTex"; + private const string MetallicGlossTexturePropertyName = "_MetallicGlossMap"; + private const string NormalTexturePropertyName = "_BumpMap"; + private const string EmissionTexturePropertyName = "_EmissionMap"; + private const string OcclusionTexturePropertyName = "_OcclusionMap"; + + public static bool TryExportMaterial(Material src, ITextureExporter textureExporter, out glTFMaterial dst) + { + if (src.shader.name != TargetShaderName) + { + dst = default; + return false; + } + + dst = new glTFMaterial + { + name = src.name, + pbrMetallicRoughness = new glTFPbrMetallicRoughness(), + }; + + ExportRenderingSettings(src, dst); + ExportBaseColor(src, textureExporter, dst); + ExportEmission(src, textureExporter, dst); + ExportNormal(src, textureExporter, dst); + ExportOcclusionMetallicRoughness(src, textureExporter, dst); + + return true; + } + + private static void ExportRenderingSettings(Material src, glTFMaterial dst) + { + switch (src.GetTag("RenderType", true)) + { + case "Transparent": + dst.alphaMode = glTFBlendMode.BLEND.ToString(); + break; + + case "TransparentCutout": + dst.alphaMode = glTFBlendMode.MASK.ToString(); + dst.alphaCutoff = src.GetFloat("_Cutoff"); + break; + + default: + dst.alphaMode = glTFBlendMode.OPAQUE.ToString(); + break; + } + } + + private static void ExportBaseColor(Material src, ITextureExporter textureExporter, glTFMaterial dst) + { + if (src.HasProperty("_Color")) + { + dst.pbrMetallicRoughness.baseColorFactor = src.GetColor("_Color").ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); + } + + if (src.HasProperty(ColorTexturePropertyName)) + { + // Don't export alpha channel if material was OPAQUE + var unnecessaryAlpha = string.Equals(dst.alphaMode, "OPAQUE", StringComparison.Ordinal); + + var index = textureExporter.RegisterExportingAsSRgb(src.GetTexture(ColorTexturePropertyName), !unnecessaryAlpha); + if (index != -1) + { + dst.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo() + { + index = index, + }; + + ExportMainTextureTransform(src, dst.pbrMetallicRoughness.baseColorTexture); + } + } + } + + /// + /// Occlusion, Metallic, Roughness + /// + private static void ExportOcclusionMetallicRoughness(Material src, ITextureExporter textureExporter, glTFMaterial dst) + { + Texture metallicSmoothTexture = default; + float smoothness = 1.0f; + + var textuerNames = src.GetTexturePropertyNames(); + if (textuerNames.Contains(MetallicGlossTexturePropertyName)) + { + if (src.HasProperty("_GlossMapScale")) + { + smoothness = src.GetFloat("_GlossMapScale"); + } + metallicSmoothTexture = src.GetTexture(MetallicGlossTexturePropertyName); + } + + Texture occlusionTexture = default; + var occlusionStrength = 1.0f; + if (textuerNames.Contains(OcclusionTexturePropertyName)) + { + occlusionTexture = src.GetTexture(OcclusionTexturePropertyName); + if (occlusionTexture != null && src.HasProperty("_OcclusionStrength")) + { + occlusionStrength = src.GetFloat("_OcclusionStrength"); + } + } + + int index = textureExporter.RegisterExportingAsCombinedGltfPbrParameterTextureFromUnityStandardTextures(metallicSmoothTexture, smoothness, occlusionTexture); + + if (index != -1 && metallicSmoothTexture != null) + { + dst.pbrMetallicRoughness.metallicRoughnessTexture = + new glTFMaterialMetallicRoughnessTextureInfo() + { + index = index, + }; + ExportMainTextureTransform(src, dst.pbrMetallicRoughness.metallicRoughnessTexture); + + // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. + dst.pbrMetallicRoughness.metallicFactor = 1.0f; + dst.pbrMetallicRoughness.roughnessFactor = 1.0f; + } + else + { + if (src.HasProperty("_Metallic")) + { + dst.pbrMetallicRoughness.metallicFactor = src.GetFloat("_Metallic"); + } + + if (src.HasProperty("_Glossiness")) + { + dst.pbrMetallicRoughness.roughnessFactor = 1.0f - src.GetFloat("_Glossiness"); + } + } + + if (index != -1 && occlusionTexture != null) + { + dst.occlusionTexture = new glTFMaterialOcclusionTextureInfo() + { + index = index, + strength = occlusionStrength, + }; + ExportMainTextureTransform(src, dst.occlusionTexture); + } + } + + private static void ExportNormal(Material src, ITextureExporter textureExporter, glTFMaterial dst) + { + if (src.HasProperty(NormalTexturePropertyName)) + { + var index = textureExporter.RegisterExportingAsNormal(src.GetTexture(NormalTexturePropertyName)); + if (index != -1) + { + dst.normalTexture = new glTFMaterialNormalTextureInfo() + { + index = index, + }; + + ExportMainTextureTransform(src, dst.normalTexture); + } + + if (index != -1 && src.HasProperty("_BumpScale")) + { + dst.normalTexture.scale = src.GetFloat("_BumpScale"); + } + } + } + + private static void ExportEmission(Material src, ITextureExporter textureExporter, glTFMaterial dst) + { + if (src.IsKeywordEnabled("_EMISSION") == false) + { + return; + } + + if (src.HasProperty("_EmissionColor")) + { + var color = src.GetColor("_EmissionColor"); + // NOTE: Built-in RP Standard shader's emission color is in gamma color space. + var linearFactor = color.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear); + var maxComponent = linearFactor.Max(); + if (maxComponent > 1) + { + linearFactor = linearFactor.Select(x => x / maxComponent).ToArray(); + UniGLTF.glTF_KHR_materials_emissive_strength.Serialize(ref dst.extensions, maxComponent); + } + dst.emissiveFactor = linearFactor; + } + + if (src.HasProperty(EmissionTexturePropertyName)) + { + var index = textureExporter.RegisterExportingAsSRgb(src.GetTexture(EmissionTexturePropertyName), needsAlpha: false); + if (index != -1) + { + dst.emissiveTexture = new glTFMaterialEmissiveTextureInfo() + { + index = index, + }; + + ExportMainTextureTransform(src, dst.emissiveTexture); + } + } + } + + private static void ExportMainTextureTransform(Material src, glTFTextureInfo targetTextureInfo) + { + GltfMaterialExportUtils.ExportTextureTransform(src, targetTextureInfo, ColorTexturePropertyName); + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInStandardMaterialExporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInStandardMaterialExporter.cs.meta new file mode 100644 index 000000000..14cf5d10b --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInStandardMaterialExporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ec789661012740afbe8b5422aadc5fa0 +timeCreated: 1667399599 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInUniUnlitMaterialExporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInUniUnlitMaterialExporter.cs new file mode 100644 index 000000000..c4499e416 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInUniUnlitMaterialExporter.cs @@ -0,0 +1,83 @@ +using System; +using UniGLTF.UniUnlit; +using UnityEngine; +using VRMShaders; +using ColorSpace = VRMShaders.ColorSpace; + +namespace UniGLTF +{ + public static class BuiltInUniUnlitMaterialExporter + { + public const string TargetShaderName = UniUnlit.UniUnlitUtil.ShaderName; + + public static bool TryExportMaterial(Material src, ITextureExporter textureExporter, out glTFMaterial dst) + { + if (src.shader.name != TargetShaderName) + { + dst = default; + return false; + } + + dst = glTF_KHR_materials_unlit.CreateDefault(); + dst.name = src.name; + + ExportRenderingSettings(src, dst); + ExportBaseColor(src, textureExporter, dst); + + return true; + } + + private static void ExportRenderingSettings(Material src, glTFMaterial dst) + { + switch (UniUnlitUtil.GetRenderMode(src)) + { + case UniUnlitRenderMode.Opaque: + dst.alphaMode = glTFBlendMode.OPAQUE.ToString(); + break; + case UniUnlitRenderMode.Cutout: + dst.alphaMode = glTFBlendMode.MASK.ToString(); + dst.alphaCutoff = src.GetFloat(UniUnlitUtil.PropNameCutoff); + break; + case UniUnlitRenderMode.Transparent: + dst.alphaMode = glTFBlendMode.BLEND.ToString(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + switch (UniUnlitUtil.GetCullMode(src)) + { + case UniUnlitCullMode.Off: + dst.doubleSided = true; + break; + case UniUnlitCullMode.Back: + dst.doubleSided = false; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private static void ExportBaseColor(Material src, ITextureExporter textureExporter, glTFMaterial dst) + { + if (src.HasProperty(UniUnlitUtil.PropNameColor)) + { + dst.pbrMetallicRoughness.baseColorFactor = src.GetColor(UniUnlitUtil.PropNameColor).ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); + } + + if (src.HasProperty(UniUnlitUtil.PropNameMainTex)) + { + var index = textureExporter.RegisterExportingAsSRgb(src.GetTexture(UniUnlitUtil.PropNameMainTex), UniUnlitUtil.GetRenderMode(src) != UniUnlitRenderMode.Opaque); + if (index != -1) + { + dst.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo() + { + index = index, + }; + + GltfMaterialExportUtils.ExportTextureTransform(src, dst.pbrMetallicRoughness.baseColorTexture, UniUnlitUtil.PropNameMainTex); + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInUniUnlitMaterialExporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInUniUnlitMaterialExporter.cs.meta new file mode 100644 index 000000000..5eb370ea2 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInUniUnlitMaterialExporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4a8ebb5c42054bd7be905f2dcb595457 +timeCreated: 1667403411 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import.meta new file mode 100644 index 000000000..bbfa19210 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 317a64fe0f994c6e83128c2ec6f94966 +timeCreated: 1667543725 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/BuiltInGltfMaterialDescriptorGenerator.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/BuiltInGltfMaterialDescriptorGenerator.cs new file mode 100644 index 000000000..c91d60401 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/BuiltInGltfMaterialDescriptorGenerator.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using VRMShaders; + + +namespace UniGLTF +{ + /// + /// GLTF の MaterialImporter + /// + public sealed class BuiltInGltfMaterialDescriptorGenerator : IMaterialDescriptorGenerator + { + public MaterialDescriptor Get(GltfData data, int i) + { + if (BuiltInGltfUnlitMaterialImporter.TryCreateParam(data, i, out var param)) return param; + if (BuiltInGltfPbrMaterialImporter.TryCreateParam(data, i, out param)) return param; + // fallback + if (Symbols.VRM_DEVELOP) + { + Debug.LogWarning($"material: {i} out of range. fallback"); + } + + return new MaterialDescriptor( + GltfMaterialImportUtils.ImportMaterialName(i, null), + BuiltInGltfPbrMaterialImporter.Shader, + null, + new Dictionary(), + new Dictionary(), + new Dictionary(), + new Dictionary(), + new Action[]{}); + } + + public MaterialDescriptor GetGltfDefault() + { + return BuiltInGltfDefaultMaterialImporter.CreateParam(); + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialDescriptorGenerator.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/BuiltInGltfMaterialDescriptorGenerator.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialDescriptorGenerator.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/BuiltInGltfMaterialDescriptorGenerator.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials.meta new file mode 100644 index 000000000..a40a4ddda --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 38683dc9661849cb86efa689b4140f17 +timeCreated: 1667543744 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfDefaultMaterialImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfDefaultMaterialImporter.cs new file mode 100644 index 000000000..ca2d4acc9 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfDefaultMaterialImporter.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using VRMShaders; + +namespace UniGLTF +{ + /// + /// Generate the descriptor of the glTF default material. + /// + public static class BuiltInGltfDefaultMaterialImporter + { + public static MaterialDescriptor CreateParam() + { + // FIXME + return new MaterialDescriptor( + "__default__", + BuiltInGltfPbrMaterialImporter.Shader, + default, + new Dictionary(), + new Dictionary(), + new Dictionary(), + new Dictionary(), + new List>() + ); + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfDefaultMaterialImporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfDefaultMaterialImporter.cs.meta new file mode 100644 index 000000000..d5b2c7e52 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfDefaultMaterialImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aa5431a3a9ee4f9caac398688c3a8973 +timeCreated: 1670224943 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfPbrMaterialImporter.cs similarity index 76% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfPbrMaterialImporter.cs index 526a7faed..8e19db3f5 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfPbrMaterialImporter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using VRMShaders; using ColorSpace = VRMShaders.ColorSpace; @@ -38,13 +39,13 @@ namespace UniGLTF /// _ZWrite /// /// - public static class GltfPbrMaterialImporter + public static class BuiltInGltfPbrMaterialImporter { private static readonly int SrcBlend = Shader.PropertyToID("_SrcBlend"); private static readonly int DstBlend = Shader.PropertyToID("_DstBlend"); private static readonly int ZWrite = Shader.PropertyToID("_ZWrite"); private static readonly int Cutoff = Shader.PropertyToID("_Cutoff"); - public const string ShaderName = "Standard"; + public static Shader Shader => Shader.Find("Standard"); private enum BlendMode { @@ -70,35 +71,38 @@ namespace UniGLTF var vectors = new Dictionary(); var actions = new List>(); - var standardTexDesc = default(TextureDescriptor); + TextureDescriptor? standardTexDesc = default; if (src.pbrMetallicRoughness != null || src.occlusionTexture != null) { if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null) { - SubAssetKey key; - (key, standardTexDesc) = GltfPbrTextureImporter.StandardTexture(data, src); + if (GltfPbrTextureImporter.TryStandardTexture(data, src, out var key, out var desc)) + { + standardTexDesc = desc; + } } - if (src.pbrMetallicRoughness.baseColorFactor != null && - src.pbrMetallicRoughness.baseColorFactor.Length == 4) + var baseColorFactor = GltfMaterialImportUtils.ImportLinearBaseColorFactor(data, src); + if (baseColorFactor.HasValue) { - colors.Add("_Color", - src.pbrMetallicRoughness.baseColorFactor.ToColor4(ColorSpace.Linear, ColorSpace.sRGB) - ); + colors.Add("_Color", baseColorFactor.Value.gamma); } if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1) { - var (key, textureParam) = GltfPbrTextureImporter.BaseColorTexture(data, src); - textureSlots.Add("_MainTex", textureParam); + if (GltfPbrTextureImporter.TryBaseColorTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_MainTex", desc); + } } if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && - src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) + src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1 && + standardTexDesc.HasValue) { actions.Add(material => material.EnableKeyword("_METALLICGLOSSMAP")); - textureSlots.Add("_MetallicGlossMap", standardTexDesc); + textureSlots.Add("_MetallicGlossMap", standardTexDesc.Value); // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. floatValues.Add("_Metallic", 1.0f); floatValues.Add("_GlossMapScale", 1.0f); @@ -113,14 +117,16 @@ namespace UniGLTF if (src.normalTexture != null && src.normalTexture.index != -1) { actions.Add(material => material.EnableKeyword("_NORMALMAP")); - var (_, textureParam) = GltfPbrTextureImporter.NormalTexture(data, src); - textureSlots.Add("_BumpMap", textureParam); - floatValues.Add("_BumpScale", src.normalTexture.scale); + if (GltfPbrTextureImporter.TryNormalTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_BumpMap", desc); + floatValues.Add("_BumpScale", src.normalTexture.scale); + } } - if (src.occlusionTexture != null && src.occlusionTexture.index != -1) + if (src.occlusionTexture != null && src.occlusionTexture.index != -1 && standardTexDesc.HasValue) { - textureSlots.Add("_OcclusionMap", standardTexDesc); + textureSlots.Add("_OcclusionMap", standardTexDesc.Value); floatValues.Add("_OcclusionStrength", src.occlusionTexture.strength); } @@ -133,27 +139,19 @@ namespace UniGLTF material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack; }); - if (src.emissiveFactor != null && src.emissiveFactor.Length == 3) + var emissiveFactor = GltfMaterialImportUtils.ImportLinearEmissiveFactor(data, src); + if (emissiveFactor.HasValue) { - var emissiveFactor = src.emissiveFactor.ToColor3(ColorSpace.Linear, ColorSpace.Linear); - if (UniGLTF.glTF_KHR_materials_emissive_strength.TryGet(src.extensions, out UniGLTF.glTF_KHR_materials_emissive_strength emissiveStrength)) - { - emissiveFactor *= emissiveStrength.emissiveStrength; - } - else if (UniGLTF.Extensions.VRMC_materials_hdr_emissiveMultiplier.GltfDeserializer.TryGet(src.extensions, - out UniGLTF.Extensions.VRMC_materials_hdr_emissiveMultiplier. - VRMC_materials_hdr_emissiveMultiplier ex)) - { - emissiveFactor *= ex.EmissiveMultiplier.Value; - } - - colors.Add("_EmissionColor", emissiveFactor); + // NOTE: Built-in RP Standard shader's emission color is in gamma color space. + colors.Add("_EmissionColor", emissiveFactor.Value.gamma); } if (src.emissiveTexture != null && src.emissiveTexture.index != -1) { - var (key, textureParam) = GltfPbrTextureImporter.EmissiveTexture(data, src); - textureSlots.Add("_EmissionMap", textureParam); + if (GltfPbrTextureImporter.TryEmissiveTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_EmissionMap", desc); + } } } @@ -206,8 +204,8 @@ namespace UniGLTF }); matDesc = new MaterialDescriptor( - GltfMaterialDescriptorGenerator.GetMaterialName(i, src), - ShaderName, + GltfMaterialImportUtils.ImportMaterialName(i, src), + Shader, null, textureSlots, floatValues, diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfPbrMaterialImporter.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfPbrMaterialImporter.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfUnlitMaterialImporter.cs similarity index 74% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfUnlitMaterialImporter.cs index 7bbde1681..4bc74d2ce 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfUnlitMaterialImporter.cs @@ -7,10 +7,12 @@ using ColorSpace = VRMShaders.ColorSpace; namespace UniGLTF { - public static class GltfUnlitMaterialImporter + public static class BuiltInGltfUnlitMaterialImporter { private static readonly int Cutoff = Shader.PropertyToID("_Cutoff"); + public static Shader Shader => Shader.Find(UniUnlitUtil.ShaderName); + public static bool TryCreateParam(GltfData data, int i, out MaterialDescriptor matDesc) { if (i < 0 || i >= data.GLTF.materials.Count) @@ -26,32 +28,29 @@ namespace UniGLTF return false; } + var colors = new Dictionary(); var textureSlots = new Dictionary(); - var colors = - src.pbrMetallicRoughness.baseColorFactor != null && - src.pbrMetallicRoughness.baseColorFactor.Length == 4 - ? new Dictionary - { - { - "_Color", - src.pbrMetallicRoughness.baseColorFactor.ToColor4(ColorSpace.Linear, ColorSpace.sRGB) - } - } - : new Dictionary(); + + // color + var baseColorFactor = GltfMaterialImportUtils.ImportLinearBaseColorFactor(data, src); + if (baseColorFactor.HasValue) + { + colors.Add("_Color", baseColorFactor.Value.gamma); + } // texture if (src.pbrMetallicRoughness.baseColorTexture != null) { - var (offset, scale) = - GltfTextureImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture); - var (key, textureParam) = GltfTextureImporter.CreateSrgb(data, - src.pbrMetallicRoughness.baseColorTexture.index, offset, scale); - textureSlots.Add("_MainTex", textureParam); + var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture); + if (GltfTextureImporter.TryCreateSrgb(data, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale, out var key, out var desc)) + { + textureSlots.Add("_MainTex", desc); + } } matDesc = new MaterialDescriptor( - GltfMaterialDescriptorGenerator.GetMaterialName(i, src), - UniUnlitUtil.ShaderName, + GltfMaterialImportUtils.ImportMaterialName(i, src), + Shader, null, textureSlots, new Dictionary(), diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfUnlitMaterialImporter.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInGltfUnlitMaterialImporter.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialDescriptorGenerator.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialDescriptorGenerator.cs deleted file mode 100644 index baabfe3d7..000000000 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialDescriptorGenerator.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using VRMShaders; - - -namespace UniGLTF -{ - /// - /// GLTF の MaterialImporter - /// - public sealed class GltfMaterialDescriptorGenerator : IMaterialDescriptorGenerator - { - public MaterialDescriptor Get(GltfData data, int i) - { - if (GltfUnlitMaterialImporter.TryCreateParam(data, i, out var param)) return param; - if (GltfPbrMaterialImporter.TryCreateParam(data, i, out param)) return param; - // fallback -#if VRM_DEVELOP - Debug.LogWarning($"material: {i} out of range. fallback"); -#endif - return new MaterialDescriptor( - GetMaterialName(i, null), - GltfPbrMaterialImporter.ShaderName, - null, - new Dictionary(), - new Dictionary(), - new Dictionary(), - new Dictionary(), - new Action[]{}); - - } - - public static string GetMaterialName(int index, glTFMaterial src) - { - if (src != null && !string.IsNullOrEmpty(src.name)) - { - return src.name; - } - return $"material_{index:00}"; - } - } -} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialExportUtils.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialExportUtils.cs new file mode 100644 index 000000000..22da6e790 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialExportUtils.cs @@ -0,0 +1,20 @@ +using System; +using UnityEngine; + +namespace UniGLTF +{ + public static class GltfMaterialExportUtils + { + public static void ExportTextureTransform(Material src, glTFTextureInfo dstTextureInfo, string targetTextureName) + { + if (dstTextureInfo != null && src.HasProperty(targetTextureName)) + { + var offset = src.GetTextureOffset(targetTextureName); + var scale = src.GetTextureScale(targetTextureName); + (scale, offset) = TextureTransform.VerticalFlipScaleOffset(scale, offset); + + glTF_KHR_texture_transform.Serialize(dstTextureInfo, (offset.x, offset.y), (scale.x, scale.y)); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialExportUtils.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialExportUtils.cs.meta new file mode 100644 index 000000000..ca83166d1 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialExportUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4bbc9904e5fe4176b74d39eeb2318bd6 +timeCreated: 1667400475 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImportUtils.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImportUtils.cs new file mode 100644 index 000000000..27c676248 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImportUtils.cs @@ -0,0 +1,61 @@ +using UnityEngine; +using ColorSpace = VRMShaders.ColorSpace; + +namespace UniGLTF +{ + public static class GltfMaterialImportUtils + { + public static string ImportMaterialName(int index, glTFMaterial src) + { + if (src != null && !string.IsNullOrEmpty(src.name)) + { + return src.name; + } + return $"material_{index:00}"; + } + + public static Color? ImportLinearBaseColorFactor(GltfData data, glTFMaterial src) + { + if (src.pbrMetallicRoughness == null) return null; + var baseColorFactor = src.pbrMetallicRoughness.baseColorFactor; + if (baseColorFactor == null || baseColorFactor.Length != 4) return null; + + if (data.MigrationFlags.IsBaseColorFactorGamma) + { + return baseColorFactor.ToColor4(ColorSpace.sRGB, ColorSpace.Linear); + } + else + { + return baseColorFactor.ToColor4(ColorSpace.Linear, ColorSpace.Linear); + } + } + + public static Color? ImportLinearEmissiveFactor(GltfData data, glTFMaterial src) + { + if (src.emissiveFactor == null || src.emissiveFactor.Length != 3) return null; + + // NOTE: glTF 仕様違反だが emissiveFactor に 1.0 より大きな値が入っていた場合もそのまま受け入れる. + var emissiveFactor = new Vector3(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]); + if (glTF_KHR_materials_emissive_strength.TryGet(src.extensions, out var emissiveStrength)) + { + emissiveFactor *= emissiveStrength.emissiveStrength; + } + else if (Extensions.VRMC_materials_hdr_emissiveMultiplier.GltfDeserializer.TryGet(src.extensions, out var ex)) + { + if (ex.EmissiveMultiplier != null) + { + emissiveFactor *= ex.EmissiveMultiplier.Value; + } + } + + if (data.MigrationFlags.IsEmissiveFactorGamma) + { + return emissiveFactor.ToColor3(VRMShaders.ColorSpace.sRGB, VRMShaders.ColorSpace.Linear); + } + else + { + return emissiveFactor.ToColor3(ColorSpace.Linear, ColorSpace.Linear); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImportUtils.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImportUtils.cs.meta new file mode 100644 index 000000000..476a39f19 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfMaterialImportUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 901463b34f824dffa3f531783cff2cc0 +timeCreated: 1668078892 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/IMaterialDescriptorGenerator.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/IMaterialDescriptorGenerator.cs index 10f877c23..c727bf601 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/IMaterialDescriptorGenerator.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/IMaterialDescriptorGenerator.cs @@ -8,6 +8,14 @@ namespace UniGLTF /// public interface IMaterialDescriptorGenerator { + /// + /// Generate the MaterialDescriptor generated from the index i. + /// MaterialDescriptor Get(GltfData data, int i); + + /// + /// Generate the MaterialDescriptor for the non-specified glTF material. + /// + MaterialDescriptor GetGltfDefault(); } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs deleted file mode 100644 index 92a95ff26..000000000 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs +++ /dev/null @@ -1,339 +0,0 @@ -using System; -using System.Linq; -using UniGLTF.UniUnlit; -using UnityEngine; -using VRMShaders; -using ColorSpace = VRMShaders.ColorSpace; - -namespace UniGLTF -{ - public enum glTFBlendMode - { - OPAQUE, - MASK, - BLEND - } - - public class MaterialExporter : IMaterialExporter - { - public virtual glTFMaterial ExportMaterial(Material m, ITextureExporter textureExporter, GltfExportSettings settings) - { - var material = CreateMaterial(m); - - // common params - material.name = m.name; - Export_Color(m, textureExporter, material); - Export_Emission(m, textureExporter, material); - Export_Normal(m, textureExporter, material); - Export_OcclusionMetallicRoughness(m, textureExporter, material); - - return material; - } - - public const string COLOR_TEXTURE_PROP = "_MainTex"; - public const string METALLIC_TEX_PROP = "_MetallicGlossMap"; - public const string NORMAL_TEX_PROP = "_BumpMap"; - public const string EMISSION_TEX_PROP = "_EmissionMap"; - public const string OCCLUSION_TEX_PROP = "_OcclusionMap"; - - static void Export_Color(Material m, ITextureExporter textureManager, glTFMaterial material) - { - if (m.HasProperty("_Color")) - { - material.pbrMetallicRoughness.baseColorFactor = m.GetColor("_Color").ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); - } - - if (m.HasProperty(COLOR_TEXTURE_PROP)) - { - // Don't export alpha channel if material was OPAQUE - var unnecessaryAlpha = string.Equals(material.alphaMode, "OPAQUE", StringComparison.Ordinal); - - var index = textureManager.RegisterExportingAsSRgb(m.GetTexture(COLOR_TEXTURE_PROP), !unnecessaryAlpha); - if (index != -1) - { - material.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo() - { - index = index, - }; - - Export_MainTextureTransform(m, material.pbrMetallicRoughness.baseColorTexture); - } - } - } - - /// - /// Occlusion, Metallic, Roughness - /// - /// - /// - /// - static void Export_OcclusionMetallicRoughness(Material m, ITextureExporter textureExporter, glTFMaterial material) - { - Texture metallicSmoothTexture = default; - float smoothness = 1.0f; - - var textuerNames = m.GetTexturePropertyNames(); - if (textuerNames.Contains(METALLIC_TEX_PROP)) - { - if (m.HasProperty("_GlossMapScale")) - { - smoothness = m.GetFloat("_GlossMapScale"); - } - metallicSmoothTexture = m.GetTexture(METALLIC_TEX_PROP); - } - - Texture occlusionTexture = default; - var occlusionStrength = 1.0f; - if (textuerNames.Contains(OCCLUSION_TEX_PROP)) - { - occlusionTexture = m.GetTexture(OCCLUSION_TEX_PROP); - if (occlusionTexture != null && m.HasProperty("_OcclusionStrength")) - { - occlusionStrength = m.GetFloat("_OcclusionStrength"); - } - } - - int index = textureExporter.RegisterExportingAsCombinedGltfPbrParameterTextureFromUnityStandardTextures(metallicSmoothTexture, smoothness, occlusionTexture); - - if (index != -1 && metallicSmoothTexture != null) - { - material.pbrMetallicRoughness.metallicRoughnessTexture = - new glTFMaterialMetallicRoughnessTextureInfo() - { - index = index, - }; - Export_MainTextureTransform(m, material.pbrMetallicRoughness.metallicRoughnessTexture); - - // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. - material.pbrMetallicRoughness.metallicFactor = 1.0f; - material.pbrMetallicRoughness.roughnessFactor = 1.0f; - } - else - { - if (m.HasProperty("_Metallic")) - { - material.pbrMetallicRoughness.metallicFactor = m.GetFloat("_Metallic"); - } - - if (m.HasProperty("_Glossiness")) - { - material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_Glossiness"); - } - } - - if (index != -1 && occlusionTexture != null) - { - material.occlusionTexture = new glTFMaterialOcclusionTextureInfo() - { - index = index, - strength = occlusionStrength, - }; - Export_MainTextureTransform(m, material.occlusionTexture); - } - } - - static void Export_Normal(Material m, ITextureExporter textureExporter, glTFMaterial material) - { - if (m.HasProperty(NORMAL_TEX_PROP)) - { - var index = textureExporter.RegisterExportingAsNormal(m.GetTexture(NORMAL_TEX_PROP)); - if (index != -1) - { - material.normalTexture = new glTFMaterialNormalTextureInfo() - { - index = index, - }; - - Export_MainTextureTransform(m, material.normalTexture); - } - - if (index != -1 && m.HasProperty("_BumpScale")) - { - material.normalTexture.scale = m.GetFloat("_BumpScale"); - } - } - } - - static void Export_Emission(Material m, ITextureExporter textureExporter, glTFMaterial material) - { - if (m.IsKeywordEnabled("_EMISSION") == false) - { - return; - } - - if (m.HasProperty("_EmissionColor")) - { - var color = m.GetColor("_EmissionColor"); - if (color.maxColorComponent > 1) - { - var maxColorComponent = color.maxColorComponent; - color /= maxColorComponent; - UniGLTF.glTF_KHR_materials_emissive_strength.Serialize(ref material.extensions, maxColorComponent); - } - material.emissiveFactor = color.ToFloat3(ColorSpace.Linear, ColorSpace.Linear); - } - - if (m.HasProperty(EMISSION_TEX_PROP)) - { - var index = textureExporter.RegisterExportingAsSRgb(m.GetTexture(EMISSION_TEX_PROP), needsAlpha: false); - if (index != -1) - { - material.emissiveTexture = new glTFMaterialEmissiveTextureInfo() - { - index = index, - }; - - Export_MainTextureTransform(m, material.emissiveTexture); - } - } - } - - static void Export_MainTextureTransform(Material m, glTFTextureInfo textureInfo) - { - Export_TextureTransform(m, textureInfo, COLOR_TEXTURE_PROP); - } - - static void Export_TextureTransform(Material m, glTFTextureInfo textureInfo, string propertyName) - { - if (textureInfo != null && m.HasProperty(propertyName)) - { - var offset = m.GetTextureOffset(propertyName); - var scale = m.GetTextureScale(propertyName); - (scale, offset) = TextureTransform.VerticalFlipScaleOffset(scale, offset); - - glTF_KHR_texture_transform.Serialize(textureInfo, (offset.x, offset.y), (scale.x, scale.y)); - } - } - - public static bool IsUnlit(string shaderName) - { - switch (shaderName) - { - case "Unlit/Color": - case "Unlit/Texture": - case "Unlit/Transparent": - case "Unlit/Transparent Cutout": - case UniUnlit.UniUnlitUtil.ShaderName: - return true; - - default: - return false; - } - } - - protected virtual glTFMaterial CreateMaterial(Material m) - { - switch (m.shader.name) - { - case "Unlit/Color": - return Export_UnlitColor(m); - - case "Unlit/Texture": - return Export_UnlitTexture(m); - - case "Unlit/Transparent": - return Export_UnlitTransparent(m); - - case "Unlit/Transparent Cutout": - return Export_UnlitCutout(m); - - case UniUnlit.UniUnlitUtil.ShaderName: - return Export_UniUnlit(m); - - default: - return Export_Standard(m); - } - } - - static glTFMaterial Export_UnlitColor(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - material.alphaMode = glTFBlendMode.OPAQUE.ToString(); - return material; - } - - static glTFMaterial Export_UnlitTexture(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - material.alphaMode = glTFBlendMode.OPAQUE.ToString(); - return material; - } - - static glTFMaterial Export_UnlitTransparent(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - material.alphaMode = glTFBlendMode.BLEND.ToString(); - return material; - } - - static glTFMaterial Export_UnlitCutout(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - material.alphaMode = glTFBlendMode.MASK.ToString(); - material.alphaCutoff = m.GetFloat("_Cutoff"); - return material; - } - - private glTFMaterial Export_UniUnlit(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - - var renderMode = UniUnlit.UniUnlitUtil.GetRenderMode(m); - if (renderMode == UniUnlitRenderMode.Opaque) - { - material.alphaMode = glTFBlendMode.OPAQUE.ToString(); - } - else if (renderMode == UniUnlitRenderMode.Transparent) - { - material.alphaMode = glTFBlendMode.BLEND.ToString(); - } - else if (renderMode == UniUnlitRenderMode.Cutout) - { - material.alphaMode = glTFBlendMode.MASK.ToString(); - material.alphaCutoff = m.GetFloat("_Cutoff"); - } - else - { - material.alphaMode = glTFBlendMode.OPAQUE.ToString(); - } - - var cullMode = UniUnlit.UniUnlitUtil.GetCullMode(m); - if (cullMode == UniUnlitCullMode.Off) - { - material.doubleSided = true; - } - else - { - material.doubleSided = false; - } - - return material; - } - - static glTFMaterial Export_Standard(Material m) - { - var material = new glTFMaterial - { - pbrMetallicRoughness = new glTFPbrMetallicRoughness(), - }; - - switch (m.GetTag("RenderType", true)) - { - case "Transparent": - material.alphaMode = glTFBlendMode.BLEND.ToString(); - break; - - case "TransparentCutout": - material.alphaMode = glTFBlendMode.MASK.ToString(); - material.alphaCutoff = m.GetFloat("_Cutoff"); - break; - - default: - material.alphaMode = glTFBlendMode.OPAQUE.ToString(); - break; - } - - return material; - } - } -} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineMaterialDescriptorUtility.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineMaterialDescriptorUtility.cs new file mode 100644 index 000000000..2b56a9709 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineMaterialDescriptorUtility.cs @@ -0,0 +1,38 @@ +using UniGLTF; +using UnityEngine.Rendering; + +public class RenderPipelineMaterialDescriptorGeneratorUtility +{ + protected static RenderPipelineTypes GetRenderPipelineType() + { + RenderPipeline currentPipeline = RenderPipelineManager.currentPipeline; + + if (currentPipeline == null) + { + return RenderPipelineTypes.BuiltinRenderPipeline; + } + if (currentPipeline.GetType().Name.Contains("HDRenderPipeline")) + { + return RenderPipelineTypes.HighDefinitionRenderPipeline; + } + if (currentPipeline.GetType().Name.Contains("UniversalRenderPipeline")) + { + return RenderPipelineTypes.UniversalRenderPipeline; + } + return RenderPipelineTypes.Unknown; + } + + public static IMaterialDescriptorGenerator GetValidGLTFMaterialDescriptorGenerator() + { + switch (GetRenderPipelineType()) + { + case RenderPipelineTypes.UniversalRenderPipeline: + return new UrpGltfMaterialDescriptorGenerator(); + case RenderPipelineTypes.BuiltinRenderPipeline: + return new BuiltInGltfMaterialDescriptorGenerator(); + } + + return null; + } +} + diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineMaterialDescriptorUtility.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineMaterialDescriptorUtility.cs.meta new file mode 100644 index 000000000..27275ee5c --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineMaterialDescriptorUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2a7306f577654254b1fda4dedc322f87 +timeCreated: 1690283093 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineTypes.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineTypes.cs index 78c1cf7f9..96490aa11 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineTypes.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineTypes.cs @@ -8,5 +8,7 @@ namespace UniGLTF { BuiltinRenderPipeline, UniversalRenderPipeline, + HighDefinitionRenderPipeline, + Unknown } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import.meta new file mode 100644 index 000000000..5291c7c43 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3292057f1c104100be6ed94ef578c899 +timeCreated: 1668078713 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials.meta new file mode 100644 index 000000000..2a0920d58 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a76f43b22cf44db80bb2c035df97bca +timeCreated: 1668078724 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfDefaultMaterialImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfDefaultMaterialImporter.cs new file mode 100644 index 000000000..2235009de --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfDefaultMaterialImporter.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using VRMShaders; + +namespace UniGLTF +{ + /// + /// Generate the descriptor of the glTF default material. + /// + public static class UrpGltfDefaultMaterialImporter + { + public static MaterialDescriptor CreateParam() + { + // FIXME + return new MaterialDescriptor( + "__default__", + UrpGltfPbrMaterialImporter.Shader, + default, + new Dictionary(), + new Dictionary(), + new Dictionary(), + new Dictionary(), + new List>() + ); + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfDefaultMaterialImporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfDefaultMaterialImporter.cs.meta new file mode 100644 index 000000000..4d5d5eae0 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfDefaultMaterialImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 320b6d26ea014356b1c37e38425bf152 +timeCreated: 1670225169 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfPbrMaterialImporter.cs similarity index 79% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfPbrMaterialImporter.cs index e9996cfac..be38188d8 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfPbrMaterialImporter.cs @@ -11,13 +11,16 @@ namespace UniGLTF /// /// see: https://github.com/Unity-Technologies/Graphics/blob/v7.5.3/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineMaterialUpgrader.cs#L354-L379 /// - public static class GltfPbrUrpMaterialImporter + public static class UrpGltfPbrMaterialImporter { + public const string ShaderName = "Universal Render Pipeline/Lit"; + private static readonly int SrcBlend = Shader.PropertyToID("_SrcBlend"); private static readonly int DstBlend = Shader.PropertyToID("_DstBlend"); private static readonly int ZWrite = Shader.PropertyToID("_ZWrite"); private static readonly int Cutoff = Shader.PropertyToID("_Cutoff"); - public const string ShaderName = "Universal Render Pipeline/Lit"; + + public static Shader Shader => Shader.Find(ShaderName); private enum BlendMode { @@ -42,13 +45,19 @@ namespace UniGLTF var actions = new List>(); var src = data.GLTF.materials[i]; - var standardTexDesc = default(TextureDescriptor); + TextureDescriptor? standardTexDesc = default; if (src.pbrMetallicRoughness != null || src.occlusionTexture != null) { if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null) { - SubAssetKey key; - (key, standardTexDesc) = GltfPbrTextureImporter.StandardTexture(data, src); + if (GltfPbrTextureImporter.TryStandardTexture(data, src, out var key, out var desc)) + { + if (string.IsNullOrEmpty(desc.UnityObjectName)) + { + throw new ArgumentNullException(); + } + standardTexDesc = desc; + } } if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4) @@ -61,15 +70,17 @@ namespace UniGLTF if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1) { - var (key, textureParam) = GltfPbrTextureImporter.BaseColorTexture(data, src); - // from _MainTex ! - textureSlots.Add("_BaseMap", textureParam); + if (GltfPbrTextureImporter.TryBaseColorTexture(data, src, out var key, out var desc)) + { + // from _MainTex ! + textureSlots.Add("_BaseMap", desc); + } } - if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) + if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1 && standardTexDesc.HasValue) { - actions.Add(material => material.EnableKeyword("_METALLICGLOSSMAP")); - textureSlots.Add("_MetallicGlossMap", standardTexDesc); + actions.Add(material => material.EnableKeyword("_METALLICSPECGLOSSMAP")); + textureSlots.Add("_MetallicGlossMap", standardTexDesc.Value); // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. floatValues.Add("_Metallic", 1.0f); floatValues.Add("_GlossMapScale", 1.0f); @@ -87,14 +98,16 @@ namespace UniGLTF if (src.normalTexture != null && src.normalTexture.index != -1) { actions.Add(material => material.EnableKeyword("_NORMALMAP")); - var (key, textureParam) = GltfPbrTextureImporter.NormalTexture(data, src); - textureSlots.Add("_BumpMap", textureParam); - floatValues.Add("_BumpScale", src.normalTexture.scale); + if (GltfPbrTextureImporter.TryNormalTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_BumpMap", desc); + floatValues.Add("_BumpScale", src.normalTexture.scale); + } } - if (src.occlusionTexture != null && src.occlusionTexture.index != -1) + if (src.occlusionTexture != null && src.occlusionTexture.index != -1 && standardTexDesc.HasValue) { - textureSlots.Add("_OcclusionMap", standardTexDesc); + textureSlots.Add("_OcclusionMap", standardTexDesc.Value); floatValues.Add("_OcclusionStrength", src.occlusionTexture.strength); } @@ -107,26 +120,18 @@ namespace UniGLTF material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack; }); - if (src.emissiveFactor != null && src.emissiveFactor.Length == 3) + var emissiveFactor = GltfMaterialImportUtils.ImportLinearEmissiveFactor(data, src); + if (emissiveFactor.HasValue) { - var emissiveFactor = src.emissiveFactor.ToColor3(ColorSpace.Linear, ColorSpace.Linear); - if (UniGLTF.glTF_KHR_materials_emissive_strength.TryGet(src.extensions, - out UniGLTF.glTF_KHR_materials_emissive_strength emissiveStrength)) - { - emissiveFactor *= emissiveStrength.emissiveStrength; - } - else if (UniGLTF.Extensions.VRMC_materials_hdr_emissiveMultiplier.GltfDeserializer.TryGet(src.extensions, - out UniGLTF.Extensions.VRMC_materials_hdr_emissiveMultiplier.VRMC_materials_hdr_emissiveMultiplier ex)) - { - emissiveFactor *= ex.EmissiveMultiplier.Value; - } - colors.Add("_EmissionColor", emissiveFactor); + colors.Add("_EmissionColor", emissiveFactor.Value); } if (src.emissiveTexture != null && src.emissiveTexture.index != -1) { - var (key, textureParam) = GltfPbrTextureImporter.EmissiveTexture(data, src); - textureSlots.Add("_EmissionMap", textureParam); + if (GltfPbrTextureImporter.TryEmissiveTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_EmissionMap", desc); + } } } @@ -179,8 +184,8 @@ namespace UniGLTF }); matDesc = new MaterialDescriptor( - GltfMaterialDescriptorGenerator.GetMaterialName(i, src), - ShaderName, + GltfMaterialImportUtils.ImportMaterialName(i, src), + Shader, null, textureSlots, floatValues, diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfPbrMaterialImporter.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/Materials/UrpGltfPbrMaterialImporter.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfURPMaterialDescriptorGenerator.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/UrpGltfMaterialDescriptorGenerator.cs similarity index 55% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfURPMaterialDescriptorGenerator.cs rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/UrpGltfMaterialDescriptorGenerator.cs index 309fc82a7..b0a24cf9e 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfURPMaterialDescriptorGenerator.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/UrpGltfMaterialDescriptorGenerator.cs @@ -10,36 +10,32 @@ namespace UniGLTF /// /// GLTF の MaterialImporter /// - public sealed class GltfUrpMaterialDescriptorGenerator : IMaterialDescriptorGenerator + public sealed class UrpGltfMaterialDescriptorGenerator : IMaterialDescriptorGenerator { public MaterialDescriptor Get(GltfData data, int i) { - if (GltfUnlitMaterialImporter.TryCreateParam(data, i, out var param)) return param; - if (GltfPbrUrpMaterialImporter.TryCreateParam(data, i, out param)) return param; + if (BuiltInGltfUnlitMaterialImporter.TryCreateParam(data, i, out var param)) return param; + if (UrpGltfPbrMaterialImporter.TryCreateParam(data, i, out param)) return param; // fallback -#if VRM_DEVELOP - Debug.LogWarning($"material: {i} out of range. fallback"); -#endif + if (Symbols.VRM_DEVELOP) + { + Debug.LogWarning($"material: {i} out of range. fallback"); + } + return new MaterialDescriptor( - GetMaterialName(i, null), - GltfPbrMaterialImporter.ShaderName, + GltfMaterialImportUtils.ImportMaterialName(i, null), + UrpGltfPbrMaterialImporter.Shader, null, new Dictionary(), new Dictionary(), new Dictionary(), new Dictionary(), new Collection>()); - } - public static string GetMaterialName(int index, glTFMaterial src) + public MaterialDescriptor GetGltfDefault() { - if (src != null && !string.IsNullOrEmpty(src.name)) - { - return src.name; - } - - return $"material_{index:00}"; + return UrpGltfDefaultMaterialImporter.CreateParam(); } } } \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfURPMaterialDescriptorGenerator.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/UrpGltfMaterialDescriptorGenerator.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfURPMaterialDescriptorGenerator.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Import/UrpGltfMaterialDescriptorGenerator.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/glTFBlendMode.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/glTFBlendMode.cs new file mode 100644 index 000000000..bcd2e3205 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/glTFBlendMode.cs @@ -0,0 +1,9 @@ +namespace UniGLTF +{ + public enum glTFBlendMode + { + OPAQUE, + MASK, + BLEND + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/glTFBlendMode.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/glTFBlendMode.cs.meta new file mode 100644 index 000000000..1f2bab03c --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/glTFBlendMode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 59e2e94f37164b3c87324eea9ba98006 +timeCreated: 1667402917 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs index 8276891ba..2f2d6f3e4 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs @@ -48,6 +48,8 @@ namespace UniGLTF positionAccessorIndex = data.ExtendSparseBufferAndGetAccessorIndex(accessorCount, sparseIndices.Select(x => positions[x]).ToArray(), sparseIndices, sparseIndicesViewIndex, glBufferTarget.NONE); + data.Gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); + data.Gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); } // normals diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshData.cs similarity index 63% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshData.cs index 48e54d0a9..2bffd253a 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshData.cs @@ -1,35 +1,141 @@ using System; using System.Collections.Generic; using System.Linq; +using Unity.Collections; using UnityEngine; using UnityEngine.Profiling; using UnityEngine.Rendering; namespace UniGLTF { - internal class MeshContext + internal class MeshData : IDisposable { - private readonly List _vertices = new List(); - private readonly List _skinnedMeshVertices = new List(); - private readonly List _indices = new List(); + private int _currentVertexCount = 0; + private int _currentIndexCount = 0; + + private NativeArray _indices; + private NativeArray _vertices0; + private NativeArray _vertices1; + private NativeArray _vertices2; + private readonly List _subMeshes = new List(); private readonly List _materialIndices = new List(); private readonly List _blendShapes = new List(); + + public NativeArray Vertices0 => _vertices0.GetSubArray(0, _currentVertexCount); + public NativeArray Vertices1 => _vertices1.GetSubArray(0, _currentVertexCount); + public NativeArray Vertices2 => _vertices2.GetSubArray(0, _currentVertexCount); + public NativeArray Indices => _indices.GetSubArray(0, _currentIndexCount); + + public IReadOnlyList SubMeshes => _subMeshes; public IReadOnlyList MaterialIndices => _materialIndices; + public IReadOnlyList BlendShapes => _blendShapes; - public bool HasNormal { get; private set; } = true; + public bool HasNormal { get; private set; } + public string Name { get; private set; } + public bool ShouldSetRendererNodeAsBone { get; private set; } - public string Name { get; } + public MeshData(int vertexCapacity, int indexCapacity) + { + _vertices0 = new NativeArray(vertexCapacity, Allocator.Persistent); + _vertices1 = new NativeArray(vertexCapacity, Allocator.Persistent); + _vertices2 = new NativeArray(vertexCapacity, Allocator.Persistent); + _indices = new NativeArray(indexCapacity, Allocator.Persistent); + } + + public void Dispose() + { + _vertices0.Dispose(); + _vertices1.Dispose(); + _vertices2.Dispose(); + _indices.Dispose(); + } + + void Clear() + { + _currentVertexCount = 0; + _currentIndexCount = 0; + _subMeshes.Clear(); + _materialIndices.Clear(); + _blendShapes.Clear(); + Name = null; + HasNormal = false; + ShouldSetRendererNodeAsBone = false; + } /// - /// * flip triangle - /// * add submesh offset + /// バッファ共有方式(vrm-0.x)の判定。 + /// import の後方互換性のためで、vrm-1.0 export では使いません。 + /// + /// バッファ共用方式は連結済みの VertexBuffer を共有して、SubMeshの index buffer による参照がスライドしていく方式 + /// + /// * バッファがひとつのとき + /// * すべての primitive の attribute が 同一の accessor を使用している時 + /// /// - /// - /// - void PushIndices(BufferAccessor src, int offset) + public static bool HasSharedVertexBuffer(glTFMesh gltfMesh) + { + glTFAttributes lastAttributes = null; + foreach (var prim in gltfMesh.primitives) + { + if (lastAttributes != null && !prim.attributes.Equals(lastAttributes)) + { + return false; + } + lastAttributes = prim.attributes; + } + return true; + } + + /// + /// glTF から 頂点バッファと index バッファ、BlendShape を蓄える。 + /// 右手系と左手系の反転(ZもしくはX軸の反転)も実行する。 + /// + public void LoadFromGltf(GltfData data, int meshIndex, IAxisInverter inverter) + { + Profiler.BeginSample("MeshData.CreateFromGltf"); + Clear(); + + var gltfMesh = data.GLTF.meshes[meshIndex]; + + var name = gltfMesh.name; + if (string.IsNullOrEmpty(name)) + { + name = $"UniGLTF import#{meshIndex}"; + } + Name = name; + + if (HasSharedVertexBuffer(gltfMesh)) + { + ImportMeshSharingVertexBuffer(data, gltfMesh, inverter); + } + else + { + ImportMeshIndependentVertexBuffer(data, gltfMesh, inverter); + } + + RenameBlendShape(gltfMesh); + + DropUnusedVertices(); + + AddDefaultMaterial(); + + Profiler.EndSample(); + } + + private void AddIndex(int i) + { + _indices[_currentIndexCount] = i; + _currentIndexCount += 1; + } + + /// + /// * flip triangle(gltfとtriangleの CW と CCW が異なる) + /// * add submesh offset(gltfのprimitiveは、頂点バッファが分かれているので連結。連結すると index が変わる(offset)) + /// + private void PushIndices(BufferAccessor src, int offset) { switch (src.ComponentType) { @@ -38,9 +144,9 @@ namespace UniGLTF var indices = src.Bytes; for (int i = 0; i < src.Count; i += 3) { - _indices.Add(offset + indices[i + 2]); - _indices.Add(offset + indices[i + 1]); - _indices.Add(offset + indices[i]); + AddIndex(offset + indices[i + 2]); + AddIndex(offset + indices[i + 1]); + AddIndex(offset + indices[i]); } } break; @@ -50,9 +156,9 @@ namespace UniGLTF var indices = src.Bytes.Reinterpret(1); for (int i = 0; i < src.Count; i += 3) { - _indices.Add(offset + indices[i + 2]); - _indices.Add(offset + indices[i + 1]); - _indices.Add(offset + indices[i]); + AddIndex(offset + indices[i + 2]); + AddIndex(offset + indices[i + 1]); + AddIndex(offset + indices[i]); } } break; @@ -63,9 +169,9 @@ namespace UniGLTF var indices = src.Bytes.Reinterpret(1); for (int i = 0; i < src.Count; i += 3) { - _indices.Add(offset + indices[i + 2]); - _indices.Add(offset + indices[i + 1]); - _indices.Add(offset + indices[i]); + AddIndex(offset + indices[i + 2]); + AddIndex(offset + indices[i + 1]); + AddIndex(offset + indices[i]); } } break; @@ -75,96 +181,7 @@ namespace UniGLTF } } - /// - /// 頂点情報をMeshに対して送る - /// - /// - public void UploadMeshVertices(Mesh mesh) - { - var vertexAttributeDescriptor = MeshVertex.GetVertexAttributeDescriptor(); - - // Weight情報等は存在しないパターンがあり、かつこの存在の有無によって内部的に条件分岐が走ってしまうため、 - // Streamを分けて必要に応じてアップロードする - if (_skinnedMeshVertices.Count > 0) - { - vertexAttributeDescriptor = vertexAttributeDescriptor.Concat(SkinnedMeshVertex - .GetVertexAttributeDescriptor().Select( - attr => - { - attr.stream = 1; - return attr; - })).ToArray(); - } - - mesh.SetVertexBufferParams(_vertices.Count, vertexAttributeDescriptor); - - mesh.SetVertexBufferData(_vertices, 0, 0, _vertices.Count); - if (_skinnedMeshVertices.Count > 0) - { - mesh.SetVertexBufferData(_skinnedMeshVertices, 0, 0, _skinnedMeshVertices.Count, 1); - } - } - - /// - /// インデックス情報をMeshに対して送る - /// - /// - public void UploadMeshIndices(Mesh mesh) - { - mesh.SetIndexBufferParams(_indices.Count, IndexFormat.UInt32); - mesh.SetIndexBufferData(_indices, 0, 0, _indices.Count); - mesh.subMeshCount = _subMeshes.Count; - for (var i = 0; i < _subMeshes.Count; i++) - { - mesh.SetSubMesh(i, _subMeshes[i]); - } - } - - private BlendShape GetOrCreateBlendShape(int i) - { - if (i < _blendShapes.Count && _blendShapes[i] != null) - { - return _blendShapes[i]; - } - - while (_blendShapes.Count <= i) - { - _blendShapes.Add(null); - } - - var blendShape = new BlendShape(i.ToString()); - _blendShapes[i] = blendShape; - return blendShape; - } - - public MeshContext(string name, int meshIndex) - { - if (string.IsNullOrEmpty(name)) - { - name = $"UniGLTF import#{meshIndex}"; - } - - Name = name; - } - - private static (float x, float y, float z, float w) NormalizeBoneWeight( - (float x, float y, float z, float w) src) - { - var sum = src.x + src.y + src.z + src.w; - if (sum == 0) - { - return src; - } - - var f = 1.0f / sum; - src.x *= f; - src.y *= f; - src.z *= f; - src.w *= f; - return src; - } - - (int VertexCapacity, int IndexCapacity) GetCapacity(GltfData data, glTFMesh gltfMesh) + public static (int VertexCapacity, int IndexCapacity) GetCapacity(GltfData data, glTFMesh gltfMesh) { var vertexCount = 0; var indexCount = 0; @@ -186,6 +203,84 @@ namespace UniGLTF return (vertexCount, indexCount); } + private BlendShape GetOrCreateBlendShape(int i) + { + if (i < _blendShapes.Count && _blendShapes[i] != null) + { + return _blendShapes[i]; + } + + while (_blendShapes.Count <= i) + { + _blendShapes.Add(null); + } + + var blendShape = new BlendShape(i.ToString()); + _blendShapes[i] = blendShape; + return blendShape; + } + + private void RenameBlendShape(glTFMesh gltfMesh) + { + if (!gltf_mesh_extras_targetNames.TryGet(gltfMesh, out var targetNames)) return; + for (var i = 0; i < _blendShapes.Count; i++) + { + if (i >= targetNames.Count) + { + Debug.LogWarning($"invalid primitive.extras.targetNames length"); + break; + } + + _blendShapes[i].Name = targetNames[i]; + } + } + + /// + /// https://github.com/vrm-c/UniVRM/issues/610 + /// + /// VertexBuffer の後ろに未使用頂点がある場合に削除する + /// + private void DropUnusedVertices() + { + Profiler.BeginSample("MeshData.DropUnusedVertices"); + var maxIndex = Indices.Max(); + if (maxIndex + 1 < _currentVertexCount) + { + _currentVertexCount = maxIndex + 1; + } + foreach (var blendShape in _blendShapes) + { + Truncate(blendShape.Positions, maxIndex); + Truncate(blendShape.Normals, maxIndex); + Truncate(blendShape.Tangents, maxIndex); + } + Profiler.EndSample(); + } + + private static void Truncate(List list, int maxIndex) + { + if (list == null) + { + return; + } + + var count = maxIndex + 1; + if (list.Count > count) + { + // Debug.LogWarning($"remove {count} to {list.Count}"); + list.RemoveRange(count, list.Count - count); + } + } + + private void AddDefaultMaterial() + { + if (!_materialIndices.Any()) + { + // add default material + _materialIndices.Add(0); + } + } + /// /// 各 primitive の attribute の要素が同じでない。=> uv が有るものと無いものが混在するなど /// glTF 的にはありうる。 @@ -195,27 +290,27 @@ namespace UniGLTF /// /// /// - public void ImportMeshIndependentVertexBuffer(GltfData data, glTFMesh gltfMesh, IAxisInverter inverter) + private void ImportMeshIndependentVertexBuffer(GltfData data, glTFMesh gltfMesh, IAxisInverter inverter) { - (_vertices.Capacity, _indices.Capacity) = GetCapacity(data, gltfMesh); - bool isOldVersion = data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16); foreach (var primitives in gltfMesh.primitives) { - var vertexOffset = _vertices.Count; + var vertexOffset = _currentVertexCount; var indexBufferCount = primitives.indices; - // position は必ずある + // position は必ず存在する。normal, texCoords, colors, skinning は無いかもしれない var positions = primitives.GetPositions(data); var normals = primitives.GetNormals(data, positions.Length); + if (normals.HasValue) + { + HasNormal = true; + } var texCoords0 = primitives.GetTexCoords0(data, positions.Length); var texCoords1 = primitives.GetTexCoords1(data, positions.Length); var colors = primitives.GetColors(data, positions.Length); - var jointsGetter = primitives.GetJoints(data, positions.Length); - var weightsGetter = primitives.GetWeights(data, positions.Length); - - CheckAttributeUsages(primitives); + var skinning = SkinningInfo.Create(data, gltfMesh, primitives); + ShouldSetRendererNodeAsBone = skinning.ShouldSetRendererNodeAsBone; for (var i = 0; i < positions.Length; ++i) { @@ -239,30 +334,24 @@ namespace UniGLTF } var texCoord1 = texCoords1 != null ? texCoords1.Value[i].ReverseUV() : Vector2.zero; - var joints = jointsGetter?.Invoke(i) ?? (0, 0, 0, 0); - var weights = weightsGetter != null ? NormalizeBoneWeight(weightsGetter(i)) : (0, 0, 0, 0); var color = colors != null ? colors.Value[i] : Color.white; - _vertices.Add( - new MeshVertex( - position, - normal, - texCoord0, - texCoord1, - color - )); - if (jointsGetter != null) + + _vertices0[_currentVertexCount] = new MeshVertex0( + position, + normal + ); + _vertices1[_currentVertexCount] = new MeshVertex1( + texCoord0, + texCoord1, + color + ); + var skin = skinning.GetSkinnedVertex(i); + if (skin.HasValue) { - _skinnedMeshVertices.Add(new SkinnedMeshVertex( - joints.x, - joints.y, - joints.z, - joints.w, - weights.x, - weights.y, - weights.z, - weights.w)); + _vertices2[_currentVertexCount] = skin.Value; } + _currentVertexCount += 1; } // blendshape @@ -309,17 +398,22 @@ namespace UniGLTF if (indexBufferCount >= 0) { - var indexOffset = _indices.Count; + var indexOffset = _currentIndexCount; var dataIndices = data.GetIndicesFromAccessorIndex(indexBufferCount); PushIndices(dataIndices, vertexOffset); _subMeshes.Add(new SubMeshDescriptor(indexOffset, dataIndices.Count)); } else { - var indexOffset = _indices.Count; - _indices.AddRange(TriangleUtil.FlipTriangle(Enumerable.Range(0, _vertices.Count)) - .Select(index => index + vertexOffset)); - _subMeshes.Add(new SubMeshDescriptor(indexOffset, _vertices.Count)); + var indexOffset = _currentIndexCount; + for (int i = 0; i < positions.Count(); i += 3) + { + // flip triangle + AddIndex(i + vertexOffset + 2); + AddIndex(i + vertexOffset + 1); + AddIndex(i + vertexOffset); + } + _subMeshes.Add(new SubMeshDescriptor(indexOffset, positions.Count())); } // material @@ -327,15 +421,6 @@ namespace UniGLTF } } - /// - /// 各種頂点属性が使われているかどうかをチェックし、使われていなかったらフラグを切る - /// MEMO: O(1)で検知する手段がありそう - /// - private void CheckAttributeUsages(glTFPrimitives primitives) - { - if (!primitives.HasNormal()) HasNormal = false; - } - /// /// /// 各primitiveが同じ attribute を共有している場合専用のローダー。 @@ -344,25 +429,25 @@ namespace UniGLTF /// /// /// - public void ImportMeshSharingVertexBuffer(GltfData data, glTFMesh gltfMesh, IAxisInverter inverter) + private void ImportMeshSharingVertexBuffer(GltfData data, glTFMesh gltfMesh, IAxisInverter inverter) { - (_vertices.Capacity, _indices.Capacity) = GetCapacity(data, gltfMesh); - var isOldVersion = data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16); { - // 同じVertexBufferを共有しているので先頭のモノを使う + // すべての primitives で連結済みの VertexBuffer を共有している。代表して先頭を使う var primitives = gltfMesh.primitives.First(); var positions = primitives.GetPositions(data); var normals = primitives.GetNormals(data, positions.Length); + if (normals.HasValue) + { + HasNormal = true; + } var texCoords0 = primitives.GetTexCoords0(data, positions.Length); var texCoords1 = primitives.GetTexCoords1(data, positions.Length); var colors = primitives.GetColors(data, positions.Length); - var jointsGetter = primitives.GetJoints(data, positions.Length); - var weightsGetter = primitives.GetWeights(data, positions.Length); - - CheckAttributeUsages(primitives); + var skinning = SkinningInfo.Create(data, gltfMesh, primitives); + ShouldSetRendererNodeAsBone = skinning.ShouldSetRendererNodeAsBone; for (var i = 0; i < positions.Length; ++i) { @@ -385,28 +470,22 @@ namespace UniGLTF var texCoord1 = texCoords1 != null ? texCoords1.Value[i].ReverseUV() : Vector2.zero; var color = colors != null ? colors.Value[i] : Color.white; - var joints = jointsGetter?.Invoke(i) ?? (0, 0, 0, 0); - var weights = weightsGetter != null ? NormalizeBoneWeight(weightsGetter(i)) : (0, 0, 0, 0); - _vertices.Add(new MeshVertex( + _vertices0[_currentVertexCount] = new MeshVertex0( position, - normal, + normal + ); + _vertices1[_currentVertexCount] = new MeshVertex1( texCoord0, texCoord1, color - )); - if (jointsGetter != null) + ); + var skin = skinning.GetSkinnedVertex(i); + if (skin.HasValue) { - _skinnedMeshVertices.Add(new SkinnedMeshVertex( - joints.x, - joints.y, - joints.z, - joints.w, - weights.x, - weights.y, - weights.z, - weights.w)); + _vertices2[_currentVertexCount] = skin.Value; } + _currentVertexCount += 1; } // blendshape @@ -459,83 +538,30 @@ namespace UniGLTF foreach (var primitive in gltfMesh.primitives) { - if (primitive.indices == -1) + if (primitive.indices >= 0) { - var indexOffset = _indices.Count; - _indices.AddRange(TriangleUtil.FlipTriangle(Enumerable.Range(0, _vertices.Count))); - _subMeshes.Add(new SubMeshDescriptor(indexOffset, _vertices.Count)); - } - else - { - var indexOffset = _indices.Count; + var indexOffset = _currentIndexCount; var indices = data.GetIndicesFromAccessorIndex(primitive.indices); PushIndices(indices, 0); _subMeshes.Add(new SubMeshDescriptor(indexOffset, indices.Count)); } + else + { + var indexOffset = _currentIndexCount; + var positions = data.GLTF.accessors[primitive.attributes.POSITION]; + for (int i = 0; i < positions.count; i += 3) + { + // flip triangle + AddIndex(i + 2); + AddIndex(i + 1); + AddIndex(i); + } + _subMeshes.Add(new SubMeshDescriptor(indexOffset, positions.count)); + } // material _materialIndices.Add(primitive.material); } } - - public void RenameBlendShape(glTFMesh gltfMesh) - { - if (!gltf_mesh_extras_targetNames.TryGet(gltfMesh, out var targetNames)) return; - for (var i = 0; i < BlendShapes.Count; i++) - { - if (i >= targetNames.Count) - { - Debug.LogWarning($"invalid primitive.extras.targetNames length"); - break; - } - - BlendShapes[i].Name = targetNames[i]; - } - } - - private static void Truncate(List list, int maxIndex) - { - if (list == null) - { - return; - } - - var count = maxIndex + 1; - if (list.Count > count) - { - // Debug.LogWarning($"remove {count} to {list.Count}"); - list.RemoveRange(count, list.Count - count); - } - } - - public void AddDefaultMaterial() - { - if (!_materialIndices.Any()) - { - // add default material - _materialIndices.Add(0); - } - } - - /// - /// https://github.com/vrm-c/UniVRM/issues/610 - /// - /// VertexBuffer の後ろに未使用頂点がある場合に削除する - /// - public void DropUnusedVertices() - { - Profiler.BeginSample("MeshContext.DropUnusedVertices"); - var maxIndex = _indices.Max(); - Truncate(_vertices, maxIndex); - Truncate(_skinnedMeshVertices, maxIndex); - foreach (var blendShape in _blendShapes) - { - Truncate(blendShape.Positions, maxIndex); - Truncate(blendShape.Normals, maxIndex); - Truncate(blendShape.Tangents, maxIndex); - } - - Profiler.EndSample(); - } } } \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshData.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshData.cs.meta new file mode 100644 index 000000000..800ac75fa --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ef93605dcfe9014fbf96a3b681795ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportInfo.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportInfo.cs index 952cb37f2..f918be318 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportInfo.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportInfo.cs @@ -264,7 +264,7 @@ namespace UniGLTF } else { - throw new NotImplementedException(); + Debug.LogWarning($"unknown renderer: {renderer}", context: renderer); } } @@ -412,7 +412,7 @@ namespace UniGLTF foreach (var node in nodes) { var renderer = node.GetComponent(); - if (renderer == null) + if (renderer == null || !renderer.enabled) { continue; } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs index f3b65e5f0..1af876ce0 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs @@ -34,6 +34,10 @@ namespace UniGLTF var normals = mesh.normals; var uv = mesh.uv; var boneWeights = mesh.boneWeights; + if (boneWeights.All(x => x.weight0 == 0 && x.weight1 == 0 && x.weight2 == 0 && x.weight3 == 0)) + { + boneWeights = null; + } var colors = mesh.colors; Func getJointIndex = null; @@ -47,7 +51,7 @@ namespace UniGLTF var vColorState = VertexColorUtility.DetectVertexColor(mesh, unityMaterials); var exportVertexColor = ( - (settings.KeepVertexColor && mesh.colors != null && mesh.colors.Length == mesh.vertexCount) // vertex color を残す設定 + (settings.ExportVertexColor && mesh.colors != null && mesh.colors.Length == mesh.vertexCount) // vertex color を残す設定 || vColorState == VertexColorState.ExistsAndIsUsed // VColor使っている || vColorState == VertexColorState.ExistsAndMixed // VColorを使っているところと使っていないところが混在(とりあえずExportする) ); @@ -125,7 +129,7 @@ namespace UniGLTF } var targetNames = Enumerable.Range(0, mesh.blendShapeCount).Select(x => mesh.GetBlendShapeName(x)).ToArray(); - gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames); + gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames, BlendShapeTargetNameLocationFlags.Both); return (gltfMesh, Enumerable.Range(0, mesh.blendShapeCount).ToDictionary(x => x, x => x)); } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs index e1885be1f..dcef406c5 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs @@ -43,12 +43,16 @@ namespace UniGLTF } var uvAccessorIndex0 = data.ExtendBufferAndGetAccessorIndex(mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); - var uvAccessorIndex1 = data.ExtendBufferAndGetAccessorIndex(mesh.uv2.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); + + var uvAccessorIndex1 = -1; + if (settings.ExportUvSecondary) + { + uvAccessorIndex1 = data.ExtendBufferAndGetAccessorIndex(mesh.uv2.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); + } var colorAccessorIndex = -1; - var vColorState = VertexColorUtility.DetectVertexColor(mesh, materials); - if ((settings.KeepVertexColor && mesh.colors != null && mesh.colors.Length == mesh.vertexCount) // vertex color を残す設定 + if ((settings.ExportVertexColor && mesh.colors != null && mesh.colors.Length == mesh.vertexCount) // vertex color を残す設定 || vColorState == VertexColorState.ExistsAndIsUsed // VColor使っている || vColorState == VertexColorState.ExistsAndMixed // VColorを使っているところと使っていないところが混在(とりあえずExportする) ) @@ -57,15 +61,23 @@ namespace UniGLTF colorAccessorIndex = data.ExtendBufferAndGetAccessorIndex(mesh.colors, glBufferTarget.ARRAY_BUFFER); } - var boneweights = mesh.boneWeights; - var weightAccessorIndex = data.ExtendBufferAndGetAccessorIndex(boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER); - var jointsAccessorIndex = data.ExtendBufferAndGetAccessorIndex(boneweights.Select(y => - new UShort4( - (ushort)unityMesh.GetJointIndex(y.boneIndex0), - (ushort)unityMesh.GetJointIndex(y.boneIndex1), - (ushort)unityMesh.GetJointIndex(y.boneIndex2), - (ushort)unityMesh.GetJointIndex(y.boneIndex3)) - ).ToArray(), glBufferTarget.ARRAY_BUFFER); + var boneWeights = mesh.boneWeights; + var weightAccessorIndex = -1; + var jointsAccessorIndex = -1; + if (boneWeights.All(x => x.weight0 == 0 && x.weight1 == 0 && x.weight2 == 0 && x.weight3 == 0)) + { + } + else + { + weightAccessorIndex = data.ExtendBufferAndGetAccessorIndex(boneWeights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER); + jointsAccessorIndex = data.ExtendBufferAndGetAccessorIndex(boneWeights.Select(y => + new UShort4( + (ushort)unityMesh.GetJointIndex(y.boneIndex0), + (ushort)unityMesh.GetJointIndex(y.boneIndex1), + (ushort)unityMesh.GetJointIndex(y.boneIndex2), + (ushort)unityMesh.GetJointIndex(y.boneIndex3)) + ).ToArray(), glBufferTarget.ARRAY_BUFFER); + } var attributes = new glTFAttributes { @@ -180,7 +192,7 @@ namespace UniGLTF } } - gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames); + gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames, BlendShapeTargetNameLocationFlags.Both); } return (gltfMesh, blendShapeIndexMap); diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs.meta deleted file mode 100644 index 89f3ce9b8..000000000 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d9658f6e46942b146ad7e752c6592401 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs similarity index 55% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs index 5fcb06ca1..5540a6df3 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs @@ -1,79 +1,45 @@ -using System; +using System; using System.Linq; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Profiling; +using UnityEngine.Rendering; using VRMShaders; namespace UniGLTF { - public class MeshImporter + internal static class MeshUploader { private const float FrameWeight = 100.0f; - private static bool HasSharedVertexBuffer(glTFMesh gltfMesh) + /// + /// 頂点情報をMeshに対して送る + /// + public static void UploadMeshVertices(MeshData data, Mesh mesh) { - glTFAttributes lastAttributes = null; - var sharedAttributes = true; - foreach (var prim in gltfMesh.primitives) + MeshVertexUtility.SetVertexBufferParamsToMesh(mesh, data.Vertices0.Length, data.Vertices2.Length > 0); + + mesh.SetVertexBufferData(data.Vertices0, 0, 0, data.Vertices0.Length); + mesh.SetVertexBufferData(data.Vertices1, 0, 0, data.Vertices0.Length, 1); + if (data.Vertices2.Length > 0) { - if (lastAttributes != null && !prim.attributes.Equals(lastAttributes)) - { - sharedAttributes = false; - break; - } - - lastAttributes = prim.attributes; + mesh.SetVertexBufferData(data.Vertices2, 0, 0, data.Vertices2.Length, 2); } - - return sharedAttributes; } - internal MeshContext ReadMesh(GltfData data, int meshIndex, IAxisInverter inverter) + /// + /// インデックス情報をMeshに対して送る + /// + /// + private static void UploadMeshIndices(MeshData data, Mesh mesh) { - Profiler.BeginSample("ReadMesh"); - var gltfMesh = data.GLTF.meshes[meshIndex]; - - var meshContext = new MeshContext(gltfMesh.name, meshIndex); - if (HasSharedVertexBuffer(gltfMesh)) + mesh.SetIndexBufferParams(data.Indices.Length, IndexFormat.UInt32); + mesh.SetIndexBufferData(data.Indices, 0, 0, data.Indices.Length); + mesh.subMeshCount = data.SubMeshes.Count; + for (var i = 0; i < data.SubMeshes.Count; i++) { - meshContext.ImportMeshSharingVertexBuffer(data, gltfMesh, inverter); + mesh.SetSubMesh(i, data.SubMeshes[i]); } - else - { - meshContext.ImportMeshIndependentVertexBuffer(data, gltfMesh, inverter); - } - - meshContext.RenameBlendShape(gltfMesh); - - meshContext.DropUnusedVertices(); - - Profiler.EndSample(); - return meshContext; - } - - private static (Mesh, bool) BuildMesh(MeshContext meshContext) - { - meshContext.AddDefaultMaterial(); - - //Debug.Log(prims.ToJson()); - var mesh = new Mesh - { - name = meshContext.Name - }; - - meshContext.UploadMeshVertices(mesh); - meshContext.UploadMeshIndices(mesh); - - // NOTE: mesh.vertices では自動的に行われていたが、SetVertexBuffer では行われないため、明示的に呼び出す. - mesh.RecalculateBounds(); - - if (!meshContext.HasNormal) - { - mesh.RecalculateNormals(); - } - - return (mesh, true); } private static async Task BuildBlendShapeAsync(IAwaitCaller awaitCaller, Mesh mesh, BlendShape blendShape, @@ -90,7 +56,7 @@ namespace UniGLTF } }); - Profiler.BeginSample("MeshImporter.BuildBlendShapeAsync"); + Profiler.BeginSample("MeshUploader.BuildBlendShapeAsync"); if (blendShape.Positions.Count > 0) { if (blendShape.Positions.Count == mesh.vertexCount) @@ -122,34 +88,49 @@ namespace UniGLTF Profiler.EndSample(); } - internal static async Task BuildMeshAsync( + public static async Task BuildMeshAndUploadAsync( IAwaitCaller awaitCaller, - Func ctx, - MeshContext meshContext) + MeshData data, + Func materialFromIndex) { - Profiler.BeginSample("MeshImporter.BuildMesh"); - var (mesh, recalculateTangents) = BuildMesh(meshContext); - Profiler.EndSample(); - if (recalculateTangents) + //Debug.Log(prims.ToJson()); + var mesh = new Mesh { - await awaitCaller.NextFrame(); - mesh.RecalculateTangents(); + name = data.Name + }; + + UploadMeshVertices(data, mesh); + await awaitCaller.NextFrame(); + + UploadMeshIndices(data, mesh); + await awaitCaller.NextFrame(); + + // NOTE: mesh.vertices では自動的に行われていたが、SetVertexBuffer では行われないため、明示的に呼び出す. + mesh.RecalculateBounds(); + await awaitCaller.NextFrame(); + + if (!data.HasNormal) + { + mesh.RecalculateNormals(); await awaitCaller.NextFrame(); } - // 先にすべてのマテリアルを作成済みなのでテクスチャーは生成済み。Resultを使ってよい + mesh.RecalculateTangents(); + await awaitCaller.NextFrame(); + var result = new MeshWithMaterials { Mesh = mesh, - Materials = meshContext.MaterialIndices.Select(ctx).ToArray() + Materials = data.MaterialIndices.Select(materialFromIndex).ToArray(), + ShouldSetRendererNodeAsBone = data.ShouldSetRendererNodeAsBone, }; - await awaitCaller.NextFrame(); - if (meshContext.BlendShapes.Count > 0) + + if (data.BlendShapes.Count > 0) { var emptyVertices = new Vector3[mesh.vertexCount]; - foreach (var blendShape in meshContext.BlendShapes) + foreach (var blendShape in data.BlendShapes) { await BuildBlendShapeAsync(awaitCaller, mesh, blendShape, emptyVertices); } @@ -162,4 +143,4 @@ namespace UniGLTF return result; } } -} \ No newline at end of file +} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs deleted file mode 100644 index 5619fa84d..000000000 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using UnityEngine; -using UnityEngine.Rendering; - -namespace UniGLTF -{ - /// - /// インターリーブされたメッシュの頂点情報のうち、基本的なものを表す構造体 - /// 必要に応じてSkinnedMeshVertexとあわせて - /// そのままGPUにアップロードされる - /// - [Serializable, StructLayout(LayoutKind.Sequential)] - internal readonly struct MeshVertex - { - private readonly Vector3 _position; - private readonly Vector3 _normal; - private readonly Color _color; - private readonly Vector2 _texCoord0; - private readonly Vector2 _texCoord1; - - public MeshVertex( - Vector3 position, - Vector3 normal, - Vector2 texCoord0, - Vector2 texCoord1, - Color color) - { - _position = position; - _normal = normal; - _texCoord0 = texCoord0; - _texCoord1 = texCoord1; - _color = color; - } - - public static VertexAttributeDescriptor[] GetVertexAttributeDescriptor() => new[] { - new VertexAttributeDescriptor(VertexAttribute.Position), - new VertexAttributeDescriptor(VertexAttribute.Normal), - new VertexAttributeDescriptor(VertexAttribute.Color, dimension: 4), - new VertexAttributeDescriptor(VertexAttribute.TexCoord0, dimension: 2), - new VertexAttributeDescriptor(VertexAttribute.TexCoord1, dimension: 2) - }; - } -} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex0.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex0.cs new file mode 100644 index 000000000..ebe1ca7f2 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex0.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace UniGLTF +{ + /// + /// Stream0用のインターリーブされたメッシュの頂点情報 + /// そのままGPUにアップロードされる + /// + [Serializable, StructLayout(LayoutKind.Sequential)] + internal readonly struct MeshVertex0 + { + private readonly Vector3 _position; + private readonly Vector3 _normal; + + public MeshVertex0( + Vector3 position, + Vector3 normal) + { + _position = position; + _normal = normal; + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex0.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex0.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex1.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex1.cs new file mode 100644 index 000000000..4238efab9 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex1.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace UniGLTF +{ + /// + /// Stream1用のインターリーブされたメッシュの頂点情報 + /// そのままGPUにアップロードされる + /// + [Serializable, StructLayout(LayoutKind.Sequential)] + internal readonly struct MeshVertex1 + { + private readonly Color _color; + private readonly Vector2 _texCoord0; + private readonly Vector2 _texCoord1; + + public MeshVertex1( + Vector2 texCoord0, + Vector2 texCoord1, + Color color) + { + _texCoord0 = texCoord0; + _texCoord1 = texCoord1; + _color = color; + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex1.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex1.cs.meta new file mode 100644 index 000000000..c782ce77c --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex1.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 206d5584ba9a43079f9f09ad067c5c34 +timeCreated: 1663145915 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinnedMeshVertex.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex2.cs similarity index 68% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinnedMeshVertex.cs rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex2.cs index 5850aff65..bf07194b0 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinnedMeshVertex.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex2.cs @@ -1,15 +1,14 @@ using System; using System.Runtime.InteropServices; -using UnityEngine.Rendering; namespace UniGLTF { /// - /// インターリーブされたメッシュの頂点情報のうち、SkinnedMeshに関連した情報を表す構造体 + /// Stream2用のインターリーブされたメッシュの頂点情報 /// そのままGPUにアップロードされる /// [Serializable, StructLayout(LayoutKind.Sequential)] - internal readonly struct SkinnedMeshVertex + internal readonly struct MeshVertex2 { private readonly float _boneWeight0; private readonly float _boneWeight1; @@ -20,7 +19,7 @@ namespace UniGLTF private readonly ushort _boneIndex2; private readonly ushort _boneIndex3; - public SkinnedMeshVertex( + public MeshVertex2( ushort boneIndex0, ushort boneIndex1, ushort boneIndex2, @@ -39,10 +38,5 @@ namespace UniGLTF _boneWeight2 = boneWeight2; _boneWeight3 = boneWeight3; } - - public static VertexAttributeDescriptor[] GetVertexAttributeDescriptor() => new[] { - new VertexAttributeDescriptor(VertexAttribute.BlendWeight, dimension: 4), - new VertexAttributeDescriptor(VertexAttribute.BlendIndices, VertexAttributeFormat.UInt16, 4), - }; } } \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinnedMeshVertex.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex2.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinnedMeshVertex.cs.meta rename to Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex2.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertexUtility.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertexUtility.cs new file mode 100644 index 000000000..5a2c332bc --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertexUtility.cs @@ -0,0 +1,37 @@ +using UnityEngine; +using UnityEngine.Rendering; + +namespace UniGLTF +{ + internal readonly struct MeshVertexUtility + { + + public static void SetVertexBufferParamsToMesh(Mesh mesh, int length, bool useBlendWeight) + { + if (useBlendWeight) + { + mesh.SetVertexBufferParams(length, new VertexAttributeDescriptor[] + { + new VertexAttributeDescriptor(VertexAttribute.Position, stream: 0), + new VertexAttributeDescriptor(VertexAttribute.Normal, stream: 0), + new VertexAttributeDescriptor(VertexAttribute.Color, dimension: 4, stream: 1), + new VertexAttributeDescriptor(VertexAttribute.TexCoord0, dimension: 2, stream: 1), + new VertexAttributeDescriptor(VertexAttribute.TexCoord1, dimension: 2, stream: 1), + new VertexAttributeDescriptor(VertexAttribute.BlendWeight, dimension: 4, stream: 2), + new VertexAttributeDescriptor(VertexAttribute.BlendIndices, VertexAttributeFormat.UInt16, 4, 2), + }); + } + else + { + mesh.SetVertexBufferParams(length, new VertexAttributeDescriptor[] + { + new VertexAttributeDescriptor(VertexAttribute.Position, stream: 0), + new VertexAttributeDescriptor(VertexAttribute.Normal, stream: 0), + new VertexAttributeDescriptor(VertexAttribute.Color, dimension: 4, stream: 1), + new VertexAttributeDescriptor(VertexAttribute.TexCoord0, dimension: 2, stream: 1), + new VertexAttributeDescriptor(VertexAttribute.TexCoord1, dimension: 2, stream: 1), + }); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertexUtility.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertexUtility.cs.meta new file mode 100644 index 000000000..2afa40114 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertexUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6cf1507df80846d0aeb9ab663677881a +timeCreated: 1663146711 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshWithMaterials.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshWithMaterials.cs index 42c2e11d4..0b6e46aba 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshWithMaterials.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshWithMaterials.cs @@ -9,7 +9,12 @@ namespace UniGLTF public Mesh Mesh; public Material[] Materials; + /// + /// SkinningInfo.ShouldSetRendererNodeAsBone を伝播させる。 + /// + public bool ShouldSetRendererNodeAsBone = false; + // 複数のノードから参照されうる - public List Renderers=new List(); // SkinnedMeshRenderer or MeshRenderer + public List Renderers = new List(); // SkinnedMeshRenderer or MeshRenderer } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs index 17f5fe0c5..860abb4ca 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs @@ -146,11 +146,129 @@ namespace UniGLTF return result; } + /// + /// glTF 仕様では VEC3/VEC4 x float/unsigned byte normalized/unsigned short normalized + /// がある。 + /// public static NativeArray? GetColors(this glTFPrimitives primitives, GltfData data, int positionsLength) { if (!HasColor(primitives)) return null; - switch (data.GLTF.accessors[primitives.attributes.COLOR_0].TypeCount) + var accessor = data.GLTF.accessors[primitives.attributes.COLOR_0]; + switch (accessor.componentType) + { + case glComponentType.UNSIGNED_BYTE: + return GetColorsUInt8(primitives, data, positionsLength); + case glComponentType.UNSIGNED_SHORT: + return GetColorsUInt16(primitives, data, positionsLength); + case glComponentType.FLOAT: + return GetColorsFloat(primitives, data, positionsLength); + default: + throw new NotImplementedException( + $"unknown color type {accessor.componentType}"); + } + } + + /// unsigned byte normalized => f = c / 255.0 + public static NativeArray? GetColorsUInt8(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + if (!HasColor(primitives)) return null; + + var accessor = data.GLTF.accessors[primitives.attributes.COLOR_0]; + switch (accessor.TypeCount) + { + case 3: + { + var vec3Color = data.GetArrayFromAccessor(primitives.attributes.COLOR_0); + if (vec3Color.Length != positionsLength) + { + throw new Exception("different length"); + } + var colors = data.NativeArrayManager.CreateNativeArray(vec3Color.Length); + + for (var index = 0; index < vec3Color.Length; index++) + { + var color = vec3Color[index]; + colors[index] = new Color(color.x / 255.0f, color.y / 255.0f, color.z / 255.0f); + } + return colors; + } + + case 4: + { + var vec4Color = data.GetArrayFromAccessor(primitives.attributes.COLOR_0); + if (vec4Color.Length != positionsLength) + { + throw new Exception("different length"); + } + var colors = data.NativeArrayManager.CreateNativeArray(vec4Color.Length); + + for (var index = 0; index < vec4Color.Length; index++) + { + var color = vec4Color[index]; + colors[index] = new Color(color.x / 255.0f, color.y / 255.0f, color.z / 255.0f, color.w / 255.0f); + } + return colors; + } + + default: + throw new NotImplementedException($"unknown color type {accessor.type}"); + } + } + + /// unsigned short normalized => c = round(f * 65535.0) + public static NativeArray? GetColorsUInt16(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + if (!HasColor(primitives)) return null; + + var accessor = data.GLTF.accessors[primitives.attributes.COLOR_0]; + switch (accessor.TypeCount) + { + case 3: + { + var vec3Color = data.GetArrayFromAccessor(primitives.attributes.COLOR_0); + if (vec3Color.Length != positionsLength) + { + throw new Exception("different length"); + } + var colors = data.NativeArrayManager.CreateNativeArray(vec3Color.Length); + + for (var index = 0; index < vec3Color.Length; index++) + { + var color = vec3Color[index]; + colors[index] = new Color(color.x / 65535.0f, color.y / 65535.0f, color.z / 65535.0f); + } + return colors; + } + + case 4: + { + var vec4Color = data.GetArrayFromAccessor(primitives.attributes.COLOR_0); + if (vec4Color.Length != positionsLength) + { + throw new Exception("different length"); + } + var colors = data.NativeArrayManager.CreateNativeArray(vec4Color.Length); + + for (var index = 0; index < vec4Color.Length; index++) + { + var color = vec4Color[index]; + colors[index] = new Color(color.x / 65535.0f, color.y / 65535.0f, color.z / 65535.0f, color.w / 65535.0f); + } + return colors; + } + + default: + throw new NotImplementedException($"unknown color type {accessor.type}"); + } + } + + public static NativeArray? GetColorsFloat(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + if (!HasColor(primitives)) return null; + + var accessor = data.GLTF.accessors[primitives.attributes.COLOR_0]; + switch (accessor.TypeCount) { case 3: { @@ -166,17 +284,17 @@ namespace UniGLTF var color = vec3Color[index]; colors[index] = new Color(color.x, color.y, color.z); } - return colors; } + case 4: var result = data.GetArrayFromAccessor(primitives.attributes.COLOR_0); if (result.Length != positionsLength) { throw new Exception("different length"); } - return result; + default: throw new NotImplementedException( $"unknown color type {data.GLTF.accessors[primitives.attributes.COLOR_0].type}"); diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinningInfo.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinningInfo.cs new file mode 100644 index 000000000..eb26853fd --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinningInfo.cs @@ -0,0 +1,109 @@ +namespace UniGLTF +{ + class SkinningInfo + { + public JointsAccessor.Getter Joints; + public WeightsAccessor.Getter Weights; + + /// + /// gltfMesh に morphTarget が有る場合に、Unity では boneWeight の有無と無関係に UnityEngine.SkinnedMeshRenderer を使います。 + /// そのため `boneWeight が無い` UnityEngine.SkinnedMeshRenderer となる場合があります。 + /// boneWeight の無い SkinnedMeshRenderer の rootBone は、 + /// + /// * boundingBox の中心 + /// * boneWeight の無いボーンに対するスキニング + /// + /// が兼用になるためメッシュが正しく描画されない場合があります。 + /// この問題の対策として、全頂点に対して boneWeight = 1, boneJoint = 0 を付与します。 + /// この boneWeight を利用するために AddComponent する段階で、 + /// + /// * mesh.bindMatrices + /// * SkinnedMeshRenderer.bones = new Transform[]{ renderer.transform }; + /// + /// が必要です。この変数はその指示です。 + /// + public bool ShouldSetRendererNodeAsBone { get; private set; } + + public static SkinningInfo Create(GltfData data, glTFMesh mesh, glTFPrimitives primitives) + { + var hasMorphTarget = HasMorphTarget(mesh); + + var positions = data.GLTF.accessors[primitives.attributes.POSITION]; + var skinning = new SkinningInfo + { + Joints = primitives.GetJoints(data, positions.count), + Weights = primitives.GetWeights(data, positions.count), + }; + + if (skinning.Joints != null) + { + // use SkinnedMeshRenderer + return skinning; + } + else if (!hasMorphTarget) + { + // use MeshRenderer + return skinning; + } + else + { + // use SkinnedMeshRenderer without boneWeight. + // https://github.com/vrm-c/UniVRM/issues/1675 + return new SkinningInfo + { + ShouldSetRendererNodeAsBone = true, + Joints = _ => (0, 0, 0, 0), + Weights = _ => (1, 0, 0, 0), // assign weight 1 + }; + } + } + + static bool HasMorphTarget(glTFMesh mesh) + { + foreach (var prim in mesh.primitives) + { + if (prim.targets != null && prim.targets.Count > 0) + { + return true; + } + } + return false; + } + + private static (float x, float y, float z, float w) NormalizeBoneWeight( + (float x, float y, float z, float w) src) + { + var sum = src.x + src.y + src.z + src.w; + if (sum == 0) + { + return src; + } + + var f = 1.0f / sum; + src.x *= f; + src.y *= f; + src.z *= f; + src.w *= f; + return src; + } + + public MeshVertex2? GetSkinnedVertex(int i) + { + if (Joints == null) + { + return default; + } + var joints = Joints?.Invoke(i) ?? (0, 0, 0, 0); + var weights = Weights != null ? NormalizeBoneWeight(Weights(i)) : (0, 0, 0, 0); + return new MeshVertex2( + joints.x, + joints.y, + joints.z, + joints.w, + weights.x, + weights.y, + weights.z, + weights.w); + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinningInfo.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinningInfo.cs.meta new file mode 100644 index 000000000..2dc28d998 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MeshIO/SkinningInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 06927c8487024f541b525aa3bd3e572b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MigrationFlags.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MigrationFlags.cs index 1dfa79e80..10b39a7d6 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MigrationFlags.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/MigrationFlags.cs @@ -2,9 +2,22 @@ { public sealed class MigrationFlags { + /// + /// Before UniGLTF v0.54.0, Built-in RP Standard shader and Unlit shaders' albedo color is exported in gamma color space. + /// https://github.com/vrm-c/UniVRM/pull/339 + /// + public bool IsBaseColorFactorGamma { get; set; } + /// /// Before UniGLTF v0.69, roughness value in the texture was invalid squared value. + /// https://github.com/vrm-c/UniVRM/pull/780 /// public bool IsRoughnessTextureValueSquared { get; set; } = false; + + /// + /// Before UniGLTF v0.107.0, Built-in RP Standard shader's emission color is exported in gamma color space. + /// https://github.com/vrm-c/UniVRM/pull/1909 + /// + public bool IsEmissiveFactorGamma { get; set; } = false; } } \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs index 48f646e2e..df8e4832e 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/NodeImporter.cs @@ -119,6 +119,20 @@ namespace UniGLTF renderer.sharedMaterials = mesh.Materials; // invisible in loading renderer.enabled = false; + + if (mesh.ShouldSetRendererNodeAsBone ) + { + renderer.bones = new[] { renderer.transform }; + + // + // calc default matrices + // https://docs.unity3d.com/ScriptReference/Mesh-bindposes.html + // + var meshCoords = renderer.transform; + var calculatedBindPoses = renderer.bones.Select(bone => bone.worldToLocalMatrix * meshCoords.localToWorldMatrix).ToArray(); + mesh.Mesh.bindposes = calculatedBindPoses; + } + mesh.Renderers.Add(renderer); } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs index bdb31f01d..ce3d4e5aa 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs @@ -172,16 +172,19 @@ namespace UniGLTF for (var textureIdx = 0; textureIdx < GLTF.textures.Count; ++textureIdx) { var gltfTexture = GLTF.textures[textureIdx]; - var gltfImage = GLTF.images[gltfTexture.source]; - if (!string.IsNullOrEmpty(gltfImage.uri) && !gltfImage.uri.StartsWith("data:")) + if (gltfTexture.source.HasValidIndex()) { - // from image uri - gltfTexture.name = Path.GetFileNameWithoutExtension(gltfImage.uri); - } - if (string.IsNullOrEmpty(gltfTexture.name)) - { - // use image name - gltfTexture.name = gltfImage.name; + var gltfImage = GLTF.images[gltfTexture.source.Value]; + if (!string.IsNullOrEmpty(gltfImage.uri) && !gltfImage.uri.StartsWith("data:")) + { + // from image uri + gltfTexture.name = Path.GetFileNameWithoutExtension(gltfImage.uri); + } + if (string.IsNullOrEmpty(gltfTexture.name)) + { + // use image name + gltfTexture.name = gltfImage.name; + } } if (string.IsNullOrEmpty(gltfTexture.name)) { diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfPbrTextureImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfPbrTextureImporter.cs index 5d7ab1dfa..e8fc3e10b 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfPbrTextureImporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfPbrTextureImporter.cs @@ -15,7 +15,10 @@ namespace UniGLTF // base color if (m.pbrMetallicRoughness?.baseColorTexture != null) { - yield return BaseColorTexture(data, m); + if (TryBaseColorTexture(data, m, out var key, out var desc)) + { + yield return (key, desc); + } } // metallic roughness @@ -28,13 +31,19 @@ namespace UniGLTF // emission if (m.emissiveTexture != null) { - yield return EmissiveTexture(data, m); + if (TryEmissiveTexture(data, m, out var key, out var desc)) + { + yield return (key, desc); + } } // normal if (m.normalTexture != null) { - yield return NormalTexture(data, m); + if (TryNormalTexture(data, m, out var key, out var desc)) + { + yield return (key, desc); + } } // occlusion @@ -47,17 +56,20 @@ namespace UniGLTF // metallicSmooth and occlusion if (metallicRoughnessTexture.HasValue || occlusionTexture.HasValue) { - yield return StandardTexture(data, m); + if (TryStandardTexture(data, m, out var key, out var desc)) + { + yield return (key, desc); + } } } - public static (SubAssetKey, TextureDescriptor) BaseColorTexture(GltfData data, glTFMaterial src) + public static bool TryBaseColorTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture); - return GltfTextureImporter.CreateSrgb(data, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale); + return GltfTextureImporter.TryCreateSrgb(data, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale, out key, out desc); } - public static (SubAssetKey, TextureDescriptor) StandardTexture(GltfData data, glTFMaterial src) + public static bool TryStandardTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { var metallicFactor = 1.0f; var roughnessFactor = 1.0f; @@ -67,25 +79,24 @@ namespace UniGLTF roughnessFactor = src.pbrMetallicRoughness.roughnessFactor; } var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture); - return GltfTextureImporter.CreateStandard(data, + return GltfTextureImporter.TryCreateStandard(data, src.pbrMetallicRoughness?.metallicRoughnessTexture?.index, src.occlusionTexture?.index, offset, scale, metallicFactor, - roughnessFactor); + roughnessFactor, out key, out desc); } - public static (SubAssetKey, TextureDescriptor) NormalTexture(GltfData data, glTFMaterial src) + public static bool TryNormalTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.normalTexture); - return GltfTextureImporter.CreateNormal(data, src.normalTexture.index, offset, scale); + return GltfTextureImporter.TryCreateNormal(data, src.normalTexture.index, offset, scale, out key, out desc); } - public static (SubAssetKey, TextureDescriptor) EmissiveTexture(GltfData data, glTFMaterial src) + public static bool TryEmissiveTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.emissiveTexture); - return GltfTextureImporter.CreateSrgb(data, src.emissiveTexture.index, offset, scale); + return GltfTextureImporter.TryCreateSrgb(data, src.emissiveTexture.index, offset, scale, out key, out desc); } - } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs index bde1d5d2b..659288f37 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs @@ -12,6 +12,8 @@ namespace UniGLTF /// public static class GltfTextureImporter { + public static bool ImportKhrTextureBasisuExtension { get; set; } = true; + /// /// glTF の Texture が存在せず Image のみのものを、Texture として扱いたい場合の関数. /// @@ -29,37 +31,54 @@ namespace UniGLTF () => { var imageBytes = data.GetBytesFromImage(imageIndex); - return Task.FromResult<(byte[], string)?>((ToArray(imageBytes?.binary ?? default), null)); + return Task.FromResult<(byte[], string)?>((ToArray(imageBytes?.binary ?? default), imageBytes?.mimeType)); }, default, default, default, default, default); return (texDesc.SubAssetKey, texDesc); } - public static (SubAssetKey, TextureDescriptor) CreateSrgb(GltfData data, int textureIndex, Vector2 offset, Vector2 scale) + public static bool TryCreateSrgb(GltfData data, int textureIndex, Vector2 offset, Vector2 scale, out SubAssetKey key, out TextureDescriptor desc) { var gltfTexture = data.GLTF.textures[textureIndex]; - var gltfImage = data.GLTF.images[gltfTexture.source]; + var imageIndex = GetImageIndexFromTextureIndex(data, textureIndex); + if (!imageIndex.HasValue) + { + key = default; + desc = default; + return false; + } + + var gltfImage = data.GLTF.images[imageIndex.Value]; var name = TextureImportName.GetUnityObjectName(TextureImportTypes.sRGB, gltfTexture.name, gltfImage.uri); var sampler = TextureSamplerUtil.CreateSampler(data.GLTF, textureIndex); - var param = new TextureDescriptor( + desc = new TextureDescriptor( name, offset, scale, sampler, TextureImportTypes.sRGB, default, default, - () => Task.FromResult(GetImageBytesFromTextureIndex(data, textureIndex)), + () => Task.FromResult(GetImageBytesFromImageIndex(data, imageIndex.Value)), default, default, default, default, default); - return (param.SubAssetKey, param); + key = desc.SubAssetKey; + return true; } - public static (SubAssetKey, TextureDescriptor) CreateLinear(GltfData data, int textureIndex, Vector2 offset, Vector2 scale) + public static bool TryCreateLinear(GltfData data, int textureIndex, Vector2 offset, Vector2 scale, out SubAssetKey key, out TextureDescriptor desc) { var gltfTexture = data.GLTF.textures[textureIndex]; - var gltfImage = data.GLTF.images[gltfTexture.source]; + var imageIndex = GetImageIndexFromTextureIndex(data, textureIndex); + if (!imageIndex.HasValue) + { + key = default; + desc = default; + return false; + } + + var gltfImage = data.GLTF.images[imageIndex.Value]; var name = TextureImportName.GetUnityObjectName(TextureImportTypes.Linear, gltfTexture.name, gltfImage.uri); var sampler = TextureSamplerUtil.CreateSampler(data.GLTF, textureIndex); - var param = new TextureDescriptor( + desc = new TextureDescriptor( name, offset, scale, @@ -67,18 +86,27 @@ namespace UniGLTF TextureImportTypes.Linear, default, default, - () => Task.FromResult(GetImageBytesFromTextureIndex(data, textureIndex)), + () => Task.FromResult(GetImageBytesFromImageIndex(data, imageIndex.Value)), default, default, default, default, default); - return (param.SubAssetKey, param); + key = desc.SubAssetKey; + return true; } - public static (SubAssetKey, TextureDescriptor) CreateNormal(GltfData data, int textureIndex, Vector2 offset, Vector2 scale) + public static bool TryCreateNormal(GltfData data, int textureIndex, Vector2 offset, Vector2 scale, out SubAssetKey key, out TextureDescriptor desc) { var gltfTexture = data.GLTF.textures[textureIndex]; - var gltfImage = data.GLTF.images[gltfTexture.source]; + var imageIndex = GetImageIndexFromTextureIndex(data, textureIndex); + if (!imageIndex.HasValue) + { + key = default; + desc = default; + return false; + } + + var gltfImage = data.GLTF.images[imageIndex.Value]; var name = TextureImportName.GetUnityObjectName(TextureImportTypes.NormalMap, gltfTexture.name, gltfImage.uri); var sampler = TextureSamplerUtil.CreateSampler(data.GLTF, textureIndex); - var param = new TextureDescriptor( + desc = new TextureDescriptor( name, offset, scale, @@ -86,49 +114,77 @@ namespace UniGLTF TextureImportTypes.NormalMap, default, default, - () => Task.FromResult(GetImageBytesFromTextureIndex(data, textureIndex)), + () => Task.FromResult(GetImageBytesFromImageIndex(data, imageIndex.Value)), default, default, default, default, default); - return (param.SubAssetKey, param); + key = desc.SubAssetKey; + return true; } - public static (SubAssetKey, TextureDescriptor) CreateStandard(GltfData data, int? metallicRoughnessTextureIndex, int? occlusionTextureIndex, Vector2 offset, Vector2 scale, float metallicFactor, float roughnessFactor) + public static bool TryCreateStandard(GltfData data, int? metallicRoughnessTextureIndex, int? occlusionTextureIndex, Vector2 offset, Vector2 scale, float metallicFactor, float roughnessFactor, out SubAssetKey key, out TextureDescriptor desc) { string name = default; - + SamplerParam? sampler = default; GetTextureBytesAsync getMetallicRoughnessAsync = default; - SamplerParam sampler = default; + GetTextureBytesAsync getOcclusionAsync = default; + if (metallicRoughnessTextureIndex.HasValue) { var gltfTexture = data.GLTF.textures[metallicRoughnessTextureIndex.Value]; - name = TextureImportName.GetUnityObjectName(TextureImportTypes.StandardMap, gltfTexture.name, data.GLTF.images[gltfTexture.source].uri); - sampler = TextureSamplerUtil.CreateSampler(data.GLTF, metallicRoughnessTextureIndex.Value); - getMetallicRoughnessAsync = () => Task.FromResult(GetImageBytesFromTextureIndex(data, metallicRoughnessTextureIndex.Value)); + var imageIndex = GetImageIndexFromTextureIndex(data, metallicRoughnessTextureIndex.Value); + if (imageIndex.HasValue) + { + var gltfImage = data.GLTF.images[imageIndex.Value]; + name = TextureImportName.GetUnityObjectName(TextureImportTypes.StandardMap, gltfTexture.name, gltfImage.uri); + sampler = TextureSamplerUtil.CreateSampler(data.GLTF, metallicRoughnessTextureIndex.Value); + getMetallicRoughnessAsync = () => Task.FromResult(GetImageBytesFromImageIndex(data, imageIndex.Value)); + } } - GetTextureBytesAsync getOcclusionAsync = default; if (occlusionTextureIndex.HasValue) { var gltfTexture = data.GLTF.textures[occlusionTextureIndex.Value]; - if (string.IsNullOrEmpty(name)) + var imageIndex = GetImageIndexFromTextureIndex(data, occlusionTextureIndex.Value); + if (imageIndex.HasValue) { - name = TextureImportName.GetUnityObjectName(TextureImportTypes.StandardMap, gltfTexture.name, data.GLTF.images[gltfTexture.source].uri); + var gltfImage = data.GLTF.images[imageIndex.Value]; + if (string.IsNullOrEmpty(name)) + { + name = TextureImportName.GetUnityObjectName(TextureImportTypes.StandardMap, gltfTexture.name, gltfImage.uri); + } + if (sampler == null) + { + sampler = TextureSamplerUtil.CreateSampler(data.GLTF, occlusionTextureIndex.Value); + } + getOcclusionAsync = () => Task.FromResult(GetImageBytesFromImageIndex(data, imageIndex.Value)); } - sampler = TextureSamplerUtil.CreateSampler(data.GLTF, occlusionTextureIndex.Value); - getOcclusionAsync = () => Task.FromResult(GetImageBytesFromTextureIndex(data, occlusionTextureIndex.Value)); } - var texDesc = new TextureDescriptor( + if (getMetallicRoughnessAsync == null && getOcclusionAsync == null) + { + key = default; + desc = default; + return false; + } + if (string.IsNullOrEmpty(name)) + { + key = default; + desc = default; + return false; + } + + desc = new TextureDescriptor( name, offset, scale, - sampler, + sampler.Value, TextureImportTypes.StandardMap, metallicFactor, roughnessFactor, getMetallicRoughnessAsync, getOcclusionAsync, default, default, default, default); - return (texDesc.SubAssetKey, texDesc); + key = desc.SubAssetKey; + return true; } public static (Vector2, Vector2) GetTextureOffsetAndScale(glTFTextureInfo textureInfo) @@ -163,43 +219,47 @@ namespace UniGLTF return (offset, scale); } - public static (byte[] binary, string mimeType)? GetImageBytesFromTextureIndex(GltfData data, int textureIndex) + private static (byte[] binary, string mimeType)? GetImageBytesFromImageIndex(GltfData data, int imageIndex) { - if (Application.isPlaying) + if (imageIndex >= 0 && imageIndex < data.GLTF.images.Count) { - // NOTE: Runtime の場合は、拡張を考える. - var imageIndex = GetImageIndexFromTexture(data, textureIndex); - - if (textureIndex >= 0 && textureIndex < data.GLTF.textures.Count) + var imageBytes = data.GetBytesFromImage(imageIndex); + if (imageBytes.HasValue) { - var texture = data.GLTF.textures[textureIndex]; - if (glTF_KHR_texture_basisu.TryGet(texture, out var basisuExtension)) + + return (ToArray(imageBytes.Value.binary), imageBytes.Value.mimeType); + } + } + + return default; + } + + private static int? GetImageIndexFromTextureIndex(GltfData data, int textureIndex) + { + if (textureIndex >= 0 && textureIndex < data.GLTF.textures.Count) + { + var texture = data.GLTF.textures[textureIndex]; + + // NOTE: Runtime の場合は KHR_texture_basisu 拡張を考える. + if (ImportKhrTextureBasisuExtension && + Application.isPlaying && + glTF_KHR_texture_basisu.TryGet(texture, out var basisuExtension)) + { + var basisuImageIndex = basisuExtension.source; + if (basisuImageIndex >= 0 && basisuImageIndex < data.GLTF.images.Count) { - imageIndex = basisuExtension.source; + return basisuImageIndex; } } - if (!imageIndex.HasValue) return default; - - var imageBytes = data.GetBytesFromImage(imageIndex.Value); - return (ToArray(imageBytes?.binary ?? default), imageBytes?.mimeType); + var imageIndex = texture.source; + if (imageIndex >= 0 && imageIndex < data.GLTF.images.Count) + { + return imageIndex; + } } - else - { - // NOTE: Editor の場合は通常通り読み込む. - var imageIndex = GetImageIndexFromTexture(data, textureIndex); - if (!imageIndex.HasValue) return default; - var imageBytes = data.GetBytesFromImage(imageIndex.Value); - return (ToArray(imageBytes?.binary ?? default), imageBytes?.mimeType); - } - } - - private static int? GetImageIndexFromTexture(GltfData data, int textureIndex) - { - if (textureIndex < 0 || textureIndex >= data.GLTF.textures.Count) return default; - - return data.GLTF.textures[textureIndex].source; + return default; } private static byte[] ToArray(NativeArray bytes) diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UShort3.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UShort3.cs new file mode 100644 index 000000000..ce80edd3c --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UShort3.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.InteropServices; + +namespace UniGLTF +{ + [Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)] + public readonly struct UShort3 : IEquatable + { + public readonly ushort x; + public readonly ushort y; + public readonly ushort z; + + public UShort3(ushort _x, ushort _y, ushort _z) + { + x = _x; + y = _y; + z = _z; + } + + public bool Equals(UShort3 other) + { + return x == other.x && y == other.y && z == other.z; + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UShort3.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UShort3.cs.meta new file mode 100644 index 000000000..485f3db62 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UShort3.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 33180f1228cb5fc4cb666ed60c65264c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs index ff74aeedf..8e051c001 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs @@ -2,20 +2,27 @@ using System; using System.IO; using UnityEngine; using System.Collections.Generic; +using System.Linq; #if UNITY_EDITOR using UnityEditor; +using UnityEditor.PackageManager; +using PackageInfo = UnityEditor.PackageManager.PackageInfo; #endif namespace UniGLTF { /// - /// relative path from Unity project root. - /// For AssetDatabase. + /// Manage paths that can be handled by AssetDatabase + /// Supports Assets or editable Package + /// + /// note : Use '\' instead of '/' to delimit folders /// public struct UnityPath { +#if UNITY_EDITOR #region UnityPath + public string Value { get; @@ -32,18 +39,67 @@ namespace UniGLTF get { return Value == null; } } - public bool IsUnderAssetsFolder + /// + /// If under Assets or under an editable Package return true. + /// For historical reasons "Assets" is true. + /// + public bool IsUnderWritableFolder { get { - if (IsNull) + if (IsNull) return false; + + if (PathType == PathType.Assets) return true; + + if (PathType == PathType.Packages) { - return false; + var split = Value.Split('/'); + if (split.Length <= 1) return false; + + var packageDirectory = $"{split[0]}/{split[1]}"; + if (!Directory.Exists(packageDirectory)) return false; + + var packageInfo = GetPackageInfo(packageDirectory); + if (packageInfo == null) return false; + + // Local and Embedded packages are editable + if (packageInfo.source == PackageSource.Local + || packageInfo.source == PackageSource.Embedded) return true; } - return Value == "Assets" || Value.FastStartsWith("Assets/"); + + return false; } } + /// + /// Recursively check if path is included in local packages + /// + /// + /// + private static PackageInfo GetPackageInfo(string path) + { + if (string.IsNullOrWhiteSpace(path)) return null; + + var packageInfo = PackageList.Find(x => x.resolvedPath == path || x.assetPath == path); + if (packageInfo != null) + { + return packageInfo; + } + + return GetPackageInfo(Path.GetDirectoryName(path)); + } + + /// + /// List of packages loaded in unity + /// + private static readonly List PackageList + = AssetDatabase.FindAssets("package") + .Select(AssetDatabase.GUIDToAssetPath) + .Where(x => AssetDatabase.LoadAssetAtPath(x) != null) + .Select(PackageInfo.FindForAssetPath) + .Where(x => x != null) + .ToList(); + public bool IsStreamingAsset { get @@ -93,6 +149,34 @@ namespace UniGLTF } } + public PathType PathType + { + get + { + if (string.IsNullOrEmpty(Value)) + { + return PathType.Unsupported; + } + if (Value == "Assets" || Value.FastStartsWith("Assets/")) + { + // #1941 + return PathType.Assets; + } + + var directory = Path.GetDirectoryName(Value); + var rootDirectoryName = directory.Split(Path.DirectorySeparatorChar); + switch (rootDirectoryName[0]) + { + case "Assets": + return PathType.Assets; + case "Packages": + return PathType.Packages; + default: + return PathType.Unsupported; + } + } + } + static readonly char[] EscapeChars = new char[] { '\\', @@ -127,7 +211,7 @@ namespace UniGLTF } else { - return new UnityPath(Value + "/" + name); + return new UnityPath($"{Value}/{name}"); } } @@ -176,7 +260,7 @@ namespace UniGLTF /// public UnityPath GetAssetFolder(string suffix) { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -201,14 +285,21 @@ namespace UniGLTF /// public static UnityPath FromUnityPath(string unityPath) { - if (String.IsNullOrEmpty(unityPath)) + if (unityPath == null) + { + return new UnityPath + { + Value = null + }; + } + if (unityPath == "" || unityPath == ".") { return new UnityPath { Value = "" }; } - return FromFullpath(Path.GetFullPath(unityPath)); + return new UnityPath(unityPath); } #endregion @@ -226,14 +317,6 @@ namespace UniGLTF } } - static string AssetFullPath - { - get - { - return BaseFullPath + "/Assets"; - } - } - public string FullPath { get @@ -242,7 +325,7 @@ namespace UniGLTF { throw new NotImplementedException(); } - return Path.Combine(BaseFullPath, Value).Replace("\\", "/"); + return Path.GetFullPath(Value == "" ? "." : Value).Replace("\\", "/"); } } @@ -271,24 +354,24 @@ namespace UniGLTF if (fullPath == BaseFullPath) { - return new UnityPath - { - Value = "" - }; + return new UnityPath(""); } - else if (fullPath.FastStartsWith(BaseFullPath + "/")) + + if (fullPath.FastStartsWith($"{BaseFullPath}/Assets")) { return new UnityPath(fullPath.Substring(BaseFullPath.Length + 1)); } - else - { - return default(UnityPath); - } - } - public static bool IsUnderAssetFolder(string fullPath) - { - return fullPath.Replace("\\", "/").FastStartsWith(AssetFullPath); + var packageInfo = GetPackageInfo(fullPath); + if (packageInfo != null) + { + var packagePath = packageInfo.assetPath; + var fileName = fullPath.Substring(packageInfo.resolvedPath.Length + 1); + var relativePath = $"{packagePath}/{fileName}"; + return new UnityPath(relativePath); + } + + return default(UnityPath); } #endregion @@ -336,15 +419,14 @@ namespace UniGLTF } } -#if UNITY_EDITOR public T GetImporter() where T : AssetImporter { return AssetImporter.GetAtPath(Value) as T; } public static UnityPath FromAsset(UnityEngine.Object asset) - { - var assetPath = AssetDatabase.GetAssetPath(asset); + { + var assetPath = AssetDatabase.GetAssetPath(asset); if (string.IsNullOrEmpty(assetPath)) { throw new System.ArgumentNullException(); @@ -354,7 +436,7 @@ namespace UniGLTF public void ImportAsset() { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -365,7 +447,7 @@ namespace UniGLTF { if (IsNull) { - throw new NotImplementedException(); + return; } if (HasParent) @@ -389,7 +471,7 @@ namespace UniGLTF public UnityEngine.Object[] GetSubAssets() { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -399,7 +481,7 @@ namespace UniGLTF public void CreateAsset(UnityEngine.Object o) { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -421,7 +503,7 @@ namespace UniGLTF public void AddObjectToAsset(UnityEngine.Object o) { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -431,7 +513,7 @@ namespace UniGLTF public T LoadAsset() where T : UnityEngine.Object { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -441,7 +523,7 @@ namespace UniGLTF public UnityPath GenerateUniqueAssetPath() { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -450,4 +532,11 @@ namespace UniGLTF } #endif } + + public enum PathType + { + Assets, + Packages, + Unsupported, + } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs index 03db82d3c..8fcc316a4 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs @@ -48,19 +48,7 @@ namespace UniGLTF protected virtual IMaterialExporter CreateMaterialExporter() { - return new MaterialExporter(); - } - - /// - /// このエクスポーターがサポートするExtension - /// - protected virtual IEnumerable ExtensionUsed - { - get - { - yield return glTF_KHR_materials_unlit.ExtensionName; - yield return glTF_KHR_texture_transform.ExtensionName; - } + return new BuiltInGltfMaterialExporter(); } protected ITextureExporter TextureExporter => _textureExporter; @@ -86,8 +74,6 @@ namespace UniGLTF { _data = data; - _gltf.extensionsUsed.AddRange(ExtensionUsed); - _gltf.asset = new glTFAssets { generator = "UniGLTF-" + UniGLTFVersion.VERSION, @@ -158,6 +144,8 @@ namespace UniGLTF { GameObject.Destroy(Copy); } + + _textureExporter.Dispose(); } #region Export @@ -176,7 +164,7 @@ namespace UniGLTF { var meshRenderer = x.GetComponent(); - if (meshRenderer != null) + if (meshRenderer != null && meshRenderer.enabled) { var meshFilter = x.GetComponent(); if (meshFilter != null) @@ -206,7 +194,7 @@ namespace UniGLTF } var skinnedMeshRenderer = x.GetComponent(); - if (skinnedMeshRenderer != null) + if (skinnedMeshRenderer != null && skinnedMeshRenderer.enabled) { var mesh = skinnedMeshRenderer.sharedMesh; var materials = skinnedMeshRenderer.sharedMaterials; @@ -353,7 +341,7 @@ namespace UniGLTF } /// - /// GlbLowPevelParser.FixNameUnique で付与した Suffix を remove + /// GlbLowLevelParser.FixNameUnique で付与した Suffix を remove /// public static void FixName(glTF gltf) { diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersion.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersion.cs new file mode 100644 index 000000000..705a3c3cd --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersion.cs @@ -0,0 +1,11 @@ + +namespace UniGLTF +{ + public static partial class PackageVersion + { + public const int MAJOR = 0; + public const int MINOR = 120; + public const int PATCH = 0; + public const string VERSION = "0.120.0"; + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersion.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersion.cs.meta new file mode 100644 index 000000000..d61dbbf3b --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersion.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab81045d7751d4040b553ecbac5ab9e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersionPartial.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersionPartial.cs new file mode 100644 index 000000000..402dc4928 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersionPartial.cs @@ -0,0 +1,111 @@ +using System; +using System.Text.RegularExpressions; + +namespace UniGLTF +{ + public static partial class PackageVersion + { + /// + /// Returns true if a passed version is newer than current UniVRM. + /// + /// + /// + public static bool IsNewer(string version) + { + if (string.IsNullOrEmpty(version)) + { + return false; + } + + var prefix = "UniVRM-"; + if (version.StartsWith(prefix)) + { + version = version.Substring(prefix.Length); + } + + return IsNewer(version, VERSION); + } + + public static bool IsNewer(string newer, string older) + { + Version newerVersion; + if (!ParseVersion(newer, out newerVersion)) + { + return false; + } + + Version olderVersion; + if (!ParseVersion(older, out olderVersion)) + { + return false; + } + + return IsNewer(newerVersion, olderVersion); + } + + public static bool IsNewer(Version newerVersion, Version olderVersion) + { + if (newerVersion.Major > olderVersion.Major) + { + return true; + } + + if (newerVersion.Minor > olderVersion.Minor) + { + return true; + } + + if (newerVersion.Patch > olderVersion.Patch) + { + return true; + } + + if (string.CompareOrdinal(newerVersion.Pre, olderVersion.Pre) > 0) + { + return true; + } + + return false; + } + + private static readonly Regex VersionSpec = + new Regex(@"(?\d+)\.(?\d+)(\.(?\d+))?(-(?
[0-9A-Za-z-]+))?");
+
+        public static bool ParseVersion(string version, out Version v)
+        {
+            var match = VersionSpec.Match(version);
+            if (!match.Success)
+            {
+                v = new Version();
+                return false;
+            }
+
+            v = new Version();
+            try
+            {
+                v.Major = int.Parse(match.Groups["major"].Value);
+                v.Minor = int.Parse(match.Groups["minor"].Value);
+                v.Patch = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0;
+                v.Pre = match.Groups["pre"].Success ? match.Groups["pre"].Value : "";
+
+                return true;
+            }
+            catch (Exception)
+            {
+                return false;
+            }
+        }
+
+        public struct Version
+        {
+            public int Major;
+            public int Minor;
+            public int Patch;
+            public string Pre;
+        }
+
+        public const string VRM_VERSION = "UniVRM-" + VERSION;
+        public const string MENU = "VRM0";
+        public const string MENU_NAME = "Version: " + PackageVersion.VRM_VERSION;
+    }
+}
diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersionPartial.cs.meta b/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersionPartial.cs.meta
new file mode 100644
index 000000000..ce011769d
--- /dev/null
+++ b/Assets/External/UniGLTF/Runtime/UniGLTF/PackageVersionPartial.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a025b7dc17054bb41ae56d364d78d120
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs
index 49f7a2143..73c3e7a33 100644
--- a/Assets/External/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs
+++ b/Assets/External/UniGLTF/Runtime/UniGLTF/RuntimeGltfInstance.cs
@@ -1,5 +1,5 @@
 using System.Collections.Generic;
-using System.Linq;
+using UniGLTF.Utils;
 using UnityEngine;
 using VRMShaders;
 
@@ -22,6 +22,11 @@ namespace UniGLTF
         /// 
public IReadOnlyList Nodes => _nodes; + /// + /// Transform states on load. + /// + public IReadOnlyDictionary InitialTransformStates => _initialTransformStates; + /// /// Runtime resources. /// ex. Material, Texture, AnimationClip, Mesh. @@ -73,6 +78,7 @@ namespace UniGLTF public IList VisibleRenderers => _visibleRenderers; private readonly List _nodes = new List(); + private readonly Dictionary _initialTransformStates = new Dictionary(); private readonly List<(SubAssetKey, UnityEngine.Object)> _resources = new List<(SubAssetKey, UnityEngine.Object)>(); private readonly List _materials = new List(); private readonly List _textures = new List(); @@ -92,6 +98,7 @@ namespace UniGLTF { // Maintain index order. loaded._nodes.Add(node); + loaded._initialTransformStates.Add(node, new TransformState(node)); } context.TransferOwnership((k, o) => @@ -159,12 +166,71 @@ namespace UniGLTF } } + public void ReplaceResource(UnityEngine.Object oldResource, UnityEngine.Object newResource) + { + if (oldResource == null || newResource == null || oldResource.GetType() != newResource.GetType()) + { + Debug.LogError($"{nameof(RuntimeGltfInstance)} - Could not replace resource: mismatched or null types."); + return; + } + + for (int i = 0; i < _resources.Count; i++) + { + if (_resources[i].Item2 == oldResource) + { + _resources[i] = (_resources[i].Item1, newResource); + break; + } + } + + switch (oldResource) + { + case Texture oldTexture when newResource is Texture newTexture: + int texIndex = _textures.IndexOf(oldTexture); + if (texIndex != -1) + { + _textures[texIndex] = newTexture; + } + break; + + case Material oldMaterial when newResource is Material newMaterial: + int matIndex = _materials.IndexOf(oldMaterial); + if (matIndex != -1) + { + _materials[matIndex] = newMaterial; + } + break; + + case AnimationClip oldClip when newResource is AnimationClip newClip: + int clipIndex = _animationClips.IndexOf(oldClip); + if (clipIndex != -1) + { + _animationClips[clipIndex] = newClip; + } + break; + + case Mesh oldMesh when newResource is Mesh newMesh: + int meshIndex = _meshes.IndexOf(oldMesh); + if (meshIndex != -1) + { + _meshes[meshIndex] = newMesh; + } + break; + } + + Destroy(oldResource); + } + + public void AddResource(T resource) where T : UnityEngine.Object + { + _resources.Add((SubAssetKey.Create(resource), resource)); + } + void OnDestroy() { - Debug.Log("UnityResourceDestroyer.OnDestroy"); foreach (var (_, obj) in _resources) { - UnityObjectDestoyer.DestroyRuntimeOrEditor(obj); + UnityObjectDestroyer.DestroyRuntimeOrEditor(obj); } } @@ -181,7 +247,7 @@ namespace UniGLTF { if (this != null && this.gameObject != null) { - UnityObjectDestoyer.DestroyRuntimeOrEditor(this.gameObject); + UnityObjectDestroyer.DestroyRuntimeOrEditor(this.gameObject); } } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/UniGLTFVersion.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/UniGLTFVersion.cs index 1a06bbd57..50e41ded2 100644 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/UniGLTFVersion.cs +++ b/Assets/External/UniGLTF/Runtime/UniGLTF/UniGLTFVersion.cs @@ -4,8 +4,8 @@ namespace UniGLTF public static partial class UniGLTFVersion { public const int MAJOR = 2; - public const int MINOR = 35; + public const int MINOR = 56; public const int PATCH = 0; - public const string VERSION = "2.35.0"; + public const string VERSION = "2.56.0"; } } diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Util/CacheEnum.cs b/Assets/External/UniGLTF/Runtime/UniGLTF/Util/CacheEnum.cs deleted file mode 100644 index 5c90f6282..000000000 --- a/Assets/External/UniGLTF/Runtime/UniGLTF/Util/CacheEnum.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace UniGLTF -{ - public sealed class CacheEnum - { - public static T Parse(string name, bool ignoreCase = false) where T : struct, Enum - { - if(ignoreCase) - { - return CacheParse.ParseIgnoreCase(name); - } - else - { - return CacheParse.Parse(name); - } - } - - public static T TryParseOrDefault(string name, bool ignoreCase = false, T defaultValue=default(T)) where T : struct, Enum - { - try - { - if(ignoreCase) - { - return CacheParse.ParseIgnoreCase(name); - } - else - { - return CacheParse.Parse(name); - } - } - catch - { - return defaultValue; - } - } - - public static T[] GetValues() where T : struct, Enum - { - return CacheValues.Values; - } - - private static class CacheParse where T : struct, Enum - { - private static Dictionary _values = new Dictionary(); - private static Dictionary _ignoreCaseValues = new Dictionary(StringComparer.OrdinalIgnoreCase); - - static CacheParse() - { - } - - public static T ParseIgnoreCase(string name) - { - if(_ignoreCaseValues.TryGetValue(name, out var value)) - { - return value; - } - else - { - T result; - value = Enum.TryParse(name, true, out result) - ? result - : throw new ArgumentException(nameof(result)); - _ignoreCaseValues.Add(name, value); - return value; - } - } - - public static T Parse(string name) - { - if(_values.TryGetValue(name, out var value)) - { - return value; - } - else - { - T result; - value = Enum.TryParse(name, false, out result) - ? result - : throw new ArgumentException(nameof(result)); - _values.Add(name, value); - return value; - } - } - } - - private static class CacheValues where T : struct, Enum - { - public static readonly T[] Values; - - static CacheValues() - { - Values = Enum.GetValues(typeof(T)) as T[]; - } - } - } -} - diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs index 05a3abd6e..5a7f24a5b 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs @@ -5,10 +5,12 @@ using UnityEngine; using System; using System.Linq; using System.Collections.Generic; +using UniGLTF.Utils; namespace UniHumanoid { + // TODO: BoneLimit.cs に分ける(v0.104以降) [Serializable] public struct BoneLimit { @@ -19,13 +21,34 @@ namespace UniHumanoid public Vector3 max; public Vector3 center; public float axisLength; - private static string[] cashedHumanTraitBoneName = null; + + + // HumanTrait.BoneName は HumanBodyBones.ToString とほぼ一対一に対応するが、 + // 指のボーンについては " " の有無という微妙な違いがある。 + // このスペースは AvatarBuilder.BuildHumanAvatar において必用であり、 + // HumanBodyBones.ToString と区別する必要がある。 + // + // また、下記についてGCが発生するのでキャッシュします。 + // * HumanTrait.BoneName + // * traitName.Replace + // * Enum.Parse + // + private static readonly Dictionary cachedHumanBodyBonesToBoneTraitNameMap = + HumanTrait.BoneName.ToDictionary( + traitName => (HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), traitName.Replace(" ", "")), + traitName => traitName); + + // 逆引き + private static readonly Dictionary cachedBoneTraitNameToHumanBodyBonesMap = + HumanTrait.BoneName.ToDictionary( + traitName => traitName, + traitName => (HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), traitName.Replace(" ", ""))); public static BoneLimit From(HumanBone bone) { return new BoneLimit { - humanBone = (HumanBodyBones) Enum.Parse(typeof(HumanBodyBones), bone.humanName.Replace(" ", ""), true), + humanBone = cachedBoneTraitNameToHumanBodyBonesMap[bone.humanName], boneName = bone.boneName, useDefaultValues = bone.limit.useDefaultValues, min = bone.limit.min, @@ -35,31 +58,12 @@ namespace UniHumanoid }; } - public static String ToHumanBoneName(HumanBodyBones b) - { - // 呼び出し毎にGCが発生するのでキャッシュする - if (cashedHumanTraitBoneName == null) - { - cashedHumanTraitBoneName = HumanTrait.BoneName; - } - - foreach (var x in cashedHumanTraitBoneName) - { - if (x.Replace(" ", "") == b.ToString()) - { - return x; - } - } - - throw new KeyNotFoundException(); - } - public HumanBone ToHumanBone() { return new HumanBone { boneName = boneName, - humanName = ToHumanBoneName(humanBone), + humanName = cachedHumanBodyBonesToBoneTraitNameMap[humanBone], limit = new HumanLimit { useDefaultValues = useDefaultValues, @@ -72,6 +76,7 @@ namespace UniHumanoid } } + [Serializable] public class AvatarDescription : ScriptableObject { @@ -122,6 +127,8 @@ namespace UniHumanoid public Avatar CreateAvatar(Transform root) { + // force unique name + ForceUniqueName.Process(root); return AvatarBuilder.BuildHumanAvatar(root.gameObject, ToHumanDescription(root)); } @@ -265,5 +272,65 @@ namespace UniHumanoid return false; } #endif + + public static Avatar CreateAvatarForCopyHierarchy( + Animator src, + GameObject dst, + IDictionary boneMap, + Action modAvatarDesc = null) + { + if (src == null) + { + throw new ArgumentNullException("src"); + } + + var srcHumanBones = CachedEnum.GetValues() + .Where(x => x != HumanBodyBones.LastBone) + .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) + .Where(x => x.Value != null) + ; + + var map = + srcHumanBones + .Where(x => boneMap.ContainsKey(x.Value)) + .ToDictionary(x => x.Key, x => boneMap[x.Value]) + ; + + var avatarDescription = UniHumanoid.AvatarDescription.Create(); + if (modAvatarDesc != null) + { + modAvatarDesc(avatarDescription); + } + avatarDescription.SetHumanBones(map); + var avatar = avatarDescription.CreateAvatar(dst.transform); + avatar.name = "created"; + return avatar; + } + + public static Avatar RecreateAvatar(Animator src) + { + if (src == null) + { + throw new ArgumentNullException("src"); + } + + var srcHumanBones = CachedEnum.GetValues() + .Where(x => x != HumanBodyBones.LastBone) + .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) + .Where(x => x.Value != null) + ; + + var map = + srcHumanBones + .ToDictionary(x => x.Key, x => x.Value) + ; + + var avatarDescription = UniHumanoid.AvatarDescription.Create(); + avatarDescription.SetHumanBones(map); + + var avatar = avatarDescription.CreateAvatar(src.transform); + avatar.name = "created"; + return avatar; + } } } \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/BoneMapping.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/BoneMapping.cs index f9233e664..a3c9446ea 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/BoneMapping.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/BoneMapping.cs @@ -1,6 +1,6 @@ using UnityEngine; using System.Linq; -using System; +using UniGLTF.Utils; namespace UniHumanoid { @@ -26,7 +26,7 @@ namespace UniHumanoid { if (animator.avatar != null) { - foreach (HumanBodyBones key in Enum.GetValues(typeof(HumanBodyBones))) + foreach (var key in CachedEnum.GetValues()) { if (key == HumanBodyBones.LastBone) { diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/ForceUniqueName.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/ForceUniqueName.cs new file mode 100644 index 000000000..22c204a05 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/ForceUniqueName.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniHumanoid +{ + class ForceUniqueName + { + HashSet m_uniqueNameSet = new HashSet(); + int m_counter = 1; + + public static void Process(Transform root) + { + var uniqueName = new ForceUniqueName(); + var transforms = root.GetComponentsInChildren(); + foreach (var t in transforms) + { + uniqueName.RenameIfDupName(t); + } + } + + public void RenameIfDupName(Transform t) + { + if (!m_uniqueNameSet.Contains(t.name)) + { + m_uniqueNameSet.Add(t.name); + return; + } + + if (t.parent != null && t.childCount == 0) + { + /// AvatarBuilder:BuildHumanAvatar で同名の Transform があるとエラーになる。 + /// + /// AvatarBuilder 'GLTF': Ambiguous Transform '32/root/torso_1/torso_2/torso_3/torso_4/torso_5/torso_6/torso_7/neck_1/neck_2/head/ENDSITE' and '32/root/torso_1/torso_2/torso_3/torso_4/torso_5/torso_6/torso_7/l_shoulder/l_up_arm/l_low_arm/l_hand/ENDSITE' found in hierarchy for human bone 'Head'. Transform name mapped to a human bone must be unique. + /// UnityEngine.AvatarBuilder:BuildHumanAvatar (UnityEngine.GameObject,UnityEngine.HumanDescription) + /// UniHumanoid.AvatarDescription:CreateAvatar (UnityEngine.Transform) + /// + /// 主に BVH の EndSite 由来の GameObject 名が重複することへの対策 + /// ex: parent-ENDSITE + var newName = $"{t.parent.name}-{t.name}"; + if (!m_uniqueNameSet.Contains(newName)) + { + Debug.LogWarning($"force rename !!: {t.name} => {newName}"); + t.name = newName; + m_uniqueNameSet.Add(newName); + return; + } + } + + // 連番 + for (int i = 0; i < 100; ++i) + { + // ex: name.1 + var newName = $"{t.name}{m_counter++}"; + if (!m_uniqueNameSet.Contains(newName)) + { + Debug.LogWarning($"force rename: {t.name} => {newName}", t); + t.name = newName; + m_uniqueNameSet.Add(newName); + return; + } + } + + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/ForceUniqueName.cs.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/ForceUniqueName.cs.meta new file mode 100644 index 000000000..e0cbe042a --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/ForceUniqueName.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51b5d93eece56c3449632c9ce0c4fc02 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/Bvh.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/Bvh.cs index 1f8b9126e..01712b3b5 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/Bvh.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/Bvh.cs @@ -6,178 +6,6 @@ using System.Linq; namespace UniHumanoid { - public class BvhException : Exception - { - public BvhException(string msg) : base(msg) { } - } - - public enum Channel - { - Xposition, - Yposition, - Zposition, - Xrotation, - Yrotation, - Zrotation, - } - public static class ChannelExtensions - { - public static string ToProperty(this Channel ch) - { - switch (ch) - { - case Channel.Xposition: return "localPosition.x"; - case Channel.Yposition: return "localPosition.y"; - case Channel.Zposition: return "localPosition.z"; - case Channel.Xrotation: return "localEulerAnglesBaked.x"; - case Channel.Yrotation: return "localEulerAnglesBaked.y"; - case Channel.Zrotation: return "localEulerAnglesBaked.z"; - } - - throw new BvhException("no property for " + ch); - } - - public static bool IsLocation(this Channel ch) - { - switch (ch) - { - case Channel.Xposition: - case Channel.Yposition: - case Channel.Zposition: return true; - case Channel.Xrotation: - case Channel.Yrotation: - case Channel.Zrotation: return false; - } - - throw new BvhException("no property for " + ch); - } - } - - public struct Single3 - { - public Single x; - public Single y; - public Single z; - - public Single3(Single _x, Single _y, Single _z) - { - x = _x; - y = _y; - z = _z; - } - } - - public class BvhNode - { - public String Name - { - get; - private set; - } - - public Single3 Offset - { - get; - private set; - } - - public Channel[] Channels - { - get; - private set; - } - - public List Children - { - get; - private set; - } - - public BvhNode(string name) - { - Name = name; - Children = new List(); - } - - public virtual void Parse(StringReader r) - { - Offset = ParseOffset(r.ReadLine()); - - Channels = ParseChannel(r.ReadLine()); - } - - static Single3 ParseOffset(string line) - { - var split = line.Trim().Split(); - if (split[0] != "OFFSET") - { - throw new BvhException("OFFSET is not found"); - } - - var offset = split.Skip(1).Where(x => !string.IsNullOrEmpty(x)).Select(x => float.Parse(x, System.Globalization.CultureInfo.InvariantCulture)).ToArray(); - return new Single3(offset[0], offset[1], offset[2]); - } - - static Channel[] ParseChannel(string line) - { - var split = line.Trim().Split(); - if (split[0] != "CHANNELS") - { - throw new BvhException("CHANNELS is not found"); - } - var count = int.Parse(split[1]); - if (count + 2 != split.Length) - { - throw new BvhException("channel count is not match with split count"); - } - return split.Skip(2).Select(x => (Channel)Enum.Parse(typeof(Channel), x)).ToArray(); - } - - public IEnumerable Traverse() - { - yield return this; - - foreach (var child in Children) - { - foreach (var descendant in child.Traverse()) - { - yield return descendant; - } - } - } - } - - public class EndSite : BvhNode - { - public EndSite() : base("") - { - } - - public override void Parse(StringReader r) - { - r.ReadLine(); // offset - } - } - - public class ChannelCurve - { - public float[] Keys - { - get; - private set; - } - - public ChannelCurve(int frameCount) - { - Keys = new float[frameCount]; - } - - public void SetKey(int frame, float value) - { - Keys[frame] = value; - } - } - public class Bvh { public BvhNode Root @@ -192,7 +20,7 @@ namespace UniHumanoid private set; } - public ChannelCurve[] Channels + public BvhChannelCurve[] Channels { get; private set; @@ -211,7 +39,7 @@ namespace UniHumanoid public bool IsLocation; } - public bool TryGetPathWithPropertyFromChannel(ChannelCurve channel, out PathWithProperty pathWithProp) + public bool TryGetPathWithPropertyFromChannel(BvhChannelCurve channel, out PathWithProperty pathWithProp) { var index = Channels.ToList().IndexOf(channel); if (index == -1) @@ -270,7 +98,7 @@ namespace UniHumanoid return null; } - public ChannelCurve GetChannel(BvhNode target, Channel channel) + public BvhChannelCurve GetChannel(BvhNode target, BvhChannel channel) { var index = 0; foreach (var node in Root.Traverse()) @@ -306,7 +134,7 @@ namespace UniHumanoid .Select(x => x.Channels.Length) .Sum(); Channels = Enumerable.Range(0, channelCount) - .Select(x => new ChannelCurve(frames)) + .Select(x => new BvhChannelCurve(frames)) .ToArray() ; } @@ -410,7 +238,7 @@ namespace UniHumanoid { throw new BvhException("End in level 0"); } - node = new EndSite(); + node = new BvhEndSite(); } else { @@ -433,7 +261,7 @@ namespace UniHumanoid break; } - if (!(child is EndSite)) + if (!(child is BvhEndSite)) { node.Children.Add(child); } diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs new file mode 100644 index 000000000..3c28916f6 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs @@ -0,0 +1,45 @@ +namespace UniHumanoid +{ + public enum BvhChannel + { + Xposition, + Yposition, + Zposition, + Xrotation, + Yrotation, + Zrotation, + } + + public static class BvhChannelExtensions + { + public static string ToProperty(this BvhChannel ch) + { + switch (ch) + { + case BvhChannel.Xposition: return "localPosition.x"; + case BvhChannel.Yposition: return "localPosition.y"; + case BvhChannel.Zposition: return "localPosition.z"; + case BvhChannel.Xrotation: return "localEulerAnglesBaked.x"; + case BvhChannel.Yrotation: return "localEulerAnglesBaked.y"; + case BvhChannel.Zrotation: return "localEulerAnglesBaked.z"; + } + + throw new BvhException("no property for " + ch); + } + + public static bool IsLocation(this BvhChannel ch) + { + switch (ch) + { + case BvhChannel.Xposition: + case BvhChannel.Yposition: + case BvhChannel.Zposition: return true; + case BvhChannel.Xrotation: + case BvhChannel.Yrotation: + case BvhChannel.Zrotation: return false; + } + + throw new BvhException("no property for " + ch); + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs.meta new file mode 100644 index 000000000..c977786a4 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 885c621c7dd0faf4e8e3de2e0187d2ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannelCurve.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannelCurve.cs new file mode 100644 index 000000000..dc0dd8814 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannelCurve.cs @@ -0,0 +1,21 @@ +namespace UniHumanoid +{ + public class BvhChannelCurve + { + public float[] Keys + { + get; + private set; + } + + public BvhChannelCurve(int frameCount) + { + Keys = new float[frameCount]; + } + + public void SetKey(int frame, float value) + { + Keys[frame] = value; + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannelCurve.cs.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannelCurve.cs.meta new file mode 100644 index 000000000..c42c4951b --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhChannelCurve.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 588638a01ee0b7c47bd731aeed170cea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs new file mode 100644 index 000000000..63e8ca191 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs @@ -0,0 +1,16 @@ +using System.IO; + +namespace UniHumanoid +{ + public class BvhEndSite : BvhNode + { + public BvhEndSite() : base("") + { + } + + public override void Parse(StringReader r) + { + r.ReadLine(); // offset + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs.meta new file mode 100644 index 000000000..7f31574ba --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc2103bbe9c95224e9458e1fb058140f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhException.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhException.cs new file mode 100644 index 000000000..8e1fa95da --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhException.cs @@ -0,0 +1,9 @@ +using System; + +namespace UniHumanoid +{ + public class BvhException : Exception + { + public BvhException(string msg) : base(msg) { } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhException.cs.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhException.cs.meta new file mode 100644 index 000000000..2e9e07579 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86267a6edfc8fc749948c586e622846f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs new file mode 100644 index 000000000..0421fe09f --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEngine; + +namespace UniHumanoid +{ + public class BvhNode + { + public String Name + { + get; + private set; + } + + public Vector3 Offset + { + get; + private set; + } + + public BvhChannel[] Channels + { + get; + private set; + } + + public List Children + { + get; + private set; + } + + public BvhNode(string name) + { + Name = name; + Children = new List(); + } + + public int GetChannelIndex(BvhChannel channel) + { + for (int i = 0; i < Channels.Length; ++i) + { + if (channel == Channels[i]) + { + return i; + } + } + throw new KeyNotFoundException(); + } + + public virtual void Parse(StringReader r) + { + Offset = ParseOffset(r.ReadLine()); + + Channels = ParseChannel(r.ReadLine()); + } + + private static Vector3 ParseOffset(string line) + { + string[] split = line.Trim().Split(); + if (split[0] != "OFFSET") + { + throw new BvhException("OFFSET is not found"); + } + + var offset = split.Skip(1).Where(x => !string.IsNullOrEmpty(x)).Select(x => float.Parse(x, System.Globalization.CultureInfo.InvariantCulture)).ToArray(); + return new Vector3(offset[0], offset[1], offset[2]); + } + + private static BvhChannel[] ParseChannel(string line) + { + var split = line.Trim().Split(); + if (split[0] != "CHANNELS") + { + throw new BvhException("CHANNELS is not found"); + } + var count = int.Parse(split[1]); + if (count + 2 != split.Length) + { + throw new BvhException("channel count is not match with split count"); + } + return split.Skip(2).Select(x => (BvhChannel)Enum.Parse(typeof(BvhChannel), x)).ToArray(); + } + + public IEnumerable Traverse() + { + yield return this; + + foreach (var child in Children) + { + foreach (var descendant in child.Traverse()) + { + yield return descendant; + } + } + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs.meta new file mode 100644 index 000000000..14b8c7f27 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f4ac3efd1faca94381a344a5be51cc2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/HumanPoseClip.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/HumanPoseClip.cs index 9de446493..ab0949f2d 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/HumanPoseClip.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/HumanPoseClip.cs @@ -5,8 +5,9 @@ namespace UniHumanoid { public class HumanPoseClip : ScriptableObject { - public const string TPoseResourcePath = "T-Pose.pose"; - public const string IPoseResourcePath = "I-Pose.pose"; + public const string TPoseResourcePath = "UniHumanoid/T-Pose.pose"; + + public const string IPoseResourcePath = "UniHumanoid/I-Pose.pose"; public Vector3 bodyPosition; diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Humanoid.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/Humanoid.cs index 3e70358be..068492f5d 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/Humanoid.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Humanoid.cs @@ -1,14 +1,18 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; +using UniGLTF.Utils; using UnityEngine; namespace UniHumanoid { /// /// Bone割り当てを保持する。 - /// ヒエラルキーのルート(おそらくHipsの親)にアタッチする + /// ヒエラルキーのルートにアタッチする。 + /// root は以下の条件を満たすべし。 + /// * root は 原点に配置、回転なし、スケールなし。 + /// * root は Hips の祖先 + /// * root の親は null /// [DisallowMultipleComponent] public class Humanoid : MonoBehaviour @@ -235,7 +239,7 @@ namespace UniHumanoid return null; } - IEnumerable<(Transform, HumanBodyBones)> BoneMap + public IEnumerable<(Transform, HumanBodyBones)> BoneMap { get { @@ -424,7 +428,7 @@ namespace UniHumanoid return false; } - var keys = (UnityEngine.HumanBodyBones[])Enum.GetValues(typeof(UnityEngine.HumanBodyBones)); + var keys = CachedEnum.GetValues(); AssignBones(keys.Select(x => { @@ -437,5 +441,19 @@ namespace UniHumanoid return true; } + + public bool TryGetBoneForTransform(Transform t, out HumanBodyBones bone) + { + foreach (var (v, k) in BoneMap) + { + if (v == t) + { + bone = k; + return true; + } + } + bone = default; + return false; + } } } diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/HumanoidLoader.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/HumanoidLoader.cs index 0254e9943..45f0ec806 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/HumanoidLoader.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/HumanoidLoader.cs @@ -9,6 +9,8 @@ namespace UniHumanoid { public static Avatar LoadHumanoidAvatar(Transform root, IEnumerable<(Transform, HumanBodyBones)> boneMap) { + ForceUniqueName.Process(root); + var description = new HumanDescription { skeleton = root.GetComponentsInChildren() diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/BvhAnimationClip.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/BvhAnimationClip.cs index ea644f5c9..64036ab57 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/BvhAnimationClip.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/BvhAnimationClip.cs @@ -16,9 +16,9 @@ namespace UniHumanoid Node = node; } - public ChannelCurve PositionX; - public ChannelCurve PositionY; - public ChannelCurve PositionZ; + public BvhChannelCurve PositionX; + public BvhChannelCurve PositionY; + public BvhChannelCurve PositionZ; public Vector3 GetPosition(int i) { return new Vector3( @@ -27,9 +27,9 @@ namespace UniHumanoid PositionZ.Keys[i]); } - public ChannelCurve RotationX; - public ChannelCurve RotationY; - public ChannelCurve RotationZ; + public BvhChannelCurve RotationX; + public BvhChannelCurve RotationY; + public BvhChannelCurve RotationZ; public Quaternion GetRotation(int i) { if (EulerToRotation == null) @@ -43,7 +43,7 @@ namespace UniHumanoid ); } - static void AddCurve(Bvh bvh, AnimationClip clip, ChannelCurve ch, float scaling) + static void AddCurve(Bvh bvh, AnimationClip clip, BvhChannelCurve ch, float scaling) { if (ch == null) return; var pathWithProp = default(Bvh.PathWithProperty); @@ -106,12 +106,12 @@ namespace UniHumanoid var curve = bvh.Channels[j]; switch (node.Channels[i]) { - case Channel.Xposition: set.PositionX = curve; break; - case Channel.Yposition: set.PositionY = curve; break; - case Channel.Zposition: set.PositionZ = curve; break; - case Channel.Xrotation: set.RotationX = curve; break; - case Channel.Yrotation: set.RotationY = curve; break; - case Channel.Zrotation: set.RotationZ = curve; break; + case BvhChannel.Xposition: set.PositionX = curve; break; + case BvhChannel.Yposition: set.PositionY = curve; break; + case BvhChannel.Zposition: set.PositionZ = curve; break; + case BvhChannel.Xrotation: set.RotationX = curve; break; + case BvhChannel.Yrotation: set.RotationY = curve; break; + case BvhChannel.Zrotation: set.RotationZ = curve; break; default: throw new Exception(); } } diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/BvhImporterContext.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/BvhImporterContext.cs index 378810f81..f50f4f577 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/BvhImporterContext.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/BvhImporterContext.cs @@ -75,11 +75,15 @@ namespace UniHumanoid // // scaling. reposition // + var yCh = Bvh.Root.GetChannelIndex(BvhChannel.Yposition); + var curve = Bvh.Channels[yCh]; + var hipHeight = curve.Keys[0]; + float scaling = 1.0f; { //var foot = animator.GetBoneTransform(HumanBodyBones.LeftFoot); - var foot = hips.Traverse().Skip(skeleton.GetBoneIndex(HumanBodyBones.LeftFoot)).First(); - var hipHeight = hips.position.y - foot.position.y; + // var foot = hips.Traverse().Skip(skeleton.GetBoneIndex(HumanBodyBones.LeftFoot)).First(); + // var hipHeight = hips.position.y - foot.position.y; // hips height to a meter scaling = 1.0f / hipHeight; foreach (var x in Root.transform.Traverse()) @@ -91,15 +95,6 @@ namespace UniHumanoid hips.position = new Vector3(0, scaledHeight, 0); // foot to ground } - // - // avatar - // - Avatar = description.CreateAvatar(Root.transform); - Avatar.name = "Avatar"; - AvatarDescription = description; - var animator = Root.AddComponent(); - animator.avatar = Avatar; - // // create AnimationClip // @@ -113,15 +108,16 @@ namespace UniHumanoid animation.clip = Animation; animation.Play(); - var humanPoseTransfer = Root.AddComponent(); - humanPoseTransfer.Avatar = Avatar; + // + // avatar + // + Avatar = description.CreateAvatar(Root.transform); + Avatar.name = "Avatar"; + AvatarDescription = description; + var animator = Root.AddComponent(); + animator.avatar = Avatar; - // create SkinnedMesh for bone visualize - var renderer = SkeletonMeshUtility.CreateRenderer(animator); - Material = new Material(Shader.Find("Standard")); - renderer.sharedMaterial = Material; - Mesh = renderer.sharedMesh; - Mesh.name = "box-man"; + Root.AddComponent(); } static Transform BuildHierarchy(Transform parent, BvhNode node, float toMeter) diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/Extensions/BvhExtensions.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/Extensions/BvhExtensions.cs index 2b80293f2..b9d737cd6 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/Extensions/BvhExtensions.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/IO/Extensions/BvhExtensions.cs @@ -9,7 +9,7 @@ namespace UniHumanoid { public static Func GetEulerToRotation(this BvhNode bvh) { - var order = bvh.Channels.Where(x => x == Channel.Xrotation || x == Channel.Yrotation || x == Channel.Zrotation).ToArray(); + var order = bvh.Channels.Where(x => x == BvhChannel.Xrotation || x == BvhChannel.Yrotation || x == BvhChannel.Zrotation).ToArray(); return (x, y, z) => { @@ -22,9 +22,9 @@ namespace UniHumanoid { switch (ch) { - case Channel.Xrotation: r = r * xRot; break; - case Channel.Yrotation: r = r * yRot; break; - case Channel.Zrotation: r = r * zRot; break; + case BvhChannel.Xrotation: r = r * xRot; break; + case BvhChannel.Yrotation: r = r * yRot; break; + case BvhChannel.Zrotation: r = r * zRot; break; default: throw new BvhException("no rotation"); } } @@ -32,12 +32,12 @@ namespace UniHumanoid }; } - public static Vector3 ToVector3(this Single3 s3) + public static Vector3 ToVector3(this Vector3 s3) { return new Vector3(s3.x, s3.y, s3.z); } - public static Vector3 ToXReversedVector3(this Single3 s3) + public static Vector3 ToXReversedVector3(this Vector3 s3) { return new Vector3(-s3.x, s3.y, s3.z); } diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/Resources.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/Resources.meta new file mode 100644 index 000000000..6d2ba34e2 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b4f2ed33f96cfdd4ab1057fccbe1d9e1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/Resources/UniHumanoid.meta similarity index 77% rename from Assets/External/UniGLTF/Samples/UniHumanoid.meta rename to Assets/External/UniGLTF/Runtime/UniHumanoid/Resources/UniHumanoid.meta index dbc08374f..4e4b44155 100644 --- a/Assets/External/UniGLTF/Samples/UniHumanoid.meta +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/Resources/UniHumanoid.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9edc7cfd64210934e817c98db16bdaea +guid: 3c8d7024b7589844a9bbd3d632b5853e folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/External/UniGLTF/Runtime/Resources/T-Pose.pose.asset b/Assets/External/UniGLTF/Runtime/UniHumanoid/Resources/UniHumanoid/T-Pose.pose.asset similarity index 100% rename from Assets/External/UniGLTF/Runtime/Resources/T-Pose.pose.asset rename to Assets/External/UniGLTF/Runtime/UniHumanoid/Resources/UniHumanoid/T-Pose.pose.asset diff --git a/Assets/External/UniGLTF/Runtime/Resources/T-Pose.pose.asset.meta b/Assets/External/UniGLTF/Runtime/UniHumanoid/Resources/UniHumanoid/T-Pose.pose.asset.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/Resources/T-Pose.pose.asset.meta rename to Assets/External/UniGLTF/Runtime/UniHumanoid/Resources/UniHumanoid/T-Pose.pose.asset.meta diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/SkeletonMeshUtility.cs b/Assets/External/UniGLTF/Runtime/UniHumanoid/SkeletonMeshUtility.cs index 053a36dd1..4b38f6b66 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/SkeletonMeshUtility.cs +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/SkeletonMeshUtility.cs @@ -8,75 +8,89 @@ namespace UniHumanoid { public static class SkeletonMeshUtility { + readonly struct TSRBox + { + public readonly Vector3 T; + public readonly Vector3 S; + public readonly Quaternion R; + public readonly Vector3 HeadPosition; + + public TSRBox( + Vector3 t, + Vector3 s, + Quaternion r, + Vector3 head) + { + T = t; + S = s; + R = r; + HeadPosition = head; + } + + public Matrix4x4 ToMatrix() + { + return Matrix4x4.Translate(HeadPosition) + * Matrix4x4.Rotate(R) * Matrix4x4.Scale(S) * Matrix4x4.Translate(T); + } + } + class MeshBuilder { List m_positions = new List(); List m_indices = new List(); List m_boneWeights = new List(); - public void AddBone(Vector3 head, Vector3 tail, int boneIndex, float xWidth, float zWidth) + public void AddBone(Vector3 head, Vector3 tail, int boneIndex, float width, float height, Vector3 xAxis) { - var dir = (tail - head).normalized; - Vector3 xaxis; - Vector3 zaxis; - if (Vector3.Dot(dir, Vector3.forward) >= 1.0f - float.Epsilon) - { - xaxis = Vector3.right; - zaxis = Vector3.down; - } - else - { - xaxis = Vector3.Cross(dir, Vector3.forward).normalized; - zaxis = Vector3.forward; - } - AddBox((head+tail)*0.5f, - xaxis*xWidth, - (tail-head)*0.5f, - zaxis*zWidth, - boneIndex); + var yAxis = (tail - head).normalized; + var zAxis = Vector3.Cross(xAxis, yAxis); + xAxis = Vector3.Cross(yAxis, zAxis); + + AddBox(boneIndex, new TSRBox + ( + new Vector3(0, 0.5f, 0), + new Vector3(width, (tail - head).magnitude, height), + new Matrix4x4( + xAxis, yAxis, zAxis, new Vector4(0, 0, 0, 1) + ).rotation, + head + )); } - void AddBox(Vector3 center, Vector3 xaxis, Vector3 yaxis, Vector3 zaxis, int boneIndex) + // rotation * scale * beforeTranslation + void AddBox(int boneIndex, TSRBox box) { - AddQuad( - center - yaxis - xaxis - zaxis, - center - yaxis + xaxis - zaxis, - center - yaxis + xaxis + zaxis, - center - yaxis - xaxis + zaxis, - boneIndex); - AddQuad( - center + yaxis - xaxis - zaxis, - center + yaxis + xaxis - zaxis, - center + yaxis + xaxis + zaxis, - center + yaxis - xaxis + zaxis, - boneIndex, true); - AddQuad( - center - xaxis - yaxis - zaxis, - center - xaxis + yaxis - zaxis, - center - xaxis + yaxis + zaxis, - center - xaxis - yaxis + zaxis, - boneIndex, true); - AddQuad( - center + xaxis - yaxis - zaxis, - center + xaxis + yaxis - zaxis, - center + xaxis + yaxis + zaxis, - center + xaxis - yaxis + zaxis, - boneIndex); - AddQuad( - center - zaxis - xaxis - yaxis, - center - zaxis + xaxis - yaxis, - center - zaxis + xaxis + yaxis, - center - zaxis - xaxis + yaxis, - boneIndex, true); - AddQuad( - center + zaxis - xaxis - yaxis, - center + zaxis + xaxis - yaxis, - center + zaxis + xaxis + yaxis, - center + zaxis - xaxis + yaxis, - boneIndex); + var m = box.ToMatrix(); + + // v6+---+v7 + // v2/| v3| + // +---+ | + // | +v5-+v4 + // |/ |/ + // +---+ + // v1 v0 + var s = 0.5f; + var cube = new Vector3[] + { + m.MultiplyPoint(new Vector3(+s, -s, -s)), + m.MultiplyPoint(new Vector3(-s, -s, -s)), + m.MultiplyPoint(new Vector3(-s, +s, -s)), + m.MultiplyPoint(new Vector3(+s, +s, -s)), + m.MultiplyPoint(new Vector3(+s, -s, +s)), + m.MultiplyPoint(new Vector3(-s, -s, +s)), + m.MultiplyPoint(new Vector3(-s, +s, +s)), + m.MultiplyPoint(new Vector3(+s, +s, +s)), + }; + + AddQuad(boneIndex, cube[0], cube[1], cube[2], cube[3]); + AddQuad(boneIndex, cube[1], cube[5], cube[6], cube[2]); + AddQuad(boneIndex, cube[5], cube[4], cube[7], cube[6]); + AddQuad(boneIndex, cube[4], cube[0], cube[3], cube[7]); + AddQuad(boneIndex, cube[3], cube[2], cube[6], cube[7]); + AddQuad(boneIndex, cube[4], cube[5], cube[1], cube[0]); } - void AddQuad(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3, int boneIndex, bool reverse=false) + void AddQuad(int boneIndex, Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3) { var i = m_positions.Count; m_positions.Add(v0); @@ -86,25 +100,14 @@ namespace UniHumanoid var bw = new BoneWeight { - boneIndex0=boneIndex, - weight0=1.0f, + boneIndex0 = boneIndex, + weight0 = 1.0f, }; m_boneWeights.Add(bw); m_boneWeights.Add(bw); m_boneWeights.Add(bw); m_boneWeights.Add(bw); - if (reverse) - { - m_indices.Add(i + 3); - m_indices.Add(i + 2); - m_indices.Add(i + 1); - - m_indices.Add(i + 1); - m_indices.Add(i); - m_indices.Add(i + 3); - } - else { m_indices.Add(i); m_indices.Add(i + 1); @@ -133,93 +136,133 @@ namespace UniHumanoid public HumanBodyBones Head; public HumanBodyBones Tail; public Vector3 TailOffset; - public float XWidth; - public float ZWidth; + public float Width; + public float Height; + public Vector3 XAxis; - public BoneHeadTail(HumanBodyBones head, HumanBodyBones tail, float xWidth = 0.05f, float zWidth = 0.05f) + public BoneHeadTail(HumanBodyBones head, HumanBodyBones tail, Vector3 xAxis, float width = 0.05f, float height = 0.05f) { Head = head; Tail = tail; TailOffset = Vector3.zero; - XWidth = xWidth; - ZWidth = zWidth; + XAxis = xAxis; + Width = width; + Height = height; } - public BoneHeadTail(HumanBodyBones head, Vector3 tailOffset, float xWidth = 0.05f, float zWidth = 0.05f) + public BoneHeadTail(HumanBodyBones head, Vector3 tailOffset, Vector3 xAxis, float width = 0.05f, float height = 0.05f) { Head = head; Tail = HumanBodyBones.LastBone; TailOffset = tailOffset; - XWidth = xWidth; - ZWidth = zWidth; + XAxis = xAxis; + Width = width; + Height = height; } } static BoneHeadTail[] Bones = new BoneHeadTail[] { - new BoneHeadTail(HumanBodyBones.Hips, HumanBodyBones.Spine, 0.1f, 0.06f), - new BoneHeadTail(HumanBodyBones.Spine, HumanBodyBones.Chest), - new BoneHeadTail(HumanBodyBones.Chest, HumanBodyBones.Neck, 0.1f, 0.06f), - new BoneHeadTail(HumanBodyBones.Neck, HumanBodyBones.Head, 0.03f, 0.03f), - new BoneHeadTail(HumanBodyBones.Head, new Vector3(0, 0.1f, 0), 0.1f, 0.1f), + new BoneHeadTail(HumanBodyBones.Hips, HumanBodyBones.Spine, Vector3.right, 0.2f, 0.12f), + new BoneHeadTail(HumanBodyBones.Spine, HumanBodyBones.Chest, Vector3.right), + new BoneHeadTail(HumanBodyBones.Chest, HumanBodyBones.Neck, Vector3.right, 0.2f, 0.12f), + new BoneHeadTail(HumanBodyBones.Neck, HumanBodyBones.Head, Vector3.right, 0.06f, 0.06f), + new BoneHeadTail(HumanBodyBones.Head, new Vector3(0, 0.2f, 0), Vector3.right, 0.2f, 0.2f), + // new BoneHeadTail(HumanBodyBones.Head, new Vector3(0, 0, 0.1f), Vector3.right, 0.2f, 0.2f), - new BoneHeadTail(HumanBodyBones.LeftShoulder, HumanBodyBones.LeftUpperArm), - new BoneHeadTail(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm), - new BoneHeadTail(HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand), - new BoneHeadTail(HumanBodyBones.LeftHand, new Vector3(-0.1f, 0, 0)), + new BoneHeadTail(HumanBodyBones.LeftShoulder, HumanBodyBones.LeftUpperArm, Vector3.forward), + new BoneHeadTail(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm, Vector3.forward), + new BoneHeadTail(HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand, Vector3.forward), - new BoneHeadTail(HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg), - new BoneHeadTail(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot), - new BoneHeadTail(HumanBodyBones.LeftFoot, HumanBodyBones.LeftToes), - new BoneHeadTail(HumanBodyBones.LeftToes, new Vector3(0, 0, 0.1f)), + new BoneHeadTail(HumanBodyBones.LeftHand, HumanBodyBones.LeftMiddleProximal, Vector3.forward, 0.05f, 0.02f), + new BoneHeadTail(HumanBodyBones.LeftThumbProximal, HumanBodyBones.LeftThumbIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftThumbDistal, new Vector3(-0.03f, 0, 0), Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftIndexProximal, HumanBodyBones.LeftIndexIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftIndexDistal, new Vector3(-0.03f, 0, 0), Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftMiddleProximal, HumanBodyBones.LeftMiddleIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftMiddleDistal, new Vector3(-0.032f, 0, 0), Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftRingProximal, HumanBodyBones.LeftRingIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftRingDistal, new Vector3(-0.028f, 0, 0), Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftLittleProximal, HumanBodyBones.LeftLittleIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.LeftLittleDistal, new Vector3(-0.025f, 0, 0), Vector3.forward, 0.01f, 0.01f), + + new BoneHeadTail(HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg, Vector3.left), + new BoneHeadTail(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot, Vector3.left), + new BoneHeadTail(HumanBodyBones.LeftFoot, HumanBodyBones.LeftToes, Vector3.left), + new BoneHeadTail(HumanBodyBones.LeftToes, new Vector3(0, 0, 0.03f), Vector3.left), + + new BoneHeadTail(HumanBodyBones.RightShoulder, HumanBodyBones.RightUpperArm, Vector3.back), + new BoneHeadTail(HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm, Vector3.back), + new BoneHeadTail(HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand, Vector3.back), + + new BoneHeadTail(HumanBodyBones.RightHand, new Vector3(0.1f, 0, 0), Vector3.back, 0.05f, 0.02f), + new BoneHeadTail(HumanBodyBones.RightThumbProximal, HumanBodyBones.RightThumbIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightThumbDistal, new Vector3(0.03f, 0, 0), Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightIndexProximal, HumanBodyBones.RightIndexIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightIndexDistal, new Vector3(0.03f, 0, 0), Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightMiddleProximal, HumanBodyBones.RightMiddleIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightMiddleDistal, new Vector3(0.032f, 0, 0), Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightRingProximal, HumanBodyBones.RightRingIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightRingDistal, new Vector3(0.028f, 0, 0), Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightLittleProximal, HumanBodyBones.RightLittleIntermediate, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal, Vector3.forward, 0.01f, 0.01f), + new BoneHeadTail(HumanBodyBones.RightLittleDistal, new Vector3(0.025f, 0, 0), Vector3.forward, 0.01f, 0.01f), + + new BoneHeadTail(HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg, Vector3.left), + new BoneHeadTail(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot, Vector3.left), + new BoneHeadTail(HumanBodyBones.RightFoot, HumanBodyBones.RightToes, Vector3.left), + new BoneHeadTail(HumanBodyBones.RightToes, new Vector3(0, 0, 0.03f), Vector3.left), - new BoneHeadTail(HumanBodyBones.RightShoulder, HumanBodyBones.RightUpperArm), - new BoneHeadTail(HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm), - new BoneHeadTail(HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand), - new BoneHeadTail(HumanBodyBones.RightHand, new Vector3(0.1f, 0, 0)), - new BoneHeadTail(HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg), - new BoneHeadTail(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot), - new BoneHeadTail(HumanBodyBones.RightFoot, HumanBodyBones.RightToes), - new BoneHeadTail(HumanBodyBones.RightToes, new Vector3(0, 0, 0.1f)), }; public static SkinnedMeshRenderer CreateRenderer(Animator animator) { - //var bodyBones = (HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones)); var bones = animator.transform.Traverse().ToList(); var builder = new MeshBuilder(); - foreach(var headTail in Bones) + foreach (var headTail in Bones) { var head = animator.GetBoneTransform(headTail.Head); - if (head!=null) + if (head != null) { Transform tail = null; - if(headTail.Tail!= HumanBodyBones.LastBone) + if (headTail.Tail != HumanBodyBones.LastBone) { tail = animator.GetBoneTransform(headTail.Tail); } if (tail != null) { - builder.AddBone(head.position, tail.position, bones.IndexOf(head), headTail.XWidth, headTail.ZWidth); + builder.AddBone(head.position, tail.position, bones.IndexOf(head), headTail.Width, headTail.Height, headTail.XAxis); } else { - builder.AddBone(head.position, head.position + headTail.TailOffset, bones.IndexOf(head), headTail.XWidth, headTail.ZWidth); + builder.AddBone(head.position, head.position + headTail.TailOffset, bones.IndexOf(head), headTail.Width, headTail.Height, headTail.XAxis); } } else { - Debug.LogWarningFormat("{0} not found", headTail.Head); + if (VRMShaders.Symbols.VRM_DEVELOP) + { + Debug.LogWarningFormat("{0} not found", headTail.Head); + } } } var mesh = builder.CreateMesh(); mesh.name = "box-man"; - mesh.bindposes = bones.Select(x => - x.worldToLocalMatrix * animator.transform.localToWorldMatrix).ToArray(); + mesh.bindposes = bones.Select(x => x.worldToLocalMatrix * animator.transform.localToWorldMatrix).ToArray(); + var renderer = animator.gameObject.AddComponent(); renderer.bones = bones.ToArray(); renderer.rootBone = animator.GetBoneTransform(HumanBodyBones.Hips); @@ -229,4 +272,4 @@ namespace UniHumanoid return renderer; } } -} +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/UniHumanoid/UniHumanoid.asmdef b/Assets/External/UniGLTF/Runtime/UniHumanoid/UniHumanoid.asmdef index b66a78290..603a943f7 100644 --- a/Assets/External/UniGLTF/Runtime/UniHumanoid/UniHumanoid.asmdef +++ b/Assets/External/UniGLTF/Runtime/UniHumanoid/UniHumanoid.asmdef @@ -1,6 +1,10 @@ { "name": "UniHumanoid", - "references": [], + "rootNamespace": "", + "references": [ + "GUID:1cd941934d098654fa21a13f28346412", + "GUID:da3e51d19d51a544fa14d43fee843098" + ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, diff --git a/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonDiff.cs b/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonDiff.cs deleted file mode 100644 index 20969c628..000000000 --- a/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonDiff.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; - -namespace UniJSON -{ - public enum JsonDiffType - { - KeyAdded, - KeyRemoved, - ValueChanged, - } - - public struct JsonDiff - { - public JsonPointer Path; - public JsonDiffType DiffType; - public string Msg; - - public static JsonDiff Create(JsonNode node, JsonDiffType diffType, string msg) - { - return new JsonDiff - { - Path = JsonPointer.Create(node), - DiffType = diffType, - Msg = msg, - }; - } - - public override string ToString() - { - switch (DiffType) - { - case JsonDiffType.KeyAdded: - return string.Format("+ {0}: {1}", Path, Msg); - case JsonDiffType.KeyRemoved: - return string.Format("- {0}: {1}", Path, Msg); - case JsonDiffType.ValueChanged: - return string.Format("= {0}: {1}", Path, Msg); - default: - throw new NotImplementedException(); - } - } - } -} diff --git a/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonPointer.cs b/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonPointer.cs deleted file mode 100644 index 2ab6340f2..000000000 --- a/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonPointer.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Linq; -using System.Text; - - -namespace UniJSON -{ - public struct JsonPointer - { - public ArraySegment Path - { - get; - private set; - } - - public int Count - { - get - { - return Path.Count; - } - } - - public Utf8String this[int index] - { - get - { - return Path.Array[Path.Offset + index]; - } - } - - public JsonPointer Unshift() - { - return new JsonPointer - { - Path = new ArraySegment(Path.Array, Path.Offset + 1, Path.Count - 1) - }; - } - - public static JsonPointer Create(JsonNode node) - { - return new JsonPointer - { - Path = new ArraySegment(node.Path().Skip(1).Select(x => GetKeyFromParent(x)).ToArray()) - }; - } - - public JsonPointer(Utf8String pointer) : this() - { - int pos; - if (!pointer.TrySearchAscii((Byte)'/', 0, out pos)) - { - throw new ArgumentException(); - } - if (pos != 0) - { - throw new ArgumentException(); - } - - var split = pointer.Split((Byte)'/').ToArray(); - Path = new ArraySegment(split, 1, split.Length - 1); - } - - public override string ToString() - { - if (Path.Count == 0) - { - return "/"; - } - - var sb = new StringBuilder(); - var end = Path.Offset + Path.Count; - for (int i = Path.Offset; i < end; ++i) - { - sb.Append('/'); - sb.Append(Path.Array[i]); - } - return sb.ToString(); - } - - static Utf8String GetKeyFromParent(JsonNode json) - { - var parent = json.Parent; - if (parent.IsArray()) - { - var index = parent.IndexOf(json); - return Utf8String.From(index); - } - else if (parent.IsMap()) - { - return parent.KeyOf(json); - } - else - { - throw new NotImplementedException(); - } - } - } -} diff --git a/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNode.cs b/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNode.cs index 9ce9d1892..fffb72146 100644 --- a/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNode.cs +++ b/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNode.cs @@ -197,96 +197,6 @@ namespace UniJSON return string.Join("", ToString(indent, 0).ToArray()); } - public IEnumerable Diff(JsonNode rhs, JsonPointer path = default(JsonPointer)) - { - switch (Value.ValueType) - { - case ValueNodeType.Null: - case ValueNodeType.Boolean: - case ValueNodeType.Number: - case ValueNodeType.Integer: - case ValueNodeType.String: - if (!Equals(rhs)) - { - yield return JsonDiff.Create(this, JsonDiffType.ValueChanged, string.Format("{0} => {1}", Value, rhs.Value)); - } - yield break; - } - - if (Value.ValueType != rhs.Value.ValueType) - { - yield return JsonDiff.Create(this, JsonDiffType.ValueChanged, string.Format("{0} => {1}", Value.ValueType, rhs.Value)); - yield break; - } - - if (Value.ValueType == ValueNodeType.Object) - { - - var l = this.ObjectItems().ToDictionary(x => x.Key, x => x.Value); - var r = rhs.ObjectItems().ToDictionary(x => x.Key, x => x.Value); - - foreach (var kv in l) - { - JsonNode x; - if (r.TryGetValue(kv.Key, out x)) - { - r.Remove(kv.Key); - // Found - foreach (var y in kv.Value.Diff(x)) - { - yield return y; - } - } - else - { - // Removed - yield return JsonDiff.Create(kv.Value, JsonDiffType.KeyRemoved, kv.Value.Value.ToString()); - } - } - - foreach (var kv in r) - { - // Added - yield return JsonDiff.Create(kv.Value, JsonDiffType.KeyAdded, kv.Value.Value.ToString()); - } - } - else if (Value.ValueType == ValueNodeType.Array) - { - var ll = this.ArrayItems().GetEnumerator(); - var rr = rhs.ArrayItems().GetEnumerator(); - while (true) - { - var lll = ll.MoveNext(); - var rrr = rr.MoveNext(); - if (lll && rrr) - { - // found - foreach (var y in ll.Current.Diff(rr.Current)) - { - yield return y; - } - } - else if (lll) - { - yield return JsonDiff.Create(ll.Current, JsonDiffType.KeyRemoved, ll.Current.Value.ToString()); - } - else if (rrr) - { - yield return JsonDiff.Create(rr.Current, JsonDiffType.KeyAdded, rr.Current.Value.ToString()); - } - else - { - // end - break; - } - } - } - else - { - throw new NotImplementedException(); - } - } - /// /// Whole tree nodes /// diff --git a/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs b/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs deleted file mode 100644 index e0f9dce7c..000000000 --- a/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - - -namespace UniJSON -{ - public static class ListTreeNodeJsonPointerExtensions - { - public static void SetValue(this JsonNode self, - Utf8String jsonPointer, ArraySegment bytes) - { - foreach (var node in self.GetNodes(jsonPointer)) - { - node.SetValue(default(JsonValue).New( - bytes, - ValueNodeType.Boolean, - node.Value.ParentIndex)); - } - } - - public static void RemoveValue(this JsonNode self, Utf8String jsonPointer) - { - foreach (var node in self.GetNodes(new JsonPointer(jsonPointer))) - { - if (node.Parent.IsMap()) - { - node.Prev.SetValue(default(JsonValue)); // remove key - } - node.SetValue(default(JsonValue)); // remove - } - } - - public static JsonPointer Pointer(this JsonNode self) - { - return JsonPointer.Create(self); - } - - public static IEnumerable Path(this JsonNode self) - { - if (self.HasParent) - { - foreach (var x in self.Parent.Path()) - { - yield return x; - } - } - yield return self; - } - - public static IEnumerable GetNodes(this JsonNode self, - JsonPointer jsonPointer) - { - if (jsonPointer.Path.Count == 0) - { - yield return self; - yield break; - } - - if (self.IsArray()) - { - // array - if (jsonPointer[0][0] == '*') - { - // wildcard - foreach (var child in self.ArrayItems()) - { - foreach (var childChild in child.GetNodes(jsonPointer.Unshift())) - { - yield return childChild; - } - } - } - else - { - int index = jsonPointer[0].ToInt32(); - var child = self.ArrayItems().Skip(index).First(); - foreach (var childChild in child.GetNodes(jsonPointer.Unshift())) - { - yield return childChild; - } - } - } - else if (self.IsMap()) - { - // object - if (jsonPointer[0][0] == '*') - { - // wildcard - foreach (var kv in self.ObjectItems()) - { - foreach (var childChild in kv.Value.GetNodes(jsonPointer.Unshift())) - { - yield return childChild; - } - } - } - else - { - JsonNode child; - try - { - child = self.ObjectItems().First(x => x.Key.GetUtf8String() == jsonPointer[0]).Value; - } - catch (Exception) - { - // key - self.AddKey(jsonPointer[0]); - // value - self.AddValue(default(ArraySegment), ValueNodeType.Object); - - child = self.ObjectItems().First(x => x.Key.GetUtf8String() == jsonPointer[0]).Value; - } - foreach (var childChild in child.GetNodes(jsonPointer.Unshift())) - { - yield return childChild; - } - } - } - else - { - throw new NotImplementedException(); - } - } - - public static IEnumerable GetNodes(this JsonNode self, - Utf8String jsonPointer) - { - return self.GetNodes(new JsonPointer(jsonPointer)); - } - } -} diff --git a/Assets/External/UniGLTF/Runtime/UniJSON/Utf8String/Utf8String.cs b/Assets/External/UniGLTF/Runtime/UniJSON/Utf8String/Utf8String.cs index ac9596946..020f127f8 100644 --- a/Assets/External/UniGLTF/Runtime/UniJSON/Utf8String/Utf8String.cs +++ b/Assets/External/UniGLTF/Runtime/UniJSON/Utf8String/Utf8String.cs @@ -102,123 +102,6 @@ namespace UniJSON return new Utf8String(new ArraySegment(bytes, 0, pos)); } - // -2147483648 ~ 2147483647 - public static Utf8String From(int src) - { - if (src >= 0) - { - if (src < 10) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src), - }); - } - else if (src < 100) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - else if (src < 1000) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/100), - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - else if (src < 10000) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/1000), - (byte)(0x30 + src/100), - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - else if (src < 100000) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/10000), - (byte)(0x30 + src/1000), - (byte)(0x30 + src/100), - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - else if (src < 1000000) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/100000), - (byte)(0x30 + src/10000), - (byte)(0x30 + src/1000), - (byte)(0x30 + src/100), - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - else if (src < 10000000) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/1000000), - (byte)(0x30 + src/100000), - (byte)(0x30 + src/10000), - (byte)(0x30 + src/1000), - (byte)(0x30 + src/100), - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - else if (src < 100000000) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/10000000), - (byte)(0x30 + src/1000000), - (byte)(0x30 + src/100000), - (byte)(0x30 + src/10000), - (byte)(0x30 + src/1000), - (byte)(0x30 + src/100), - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - else if (src < 1000000000) - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/100000000), - (byte)(0x30 + src/10000000), - (byte)(0x30 + src/1000000), - (byte)(0x30 + src/100000), - (byte)(0x30 + src/10000), - (byte)(0x30 + src/1000), - (byte)(0x30 + src/100), - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - else - { - return new Utf8String(new byte[] { - (byte)(0x30 + src/1000000000), - (byte)(0x30 + src/100000000), - (byte)(0x30 + src/10000000), - (byte)(0x30 + src/1000000), - (byte)(0x30 + src/100000), - (byte)(0x30 + src/10000), - (byte)(0x30 + src/1000), - (byte)(0x30 + src/100), - (byte)(0x30 + src/10), - (byte)(0x30 + src%10), - }); - } - } - else - { - throw new NotImplementedException(); - } - } - public Utf8String Concat(Utf8String rhs) { var bytes = new Byte[ByteLength + rhs.ByteLength]; diff --git a/Assets/External/UniGLTF/Runtime/Utils.meta b/Assets/External/UniGLTF/Runtime/Utils.meta new file mode 100644 index 000000000..db945a3ee --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6b7c2110b314bf4cbe36f2e16bb44a8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/Utils/CachedEnum.meta b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum.meta new file mode 100644 index 000000000..45099b92f --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bca6484928e42dc46a2d05b11bbc2d75 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnum.cs b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnum.cs new file mode 100644 index 000000000..10292f329 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnum.cs @@ -0,0 +1,42 @@ +using System; + +namespace UniGLTF.Utils +{ + /// + /// CachedEnumType に対するインターフェース。 + /// 非 Generic class + /// + public static class CachedEnum + { + public static T Parse(string name, bool ignoreCase = false) where T : struct, Enum + { + if (ignoreCase) + { + return CachedEnumType.IgnoreCaseMap[name]; + } + else + { + return CachedEnumType.Map[name]; + } + } + + public static T ParseOrDefault(string name, bool ignoreCase = false, T defaultValue = default) + where T : struct, Enum + { + try + { + return Parse(name, ignoreCase: ignoreCase); + } + catch (System.Collections.Generic.KeyNotFoundException) + { + return defaultValue; + } + } + + public static T[] GetValues() where T : struct, Enum + { + return CachedEnumType.Values; + } + } +} + diff --git a/Assets/External/UniGLTF/Runtime/UniGLTF/Util/CacheEnum.cs.meta b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnum.cs.meta similarity index 100% rename from Assets/External/UniGLTF/Runtime/UniGLTF/Util/CacheEnum.cs.meta rename to Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnum.cs.meta diff --git a/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnumType.cs b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnumType.cs new file mode 100644 index 000000000..e840e4341 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnumType.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; + + +namespace UniGLTF.Utils +{ + /// + /// enum T に対する static type caching 。 + /// + /// CachedEnumType.Values + /// CachedEnumType.Map + /// CachedEnumType.IgnoreCaseMap + /// + /// がスレッドセーフに(キャッシュされた)同じ値を返す。 + /// + internal static class CachedEnumType where T : struct, Enum + { + public static IReadOnlyDictionary Map { get; } = CreateStringEnumMap(false); + public static IReadOnlyDictionary IgnoreCaseMap { get; } = CreateStringEnumMap(true); + public static T[] Values { get; } = (T[])Enum.GetValues(typeof(T)); + + private static Dictionary CreateStringEnumMap(bool ignoreCase) + { + var dict = ignoreCase + ? new Dictionary(StringComparer.OrdinalIgnoreCase) + : new Dictionary() + ; + + // ここで Values を使うと + // System.TypeInitializationException + // が起きる。 + // static 変数初期化中に別の static 変数を参照すると未初期化がありえるぽい(初期化順?) + foreach (T value in Enum.GetValues(typeof(T))) + { + dict.Add(value.ToString(), value); + } + return dict; + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnumType.cs.meta b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnumType.cs.meta new file mode 100644 index 000000000..3d3336cf6 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/CachedEnum/CachedEnumType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 439fd6a452234eeca5105e5591e8f9aa +timeCreated: 1662528509 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/Utils/EuclideanTransform.cs b/Assets/External/UniGLTF/Runtime/Utils/EuclideanTransform.cs new file mode 100644 index 000000000..5c6992f1b --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/EuclideanTransform.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace UniGLTF.Utils +{ + public readonly struct EuclideanTransform + { + public readonly Quaternion Rotation; + public readonly Vector3 Translation; + + public EuclideanTransform(Quaternion rotation, Vector3 translation) + { + Rotation = rotation; + Translation = translation; + } + public EuclideanTransform(Quaternion rotation) + { + Rotation = rotation; + Translation = Vector3.zero; + } + public EuclideanTransform(Vector3 translation) + { + Rotation = Quaternion.identity; + Translation = translation; + } + public EuclideanTransform(Matrix4x4 matrix) + { + Rotation = matrix.rotation; + Translation = matrix.GetColumn(3); + } + } +} diff --git a/Assets/External/UniGLTF/Runtime/Utils/EuclideanTransform.cs.meta b/Assets/External/UniGLTF/Runtime/Utils/EuclideanTransform.cs.meta new file mode 100644 index 000000000..363d1575a --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/EuclideanTransform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af1b96890351fa24e9a49e7c4a6c2185 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Runtime/Utils/TransformState.cs b/Assets/External/UniGLTF/Runtime/Utils/TransformState.cs new file mode 100644 index 000000000..17b2d54f0 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/TransformState.cs @@ -0,0 +1,42 @@ +using UnityEngine; + +namespace UniGLTF.Utils +{ + public readonly struct TransformState + { + public Vector3 Position { get; } + public Vector3 LocalPosition { get; } + public Quaternion Rotation { get; } + public Quaternion LocalRotation { get; } + public Vector3 LocalScale { get; } + + public TransformState(Vector3 position, Vector3 localPosition, Quaternion rotation, Quaternion localRotation, Vector3 localScale) + { + Position = position; + LocalPosition = localPosition; + Rotation = rotation; + LocalRotation = localRotation; + LocalScale = localScale; + } + + public TransformState(Transform tf) + { + if (tf == null) + { + Position = Vector3.zero; + LocalPosition = Vector3.zero; + Rotation = Quaternion.identity; + LocalRotation = Quaternion.identity; + LocalScale = Vector3.one; + } + else + { + Position = tf.position; + LocalPosition = tf.localPosition; + Rotation = tf.rotation; + LocalRotation = tf.localRotation; + LocalScale = tf.localScale; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/Utils/TransformState.cs.meta b/Assets/External/UniGLTF/Runtime/Utils/TransformState.cs.meta new file mode 100644 index 000000000..29ef11d81 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/TransformState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 172d698f753e4e59bf65a75014016221 +timeCreated: 1657022395 \ No newline at end of file diff --git a/Assets/External/UniGLTF/Runtime/Utils/UniGLTF.Utils.asmdef b/Assets/External/UniGLTF/Runtime/Utils/UniGLTF.Utils.asmdef new file mode 100644 index 000000000..57d5bdce8 --- /dev/null +++ b/Assets/External/UniGLTF/Runtime/Utils/UniGLTF.Utils.asmdef @@ -0,0 +1,14 @@ +{ + "name": "UniGLTF.Utils", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/UniGLTF.Samples.ScreenSpace.asmdef.meta b/Assets/External/UniGLTF/Runtime/Utils/UniGLTF.Utils.asmdef.meta similarity index 76% rename from Assets/External/UniGLTF/Samples/ScreenSpace/UniGLTF.Samples.ScreenSpace.asmdef.meta rename to Assets/External/UniGLTF/Runtime/Utils/UniGLTF.Utils.asmdef.meta index a171280cf..c62d0915a 100644 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/UniGLTF.Samples.ScreenSpace.asmdef.meta +++ b/Assets/External/UniGLTF/Runtime/Utils/UniGLTF.Utils.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b7fdb0325c3f0a9449a1b286964a4e0f +guid: 1cd941934d098654fa21a13f28346412 AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/ScaleOffset.cs b/Assets/External/UniGLTF/Samples/ScreenSpace/ScaleOffset.cs deleted file mode 100644 index a3fc728e5..000000000 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/ScaleOffset.cs +++ /dev/null @@ -1,51 +0,0 @@ -using UnityEngine; - -namespace UniGLTF.Samples -{ - /// - /// ScaleOffset の検証 - /// - public class ScaleOffset : MonoBehaviour - { - [SerializeField] - public Vector2 Scale = Vector2.one; - - [SerializeField] - public Vector2 Offset = Vector2.zero; - - [SerializeField] - Material Unity; - - [SerializeField] - Material Gltf; - - void OnValidate() - { - Execute(); - } - - // Update is called once per frame - void Update() - { - Execute(); - } - - const string PROP_NAME = "_MainTex"; - - void Execute() - { - if (Unity == null || Gltf == null) - { - return; - } - - Unity.SetTextureScale(PROP_NAME, Scale); - Unity.SetTextureOffset(PROP_NAME, Offset); - - var (s, o) = TextureTransform.VerticalFlipScaleOffset(Scale, Offset); - - Gltf.SetTextureScale(PROP_NAME, s); - Gltf.SetTextureOffset(PROP_NAME, o); - } - } -} \ No newline at end of file diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/ScaleOffset.cs.meta b/Assets/External/UniGLTF/Samples/ScreenSpace/ScaleOffset.cs.meta deleted file mode 100644 index a94d3cd10..000000000 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/ScaleOffset.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cc38273c6ab8068408ffe4f2d2cec7bf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/ScreenSpace.unity b/Assets/External/UniGLTF/Samples/ScreenSpace/ScreenSpace.unity deleted file mode 100644 index cb139ac94..000000000 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/ScreenSpace.unity +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e9bb9acf0ac56553678d1b110d721ce8365f03541dd0df64bb69d3aff51eb04f -size 15228 diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/a.png b/Assets/External/UniGLTF/Samples/ScreenSpace/a.png deleted file mode 100644 index a6a1d69b5..000000000 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/a.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:87c14eccbefd696133cbdfe4212032ac5a5971bd4b565d04934ec3465a6f9a68 -size 713 diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/b.png b/Assets/External/UniGLTF/Samples/ScreenSpace/b.png deleted file mode 100644 index e7a0b020f..000000000 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/b.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a7b79e2d3e3176d6b110e5d9a6474b08e6e66b7591609b66c93a351cf4a60050 -size 279 diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/uv_color.shader b/Assets/External/UniGLTF/Samples/ScreenSpace/uv_color.shader deleted file mode 100644 index 3d644862b..000000000 --- a/Assets/External/UniGLTF/Samples/ScreenSpace/uv_color.shader +++ /dev/null @@ -1,58 +0,0 @@ -Shader "Unlit/uv_color" -{ - Properties - { - _MainTex ("Texture", 2D) = "white" {} - } - SubShader - { - Tags { "RenderType"="Opaque" } - LOD 100 - - Pass - { - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - // make fog work - #pragma multi_compile_fog - - #include "UnityCG.cginc" - - struct appdata - { - float4 vertex : POSITION; - float2 uv : TEXCOORD0; - }; - - struct v2f - { - float2 uv : TEXCOORD0; - UNITY_FOG_COORDS(1) - float4 vertex : SV_POSITION; - }; - - sampler2D _MainTex; - float4 _MainTex_ST; - - v2f vert (appdata v) - { - v2f o; - o.vertex = UnityObjectToClipPos(v.vertex); - o.uv = TRANSFORM_TEX(v.uv, _MainTex); - UNITY_TRANSFER_FOG(o,o.vertex); - return o; - } - - fixed4 frag (v2f i) : SV_Target - { - // sample the texture - fixed4 col = tex2D(_MainTex, i.uv); - // apply fog - UNITY_APPLY_FOG(i.fogCoord, col); - return col; - } - ENDCG - } - } -} diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/HumanBuilderTest.cs b/Assets/External/UniGLTF/Samples/UniHumanoid/HumanBuilderTest.cs deleted file mode 100644 index 6c81c802d..000000000 --- a/Assets/External/UniGLTF/Samples/UniHumanoid/HumanBuilderTest.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - - -namespace UniHumanoid -{ - [RequireComponent(typeof(Animator))] - public class HumanBuilderTest : MonoBehaviour - { - [SerializeField] - Material m_material; - - class SkeletonBuilder - { - Dictionary m_skeleton = new Dictionary(); - public IDictionary Skeleton - { - get { return m_skeleton; } - } - - Dictionary m_boneTail = new Dictionary(); - Transform m_root; - - public SkeletonBuilder(Transform root) - { - m_root = root; - } - - void Add(HumanBodyBones key, Transform parent, Vector3 headPosition, Vector3 tailPosition) - { - var bone = new GameObject(key.ToString()).transform; - bone.SetParent(parent, false); - bone.localPosition = headPosition; - m_skeleton[key] = bone; - m_boneTail[key] = tailPosition; - } - - void Add(HumanBodyBones key, HumanBodyBones parentKey, Vector3 tailPosition) - { - Add(key, m_skeleton[parentKey], m_boneTail[parentKey], tailPosition); - } - - #region Spine - public void AddHips(float height, float len) - { - Add(HumanBodyBones.Hips, m_root, new Vector3(0, height, 0), new Vector3(0, len, 0)); - } - - public void AddSpine(float len) - { - Add(HumanBodyBones.Spine, HumanBodyBones.Hips, new Vector3(0, len, 0)); - } - - public void AddChest(float len) - { - Add(HumanBodyBones.Chest, HumanBodyBones.Spine, new Vector3(0, len, 0)); - } - - public void AddNeck(float len) - { - Add(HumanBodyBones.Neck, HumanBodyBones.Chest, new Vector3(0, len, 0)); - } - - public void AddHead(float len) - { - Add(HumanBodyBones.Head, HumanBodyBones.Neck, new Vector3(0, len, 0)); - } - #endregion - - public void AddArm(float shoulder, float upper, float lower, float hand) - { - Add(HumanBodyBones.LeftShoulder, HumanBodyBones.Chest, new Vector3(-shoulder, 0, 0)); - Add(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftShoulder, new Vector3(-upper, 0, 0)); - Add(HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftUpperArm, new Vector3(-lower, 0, 0)); - Add(HumanBodyBones.LeftHand, HumanBodyBones.LeftLowerArm, new Vector3(-hand, 0, 0)); - - Add(HumanBodyBones.RightShoulder, HumanBodyBones.Chest, new Vector3(shoulder, 0, 0)); - Add(HumanBodyBones.RightUpperArm, HumanBodyBones.RightShoulder, new Vector3(upper, 0, 0)); - Add(HumanBodyBones.RightLowerArm, HumanBodyBones.RightUpperArm, new Vector3(lower, 0, 0)); - Add(HumanBodyBones.RightHand, HumanBodyBones.RightLowerArm, new Vector3(hand, 0, 0)); - } - - public void AddLeg(float distance, float upper, float lower, float foot, float toe) - { - Add(HumanBodyBones.LeftUpperLeg, m_skeleton[HumanBodyBones.Hips], new Vector3(-distance, 0, 0), new Vector3(0, -upper, 0)); - Add(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftUpperLeg, new Vector3(0, -lower, 0)); - Add(HumanBodyBones.LeftFoot, HumanBodyBones.LeftLowerLeg, new Vector3(0, -foot, foot)); - Add(HumanBodyBones.LeftToes, HumanBodyBones.LeftFoot, new Vector3(0, 0, toe)); - - Add(HumanBodyBones.RightUpperLeg, m_skeleton[HumanBodyBones.Hips], new Vector3(distance, 0, 0), new Vector3(0, -upper, 0)); - Add(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightUpperLeg, new Vector3(0, -lower, 0)); - Add(HumanBodyBones.RightFoot, HumanBodyBones.RightLowerLeg, new Vector3(0, -foot, foot)); - Add(HumanBodyBones.RightToes, HumanBodyBones.RightFoot, new Vector3(0, 0, toe)); - } - } - - void OnEnable() - { - BuildSkeleton(transform); - } - - private void BuildSkeleton(Transform root) - { - var position = root.position; - root.position = Vector3.zero; - - try - { - // hips -> spine -> chest - var builder = new SkeletonBuilder(root); - builder.AddHips(0.8f, 0.2f); - builder.AddSpine(0.1f); - builder.AddChest(0.2f); - builder.AddNeck(0.1f); - builder.AddHead(0.2f); - builder.AddArm(0.1f, 0.3f, 0.3f, 0.1f); - builder.AddLeg(0.1f, 0.3f, 0.4f, 0.1f, 0.1f); - - var description = AvatarDescription.Create(builder.Skeleton); - var animator = GetComponent(); - animator.avatar = description.CreateAvatar(root); - - // create SkinnedMesh for bone visualize - var renderer = SkeletonMeshUtility.CreateRenderer(animator); - - if (m_material == null) - { - m_material = new Material(Shader.Find("Standard")); - } - renderer.sharedMaterial = m_material; - //root.gameObject.AddComponent(); - - var transfer = GetComponent(); - if (transfer != null) - { - transfer.Avatar = animator.avatar; - transfer.Setup(); - } - } - finally - { - // restore position - root.position = position; - } - } - } -} diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/HumanBuilderTest.cs.meta b/Assets/External/UniGLTF/Samples/UniHumanoid/HumanBuilderTest.cs.meta deleted file mode 100644 index 420a63cd2..000000000 --- a/Assets/External/UniGLTF/Samples/UniHumanoid/HumanBuilderTest.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dfdcf658d2da05649974b59b849de74c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/PoseTransfer.unity b/Assets/External/UniGLTF/Samples/UniHumanoid/PoseTransfer.unity deleted file mode 100644 index c4eeb0afa..000000000 --- a/Assets/External/UniGLTF/Samples/UniHumanoid/PoseTransfer.unity +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:287106825ccbd5bad43a84b53656f7c71692b70c3f4dff4d5b25425e8345f3cc -size 19130 diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.cs b/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.cs deleted file mode 100644 index afc3727c0..000000000 --- a/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.cs +++ /dev/null @@ -1,83 +0,0 @@ -using UnityEngine; -using UnityEngine.Events; -using UnityEngine.UI; -using UniHumanoid; -using System.IO; -using System; -#if UNITY_EDITOR -using UnityEditor; -#endif - - -namespace UniHumanoid -{ - public class RuntimeBvhLoader : MonoBehaviour - { - [SerializeField] - Button m_openButton = default; - - [SerializeField] - HumanPoseTransfer m_dst = default; - - UnityAction m_onClick; - - private void Awake() - { - m_onClick = new UnityEngine.Events.UnityAction(OnClick); - } - - private void OnEnable() - { - m_openButton.onClick.AddListener(m_onClick); - } - - private void OnDisable() - { - m_openButton.onClick.RemoveListener(m_onClick); - } - - static string m_lastDir; - - public void OnClick() - { -#if UNITY_EDITOR - var path = EditorUtility.OpenFilePanel("open bvh", m_lastDir, "bvh"); - if (String.IsNullOrEmpty(path)) - { - return; - } - m_lastDir = Path.GetDirectoryName(path); -#else - string path=null; -#endif - -#pragma warning disable 4014 - Open(path); -#pragma warning restore 4014 - } - - BvhImporterContext m_context; - - void Open(string path) - { - Debug.LogFormat("Open: {0}", path); - if (m_context != null) - { - m_context.Destroy(true); - m_context = null; - } - - m_context = new BvhImporterContext(); - m_context.Parse(path); - m_context.Load(); - - var src = m_context.Root.AddComponent(); - - if (m_dst != null) - { - m_dst.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer; - m_dst.Source = src; - } - } - } -} diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.cs.meta b/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.cs.meta deleted file mode 100644 index 0fae39bc4..000000000 --- a/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7b994e1476323bf4fbe1ae28bea164f2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.unity b/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.unity deleted file mode 100644 index d94bc70df..000000000 --- a/Assets/External/UniGLTF/Samples/UniHumanoid/RuntimeBvhLoader.unity +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:040b7fbc010f8b0d84ea8fa4d46ea50ddc700a6096c145dc189483acac3b7b5a -size 16986 diff --git a/Assets/External/UniGLTF/Tests/UniGLTF.Tests.asmdef b/Assets/External/UniGLTF/Tests/UniGLTF.Tests.asmdef index e1ebdd170..bf3839155 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF.Tests.asmdef +++ b/Assets/External/UniGLTF/Tests/UniGLTF.Tests.asmdef @@ -1,12 +1,14 @@ { "name": "UniGLTF.Tests", + "rootNamespace": "", "references": [ "GUID:8d76e605759c3f64a957d63ef96ada7c", "GUID:5f875fdc81c40184c8333b9d63c6ddd5", "GUID:da3e51d19d51a544fa14d43fee843098", "GUID:7da8a75dcade2144aab699032d7d7987", "GUID:27619889b8ba8c24980f49ee34dbb44a", - "GUID:0acc523941302664db1f4e527237feb3" + "GUID:0acc523941302664db1f4e527237feb3", + "GUID:1cd941934d098654fa21a13f28346412" ], "includePlatforms": [ "Editor" diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_linear.png.meta b/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_linear.png.meta index 8968f3a02..8cff80177 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_linear.png.meta +++ b/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_linear.png.meta @@ -3,7 +3,7 @@ guid: fc1ba24d4a4141d4d9e9ae0a0d3ecd0a TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 @@ -23,6 +23,8 @@ TextureImporter: isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -54,10 +56,14 @@ TextureImporter: textureType: 0 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 applyGammaDecoding: 0 + cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform @@ -95,6 +101,18 @@ TextureImporter: overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] @@ -108,6 +126,7 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] + nameFileIdTable: {} spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_normal_map.png.meta b/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_normal_map.png.meta index 01d1f4a11..aa67d0199 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_normal_map.png.meta +++ b/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_normal_map.png.meta @@ -3,7 +3,7 @@ guid: b5d17df8d14f2324692a7c69f24cf658 TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 1 @@ -23,6 +23,8 @@ TextureImporter: isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -54,10 +56,14 @@ TextureImporter: textureType: 1 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 applyGammaDecoding: 0 + cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform @@ -95,6 +101,18 @@ TextureImporter: overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] @@ -108,6 +126,7 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] + nameFileIdTable: {} spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_srgb.png.meta b/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_srgb.png.meta index ab00cb466..c2e9bfc6f 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_srgb.png.meta +++ b/Assets/External/UniGLTF/Tests/UniGLTF/4x4_gray_import_as_srgb.png.meta @@ -3,7 +3,7 @@ guid: 0f7acf68f1798ae48a5505519abac457 TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 @@ -23,6 +23,8 @@ TextureImporter: isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -54,10 +56,14 @@ TextureImporter: textureType: 0 textureShape: 1 singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + ignorePngGamma: 0 applyGammaDecoding: 0 + cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform @@ -95,6 +101,18 @@ TextureImporter: overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] @@ -108,6 +126,7 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] + nameFileIdTable: {} spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/CacheEnumTest.cs b/Assets/External/UniGLTF/Tests/UniGLTF/CacheEnumTest.cs index a1e3a2ac0..89d6da927 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/CacheEnumTest.cs +++ b/Assets/External/UniGLTF/Tests/UniGLTF/CacheEnumTest.cs @@ -1,4 +1,6 @@ -using NUnit.Framework; +using System.Linq; +using NUnit.Framework; +using UniGLTF.Utils; using UnityEngine; @@ -9,13 +11,9 @@ namespace UniGLTF [Test] public void CacheEnumTestSimplePasses() { - Assert.AreEqual(default(HumanBodyBones), CacheEnum.TryParseOrDefault("xxx")); - -#if UNITY_5_6_OR_NEWER - Assert.AreEqual(HumanBodyBones.UpperChest, CacheEnum.TryParseOrDefault("upperchest", true)); -#else - Assert.AreEqual(default(HumanBodyBones), CacheEnum.TryParseOrDefault("upperchest")); -#endif + Assert.AreEqual(default(HumanBodyBones), CachedEnum.ParseOrDefault("xxx")); + Assert.AreEqual(HumanBodyBones.UpperChest, CachedEnum.ParseOrDefault("upperchest", true)); + Assert.AreEqual(CachedEnum.GetValues().First(x => x == HumanBodyBones.Hips), HumanBodyBones.Hips); } } } diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/GltfJsonUtilTests.cs b/Assets/External/UniGLTF/Tests/UniGLTF/GltfJsonUtilTests.cs index cd806db21..40034b8c8 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/GltfJsonUtilTests.cs +++ b/Assets/External/UniGLTF/Tests/UniGLTF/GltfJsonUtilTests.cs @@ -7,7 +7,7 @@ namespace UniGLTF public class GltfJsonUtilTests { [Test] - public void Update_extensionUsed() + public void Update_extensionsUsed() { var dst = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(@"{ ""asset"": { @@ -44,11 +44,11 @@ namespace UniGLTF var parsed = dst.ParseAsJson(); Assert.AreEqual(new string[] { "KHR_materials_unlit" }, - parsed["extensionUsed"].ArrayItems().Select(x => x.GetString()).ToArray()); + parsed[GltfJsonUtil.EXTENSION_USED_KEY].ArrayItems().Select(x => x.GetString()).ToArray()); } [Test] - public void Replace_extensionUsed() + public void Replace_extensionsUsed() { var dst = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(@"{ ""asset"": { @@ -63,7 +63,7 @@ namespace UniGLTF ] } ], - ""extensionUsed"": [""dummy""], + ""extensionsUsed"": [""dummy""], ""materials"": [ { ""pbrMetallicRoughness"": { @@ -86,11 +86,11 @@ namespace UniGLTF var parsed = dst.ParseAsJson(); Assert.AreEqual(new string[] { "KHR_materials_unlit" }, - parsed["extensionUsed"].ArrayItems().Select(x => x.GetString()).ToArray()); + parsed[GltfJsonUtil.EXTENSION_USED_KEY].ArrayItems().Select(x => x.GetString()).ToArray()); } [Test] - public void Empty_extensionUsed() + public void Empty_extensionsUsed() { var dst = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(@"{ ""asset"": { @@ -105,7 +105,7 @@ namespace UniGLTF ] } ], - ""extensionUsed"": [""dummy""] , + ""extensionsUsed"": [""dummy""] , ""materials"": [ { ""pbrMetallicRoughness"": { @@ -123,11 +123,11 @@ namespace UniGLTF }"); var parsed = dst.ParseAsJson(); - Assert.False(parsed.ContainsKey("extensionUsed")); + Assert.False(parsed.ContainsKey(GltfJsonUtil.EXTENSION_USED_KEY)); } [Test] - public void Empty2_extensionUsed() + public void Empty2_extensionsUsed() { var dst = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(@"{ ""asset"": { @@ -156,12 +156,11 @@ namespace UniGLTF ""name"": ""Red"" } ], - ""extensionUsed"": [""dummy""] + ""extensionsUsed"": [""dummy""] }"); var parsed = dst.ParseAsJson(); - Assert.False(parsed.ContainsKey("extensionUsed")); + Assert.False(parsed.ContainsKey(GltfJsonUtil.EXTENSION_USED_KEY)); } - } } diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs b/Assets/External/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs index 2ab25dfba..5c76b650d 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs +++ b/Assets/External/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs @@ -226,8 +226,8 @@ namespace UniGLTF var path = Path.Combine(root.FullName, "DamagedHelmet/glTF-Binary/DamagedHelmet.glb"); using (var data = new AutoGltfFileParser(path).Parse()) { - var matDesc = new GltfMaterialDescriptorGenerator().Get(data, 0); - Assert.AreEqual("Standard", matDesc.ShaderName); + var matDesc = new BuiltInGltfMaterialDescriptorGenerator().Get(data, 0); + Assert.AreEqual("Standard", matDesc.Shader.name); Assert.AreEqual(5, matDesc.TextureSlots.Count); var (key, value) = matDesc.EnumerateSubAssetKeyValue().First(); Assert.AreEqual(new SubAssetKey(typeof(Texture2D), "texture_0"), key); diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/MaterialTests.cs b/Assets/External/UniGLTF/Tests/UniGLTF/MaterialTests.cs index 845b1f328..4ec781cc7 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/MaterialTests.cs +++ b/Assets/External/UniGLTF/Tests/UniGLTF/MaterialTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using System; +using NUnit.Framework; using UnityEngine; using UniJSON; using System.Linq; @@ -28,7 +29,7 @@ namespace UniGLTF srcMaterial.mainTextureOffset = offset; srcMaterial.mainTextureScale = scale; - var materialExporter = new MaterialExporter(); + var materialExporter = new BuiltInGltfMaterialExporter(); var gltfMaterial = materialExporter.ExportMaterial(srcMaterial, textureExporter, new GltfExportSettings()); gltfMaterial.pbrMetallicRoughness.baseColorTexture.extensions = gltfMaterial.pbrMetallicRoughness.baseColorTexture.extensions.Deserialize(); @@ -257,11 +258,12 @@ namespace UniGLTF var material = new Material(Shader.Find("Standard")); material.SetColor("_EmissionColor", new Color(0, 1, 2, 1)); material.EnableKeyword("_EMISSION"); - var materialExporter = new MaterialExporter(); + var materialExporter = new BuiltInGltfMaterialExporter(); var textureExporter = new TextureExporter(new EditorTextureSerializer()); var gltfMaterial = materialExporter.ExportMaterial(material, textureExporter, new GltfExportSettings()); - Assert.AreEqual(gltfMaterial.emissiveFactor, new float[] { 0, 0.5f, 1 }); + var maxComponent = Mathf.GammaToLinearSpace(2f); + Assert.That(gltfMaterial.emissiveFactor, Is.EqualTo(new float[] { 0f, 1f / maxComponent, 1f }).Within(0.5f / 255f)); } } } diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/MeshDataTests.cs b/Assets/External/UniGLTF/Tests/UniGLTF/MeshDataTests.cs new file mode 100644 index 000000000..fa255e424 --- /dev/null +++ b/Assets/External/UniGLTF/Tests/UniGLTF/MeshDataTests.cs @@ -0,0 +1,210 @@ +using System; +using NUnit.Framework; +using UnityEngine; + +namespace UniGLTF +{ + public class MeshDataTests + { + /// + /// shared + /// 3 2 + /// +-+ + /// |/| + /// +-+ + /// 0 1 + /// + /// divided + /// 2 + /// + + /// /| + /// +-+ + /// 0 1 + /// 4 3 + /// +-+ + /// |/ + /// + + /// 5 + /// + static byte[] CreateTestData(bool shared, bool hasNormal) + { + var data = new ExportingGltfData(); + data.Gltf.asset.version = "2.0"; + var mesh = new glTFMesh(); + data.Gltf.meshes.Add(mesh); + + if (shared) + { + var positions = new Vector3[] + { + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + }; + var normals = new Vector3[] + { + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + }; + + var position = data.ExtendBufferAndGetAccessorIndex(positions); + var normal = data.ExtendBufferAndGetAccessorIndex(normals); + { + var prim = new glTFPrimitives + { + attributes = new glTFAttributes + { + POSITION = position, + }, + indices = data.ExtendBufferAndGetAccessorIndex(new uint[] { 0, 1, 2 }), + }; + mesh.primitives.Add(prim); + if (hasNormal) + { + prim.attributes.NORMAL = normal; + } + } + { + var prim = new glTFPrimitives + { + attributes = new glTFAttributes + { + POSITION = position, + }, + indices = data.ExtendBufferAndGetAccessorIndex(new uint[] { 2, 3, 0 }), + }; + mesh.primitives.Add(prim); + if (hasNormal) + { + prim.attributes.NORMAL = normal; + } + } + } + else + { + { + var positions = new Vector3[] + { + new Vector3(), + new Vector3(), + new Vector3(), + }; + var position = data.ExtendBufferAndGetAccessorIndex(positions); + var prim = new glTFPrimitives + { + attributes = new glTFAttributes + { + POSITION = position, + }, + indices = data.ExtendBufferAndGetAccessorIndex(new uint[] { 0, 1, 2 }), + }; + if (hasNormal) + { + var normals = new Vector3[] + { + new Vector3(), + new Vector3(), + new Vector3(), + }; + var normal = data.ExtendBufferAndGetAccessorIndex(normals); + prim.attributes.NORMAL = normal; + } + mesh.primitives.Add(prim); + } + { + var positions = new Vector3[] + { + new Vector3(), + new Vector3(), + new Vector3(), + }; + var position = data.ExtendBufferAndGetAccessorIndex(positions); + var prim = new glTFPrimitives + { + attributes = new glTFAttributes + { + POSITION = position, + }, + indices = data.ExtendBufferAndGetAccessorIndex(new uint[] { 0, 1, 2 }), + }; + if (hasNormal) + { + var normals = new Vector3[] + { + new Vector3(), + new Vector3(), + new Vector3(), + }; + var normal = data.ExtendBufferAndGetAccessorIndex(normals); + prim.attributes.NORMAL = normal; + } + mesh.primitives.Add(prim); + } + } + return data.ToGlbBytes(); + } + + [Test] + public void SharedHasNormalTest() + { + var glb = CreateTestData(true, true); + using (var parsed = new GlbBinaryParser(glb, "test").Parse()) + { + Assert.True(MeshData.HasSharedVertexBuffer(parsed.GLTF.meshes[0])); + using (var data = new MeshData(6, 6)) + { + data.LoadFromGltf(parsed, 0, new ReverseZ()); + Assert.True(data.HasNormal); + } + } + } + + [Test] + public void SharedNotHasNormalTest() + { + var glb = CreateTestData(true, false); + using (var parsed = new GlbBinaryParser(glb, "test").Parse()) + { + Assert.True(MeshData.HasSharedVertexBuffer(parsed.GLTF.meshes[0])); + using (var data = new MeshData(6, 6)) + { + data.LoadFromGltf(parsed, 0, new ReverseZ()); + Assert.False(data.HasNormal); + } + } + } + + [Test] + public void DividedHasNormalTest() + { + var glb = CreateTestData(false, true); + using (var parsed = new GlbBinaryParser(glb, "test").Parse()) + { + Assert.False(MeshData.HasSharedVertexBuffer(parsed.GLTF.meshes[0])); + using (var data = new MeshData(6, 6)) + { + data.LoadFromGltf(parsed, 0, new ReverseZ()); + Assert.True(data.HasNormal); + } + } + } + + [Test] + public void DividedNotHasNormalTest() + { + var glb = CreateTestData(false, false); + using (var parsed = new GlbBinaryParser(glb, "test").Parse()) + { + Assert.False(MeshData.HasSharedVertexBuffer(parsed.GLTF.meshes[0])); + using (var data = new MeshData(6, 6)) + { + data.LoadFromGltf(parsed, 0, new ReverseZ()); + Assert.False(data.HasNormal); + } + } + } + } +} diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/MeshDataTests.cs.meta b/Assets/External/UniGLTF/Tests/UniGLTF/MeshDataTests.cs.meta new file mode 100644 index 000000000..abeec9770 --- /dev/null +++ b/Assets/External/UniGLTF/Tests/UniGLTF/MeshDataTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e1e46a1dd2717854194c1b10ec096bef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/NativeArrayTests.cs b/Assets/External/UniGLTF/Tests/UniGLTF/NativeArrayTests.cs index f6b0e1933..ad1752d37 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/NativeArrayTests.cs +++ b/Assets/External/UniGLTF/Tests/UniGLTF/NativeArrayTests.cs @@ -6,6 +6,26 @@ namespace UniGLTF { public class NativeArrayTests { +#if UNITY_2020_3_OR_NEWER + [Test] + public void DisposeTest() + { + var array = new NativeArray(64, Allocator.Persistent); + var sub = array.GetSubArray(10, 4); + + // SubArray の Dispose が可能になった ! (Unity-2020.3) + // Assert.Throws(() => { sub.Dispose(); }); + var cast = array.Reinterpret(1); + + // Dispose可能 + cast.Dispose(); + + // ObjectDisposedException に変わった ! (Unity-2020.3) + Assert.Throws(() => { var c = cast[0]; }); + Assert.Throws(() => { var a = array[0]; }); + Assert.Throws(() => { var s = sub[0]; }); + } +#else [Test] public void DisposeTest() { @@ -22,5 +42,6 @@ namespace UniGLTF Assert.Throws(() => { var a = array[0]; }); Assert.Throws(() => { var s = sub[0]; }); } +#endif } } diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/TextureTests.cs b/Assets/External/UniGLTF/Tests/UniGLTF/TextureTests.cs index 6f8e6ba84..a68a0c64d 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/TextureTests.cs +++ b/Assets/External/UniGLTF/Tests/UniGLTF/TextureTests.cs @@ -23,7 +23,7 @@ namespace UniGLTF var material = new Material(Shader.Find("Standard")); material.mainTexture = tex0; - var materialExporter = new MaterialExporter(); + var materialExporter = new BuiltInGltfMaterialExporter(); materialExporter.ExportMaterial(material, textureExporter, new GltfExportSettings()); var exported = textureExporter.Export(); diff --git a/Assets/External/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs b/Assets/External/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs index 3bbc9856f..73c9e7c07 100644 --- a/Assets/External/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs +++ b/Assets/External/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs @@ -159,27 +159,89 @@ namespace UniGLTF } [Test] + [Category("UnityPath")] public void UnityPathTest() { + // 不正なパス + var nullPath = UnityPath.FromUnityPath(null); + Assert.IsTrue(nullPath.IsNull); + Assert.IsFalse(nullPath.IsUnderWritableFolder); + Assert.AreEqual(UnityPath.FromUnityPath(null), nullPath); + + // Application.dataPath のひとつ上 + var dataPath = UnityPath.FromUnityPath(""); + Assert.IsFalse(dataPath.IsNull); + Assert.IsFalse(dataPath.IsUnderWritableFolder); + Assert.AreNotEqual(nullPath, dataPath); + + // Application.dataPath のひとつ上 var root = UnityPath.FromUnityPath("."); Assert.IsFalse(root.IsNull); - Assert.IsFalse(root.IsUnderAssetsFolder); - Assert.AreEqual(UnityPath.FromUnityPath("."), root); + Assert.IsFalse(root.IsUnderWritableFolder); + Assert.AreEqual(dataPath, root); var assets = UnityPath.FromUnityPath("Assets"); Assert.IsFalse(assets.IsNull); - Assert.IsTrue(assets.IsUnderAssetsFolder); + Assert.IsTrue(assets.IsUnderWritableFolder); - var rootChild = root.Child("Assets"); - Assert.AreEqual(assets, rootChild); + var rootChildAssets = root.Child("Assets"); + Assert.AreEqual(assets, rootChildAssets); - var assetsChild = assets.Child("Hoge"); - var hoge = UnityPath.FromUnityPath("Assets/Hoge"); - Assert.AreEqual(assetsChild, hoge); + var assetsChildHoge = assets.Child("Hoge"); + var assetsHoge = UnityPath.FromUnityPath("Assets/Hoge"); + Assert.IsTrue(assetsChildHoge.IsUnderWritableFolder); + Assert.IsTrue(assetsHoge.IsUnderWritableFolder); + Assert.AreEqual(assetsChildHoge, assetsHoge); + + + var packages = UnityPath.FromUnityPath("Packages"); + Assert.IsFalse(packages.IsNull); + Assert.IsFalse(packages.IsUnderWritableFolder); + + var rootChildPackages = root.Child("Packages"); + Assert.AreEqual(packages, rootChildPackages); + + var packagesChildNUnit = packages.Child("com.unity.ext.nunit"); + var packagesNUnit = UnityPath.FromUnityPath("Packages/com.unity.ext.nunit"); + Assert.IsFalse(packages.IsUnderWritableFolder); + Assert.IsFalse(packagesNUnit.IsUnderWritableFolder); + Assert.AreEqual(packagesChildNUnit, packagesNUnit); + + var packagesChildHoge = packages.Child("Hoge"); + var packagesHoge = UnityPath.FromUnityPath("Packages/Hoge"); + Assert.IsFalse(packagesChildHoge.IsUnderWritableFolder); + Assert.IsFalse(packagesHoge.IsUnderWritableFolder); + Assert.AreEqual(packagesChildHoge, packagesHoge); //var children = root.TraverseDir().ToArray(); } + [Test] + [Category("UnityPath")] + [TestCase("", PathType.Unsupported)] + [TestCase("Assets", PathType.Assets)] + [TestCase("Assets/何らかの/パス", PathType.Assets)] + [TestCase("Packages", PathType.Unsupported)] + [TestCase("Packages/ローカルパッケージ", PathType.Packages)] + public void UnityPathPathType(string path, PathType pathType) + { + var assets = UnityPath.FromUnityPath(path); + Assert.AreEqual(pathType, assets.PathType); + } + + [Test] + [Category("UnityPath")] + [TestCase("", false)] + [TestCase("Assets", true)] + [TestCase("Assets/何らかの/パス", true)] + [TestCase("Packages", false)] + // [TestCase("Packages/存在するローカルパッケージ", true)] + public void UnityPathWritableTest(string path, bool expected) + { + var assets = UnityPath.FromUnityPath(path); + Assert.AreEqual(expected, assets.IsUnderWritableFolder); + } + [Test] public void VersionChecker() { diff --git a/Assets/External/UniGLTF/Tests/UniJSON/Json/JsonDiffTests.cs b/Assets/External/UniGLTF/Tests/UniJSON/Json/JsonDiffTests.cs deleted file mode 100644 index 87cac1906..000000000 --- a/Assets/External/UniGLTF/Tests/UniJSON/Json/JsonDiffTests.cs +++ /dev/null @@ -1,71 +0,0 @@ -using NUnit.Framework; -using System.Linq; - - -namespace UniJSON -{ - public class JsonDiffTests - { - [Test] - public void PathTest() - { - var json=@" -{ - ""a"": [ - { - ""aa"": 1 - } - ] -} -"; - var root = JsonParser.Parse(json); - - { - var it = root.Traverse().GetEnumerator(); - it.MoveNext(); Assert.AreEqual("/", it.Current.Pointer().ToString()); - it.MoveNext(); Assert.AreEqual("/a", it.Current.Pointer().ToString()); - it.MoveNext(); Assert.AreEqual("/a/0", it.Current.Pointer().ToString()); - it.MoveNext(); Assert.AreEqual("/a/0/aa", it.Current.Pointer().ToString()); - Assert.False(it.MoveNext()); - } - - { - var it = root.Traverse().GetEnumerator(); - - var f = new JsonFormatter(); - f.Value("JsonPath"); - - root.SetValue(Utf8String.From("/a"), f.GetStoreBytes()); - it.MoveNext(); Assert.AreEqual("/", it.Current.Pointer().ToString()); - it.MoveNext(); Assert.AreEqual("/a", it.Current.Pointer().ToString()); - Assert.False(it.MoveNext()); - } - } - - [Test] - public void DiffTest() - { - var a = @"{ -""a"": 1 -}"; - - var b = @"{ -}"; - - var diff = JsonParser.Parse(a).Diff(JsonParser.Parse(b)).ToArray(); - Assert.AreEqual(1, diff.Length); - } - -#if UNITY_EDITOR - [Test] - public void Vector3() - { - var src = new UnityEngine.Vector3(1, 2, 3); - var json = UnityEngine.JsonUtility.ToJson(src); - Assert.AreEqual("{\"x\":1.0,\"y\":2.0,\"z\":3.0}", json); - var dst = UnityEngine.JsonUtility.FromJson(json); - Assert.AreEqual(src, dst); - } -#endif - } -} diff --git a/Assets/External/UniGLTF/package.json b/Assets/External/UniGLTF/package.json index 23d4d2bce..5fba839a2 100644 --- a/Assets/External/UniGLTF/package.json +++ b/Assets/External/UniGLTF/package.json @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04db32680410d029925c9a8a6407d7a2080e1686fd3a8e3b90e20a7d3932b0a9 -size 289 +oid sha256:12961cc11cb01f203775e4e5399ac4cfa08690acd22356c66f70a4bc8e32cefc +size 492 diff --git a/Assets/External/VRM/Editor/BlendShape/BlendShapeClipEditorHelper.cs b/Assets/External/VRM/Editor/BlendShape/BlendShapeClipEditorHelper.cs index 34baf60a2..c073c82ca 100644 --- a/Assets/External/VRM/Editor/BlendShape/BlendShapeClipEditorHelper.cs +++ b/Assets/External/VRM/Editor/BlendShape/BlendShapeClipEditorHelper.cs @@ -294,7 +294,11 @@ namespace VRM BilinearScale(0, newHeight); +#if UNITY_2021_2_OR_NEWER tex.Reinitialize(newWidth, newHeight); +#else + tex.Resize(newWidth, newHeight); +#endif tex.SetPixels(newColors); tex.Apply(); } diff --git a/Assets/External/VRM/Editor/BlendShape/BlendShapeClipSelector.cs b/Assets/External/VRM/Editor/BlendShape/BlendShapeClipSelector.cs index ae66a99d1..1ba81c499 100644 --- a/Assets/External/VRM/Editor/BlendShape/BlendShapeClipSelector.cs +++ b/Assets/External/VRM/Editor/BlendShape/BlendShapeClipSelector.cs @@ -46,8 +46,6 @@ namespace VRM public BlendShapeClipSelector(BlendShapeAvatar avatar, Action onSelected) { - avatar.RemoveNullClip(); - m_avatar = avatar; m_onSelected = onSelected; diff --git a/Assets/External/VRM/Editor/BlendShape/VRMBlendShapeProxyValidator.cs b/Assets/External/VRM/Editor/BlendShape/VRMBlendShapeProxyValidator.cs index 3c1ae1d90..9e7d2c841 100644 --- a/Assets/External/VRM/Editor/BlendShape/VRMBlendShapeProxyValidator.cs +++ b/Assets/External/VRM/Editor/BlendShape/VRMBlendShapeProxyValidator.cs @@ -24,6 +24,10 @@ namespace VRM var used = new HashSet(); foreach (var c in p.BlendShapeAvatar.Clips) { + if (c == null) + { + continue; + } var key = c.Key; if (used.Contains(key)) { @@ -53,6 +57,12 @@ namespace VRM // 参照が生きているか foreach (var c in p.BlendShapeAvatar.Clips) { + if (c == null) + { + yield return Validation.Warning($"BlendShapeName({c.BlendShapeName})'s BlendShapeClip is not found"); + continue; + } + for (int i = 0; i < c.Values.Length; ++i) { var v = c.Values[i]; diff --git a/Assets/External/VRM/Editor/Format/VRMBlendShapeExportFilter.cs b/Assets/External/VRM/Editor/Format/VRMBlendShapeExportFilter.cs index d04f087f0..d1a754262 100644 --- a/Assets/External/VRM/Editor/Format/VRMBlendShapeExportFilter.cs +++ b/Assets/External/VRM/Editor/Format/VRMBlendShapeExportFilter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UniGLTF; using UnityEngine; @@ -11,6 +12,11 @@ namespace VRM { foreach (var c in clips) { + if (c == null) + { + continue; + } + if (onlyPreset) { if (c.Preset == BlendShapePreset.Unknown) @@ -44,7 +50,7 @@ namespace VRM { if (proxy.BlendShapeAvatar != null) { - Clips.AddRange(proxy.BlendShapeAvatar.Clips); + Clips.AddRange(proxy.BlendShapeAvatar.Clips.Where(x => x != null)); } } } diff --git a/Assets/External/VRM/Editor/Format/VRMEditorExporter.cs b/Assets/External/VRM/Editor/Format/VRMEditorExporter.cs index 4003ba880..f727df52f 100644 --- a/Assets/External/VRM/Editor/Format/VRMEditorExporter.cs +++ b/Assets/External/VRM/Editor/Format/VRMEditorExporter.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using UniGLTF; using UniGLTF.MeshUtility; +using UniGLTF.Utils; using UnityEngine; using VRMShaders; @@ -27,7 +28,8 @@ namespace VRM { foreach (var x in destroy) { - Debug.LogFormat("destroy: {0}", x.name); + // x.name がエラーを引き起こす場合がある + // Debug.LogFormat("destroy: {0}", x.name); GameObject.DestroyImmediate(x); } } @@ -49,6 +51,11 @@ namespace VRM avatar.Clips = new List(); foreach (var clip in src.Clips) { + if (clip == null) + { + continue; + } + if (removeUnknown && clip.Preset == BlendShapePreset.Unknown) { continue; @@ -70,7 +77,8 @@ namespace VRM if (mesh.blendShapeCount == 0) return; // Mesh から BlendShapeClip からの参照がある blendShape の index を集める - var usedBlendshapeIndexArray = copyBlendShapeAvatar.Clips + var copyBlendShapeAvatarClips = copyBlendShapeAvatar.Clips.Where(x => x != null).ToArray(); + var usedBlendshapeIndexArray = copyBlendShapeAvatarClips .SelectMany(clip => clip.Values) .Where(val => target.transform.Find(val.RelativePath) == smr.transform) .Select(val => val.Index) @@ -95,7 +103,7 @@ namespace VRM var indexMapper = usedBlendshapeIndexArray .Select((x, i) => new { x, i }) .ToDictionary(pair => pair.x, pair => pair.i); - foreach (var clip in copyBlendShapeAvatar.Clips) + foreach (var clip in copyBlendShapeAvatarClips) { for (var i = 0; i < clip.Values.Length; ++i) { @@ -161,12 +169,11 @@ namespace VRM { // copy元 var animator = exportRoot.GetComponent(); - var beforeTransforms = exportRoot.GetComponentsInChildren(); + var beforeTransforms = exportRoot.GetComponentsInChildren(true); // copy先 - var afterTransforms = target.GetComponentsInChildren(); + var afterTransforms = target.GetComponentsInChildren(true); // copy先のhumanoidBoneのリストを得る - var bones = (HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones)); - var humanTransforms = bones + var humanTransforms = CachedEnum.GetValues() .Where(x => x != HumanBodyBones.LastBone) .Select(x => animator.GetBoneTransform(x)) .Where(x => x != null) @@ -192,12 +199,10 @@ namespace VRM } } - // 正規化 if (settings.PoseFreeze) { - // BoneNormalizer.Execute は Copy を作って正規化する。UNDO無用 - target = VRMBoneNormalizer.Execute(target, settings.ForceTPose); - destroy.Add(target); + // 正規化 + VRMBoneNormalizer.Execute(target, settings.ForceTPose); } var fp = target.GetComponent(); @@ -223,7 +228,9 @@ namespace VRM // 出力 var sw = System.Diagnostics.Stopwatch.StartNew(); var data = new UniGLTF.ExportingGltfData(); - using (var exporter = new VRMExporter(data, settings.MeshExportSettings)) + var gltfExportSettings = settings.GltfExportSettings; + using (var exporter = new VRMExporter(data, gltfExportSettings, + settings.KeepAnimation ? new EditorAnimationExporter() : null)) { exporter.Prepare(target); exporter.Export(new EditorTextureSerializer()); diff --git a/Assets/External/VRM/Editor/Format/VRMEditorImporterContext.cs b/Assets/External/VRM/Editor/Format/VRMEditorImporterContext.cs index eac3d5d8d..f2bf44317 100644 --- a/Assets/External/VRM/Editor/Format/VRMEditorImporterContext.cs +++ b/Assets/External/VRM/Editor/Format/VRMEditorImporterContext.cs @@ -61,6 +61,12 @@ namespace VRM var meshPath = meshDir.Child(o.name.EscapeFilePath() + ".asset"); return meshPath; } + else if (o is AnimationClip) + { + var meshDir = prefabPath.GetAssetFolder(".Animations"); + var meshPath = meshDir.Child(o.name.EscapeFilePath() + ".anim"); + return meshPath; + } else { return default(UnityPath); @@ -103,7 +109,7 @@ namespace VRM // extract converted textures // var subAssets = m_context.TextureFactory.ConvertedTextures; - var vrmTextures = new VRMMaterialDescriptorGenerator(m_context.VRM); + var vrmTextures = new BuiltInVrmMaterialDescriptorGenerator(m_context.VRM); var dirName = $"{m_prefabPath.FileNameWithoutExtension}.Textures"; TextureExtractor.ExtractTextures(m_context.Data, m_prefabPath.Parent.Child(dirName), m_context.TextureDescriptorGenerator, subAssets, (_x, _y) => { }, onTextureReloaded); } @@ -112,10 +118,11 @@ namespace VRM { if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o))) { -#if VRM_DEVELOP - // 来ない? - Debug.LogWarning($"{o} already exists. skip write"); -#endif + if (Symbols.VRM_DEVELOP) + { + // 来ない? + Debug.LogWarning($"{o} already exists. skip write"); + } return; } @@ -142,7 +149,7 @@ namespace VRM var root = loaded.Root; // Remove RuntimeGltfInstance component before saving as a prefab. - UnityObjectDestoyer.DestroyRuntimeOrEditor(loaded); + UnityObjectDestroyer.DestroyRuntimeOrEditor(loaded); // Create or update Main Asset if (m_prefabPath.IsFileExists) @@ -158,7 +165,7 @@ namespace VRM } // destroy GameObject on scene - UnityObjectDestoyer.DestroyRuntimeOrEditor(root); + UnityObjectDestroyer.DestroyRuntimeOrEditor(root); foreach (var x in m_paths) { diff --git a/Assets/External/VRM/Editor/Format/VRMExportOptions.cs b/Assets/External/VRM/Editor/Format/VRMExportOptions.cs index 66d6b411a..1b23da7bc 100644 --- a/Assets/External/VRM/Editor/Format/VRMExportOptions.cs +++ b/Assets/External/VRM/Editor/Format/VRMExportOptions.cs @@ -47,5 +47,9 @@ namespace VRM [LangMsg(Languages.ja, "頂点カラーの自動削除をしない。")] [LangMsg(Languages.en, "Do not automatically delete vertex colors.")] KEEP_VERTEX_COLOR, + + [LangMsg(Languages.ja, "glTF Animationをエクスポートする。")] + [LangMsg(Languages.en, "export glTF animation.")] + EXPORT_GLTF_ANIMATION, } } diff --git a/Assets/External/VRM/Editor/Format/VRMExportSettings.cs b/Assets/External/VRM/Editor/Format/VRMExportSettings.cs index e4922baea..ff9e5067e 100644 --- a/Assets/External/VRM/Editor/Format/VRMExportSettings.cs +++ b/Assets/External/VRM/Editor/Format/VRMExportSettings.cs @@ -55,12 +55,18 @@ namespace VRM [Tooltip("Keep vertex color attribute")] public bool KeepVertexColor = false; - public GltfExportSettings MeshExportSettings => new GltfExportSettings + /// + /// Export時にAnimationを落とさない。特別な用途で使えるように敢えて残す設定 + /// + [Tooltip("Keep animation")] + public bool KeepAnimation = false; + + public GltfExportSettings GltfExportSettings => new GltfExportSettings { UseSparseAccessorForMorphTarget = UseSparseAccessor, ExportOnlyBlendShapePosition = OnlyBlendshapePosition, DivideVertexBuffer = DivideVertexBuffer, - KeepVertexColor = KeepVertexColor, + ExportVertexColor = KeepVertexColor, }; public GameObject Root { get; set; } diff --git a/Assets/External/VRM/Editor/Format/VRMExportSettingsEditor.cs b/Assets/External/VRM/Editor/Format/VRMExportSettingsEditor.cs index e411fe97c..9c8901ab3 100644 --- a/Assets/External/VRM/Editor/Format/VRMExportSettingsEditor.cs +++ b/Assets/External/VRM/Editor/Format/VRMExportSettingsEditor.cs @@ -54,6 +54,7 @@ namespace VRM m_checkbox_list.Add(new CheckBoxProp(serializedObject.FindProperty(nameof(VRMExportSettings.ReduceBlendshapeClip)), VRMExportOptions.BLENDSHAPE_EXCLUDE_UNKNOWN)); m_checkbox_list.Add(new CheckBoxProp(serializedObject.FindProperty(nameof(VRMExportSettings.DivideVertexBuffer)), VRMExportOptions.DIVIDE_VERTEX_BUFFER)); m_checkbox_list.Add(new CheckBoxProp(serializedObject.FindProperty(nameof(VRMExportSettings.KeepVertexColor)), VRMExportOptions.KEEP_VERTEX_COLOR)); + m_checkbox_list.Add(new CheckBoxProp(serializedObject.FindProperty(nameof(VRMExportSettings.KeepAnimation)), VRMExportOptions.EXPORT_GLTF_ANIMATION)); } diff --git a/Assets/External/VRM/Editor/Format/VRMExporterWizard.cs b/Assets/External/VRM/Editor/Format/VRMExporterWizard.cs index be621b52f..4e89b0e92 100644 --- a/Assets/External/VRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/External/VRM/Editor/Format/VRMExporterWizard.cs @@ -11,10 +11,11 @@ namespace VRM { public class VRMExporterWizard : ExportDialogBase { + public const string MENU_NAME = "Export VRM 0.x..."; public static void OpenExportMenu() { var window = (VRMExporterWizard)GetWindow(typeof(VRMExporterWizard)); - window.titleContent = new GUIContent("VRM Exporter"); + window.titleContent = new GUIContent(MENU_NAME); window.Show(); } @@ -167,7 +168,7 @@ namespace VRM protected override void OnLayout() { - m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings, new VRMBlendShapeExportFilter(State.ExportRoot, m_settings)); + m_meshes.SetRoot(State.ExportRoot, m_settings.GltfExportSettings, new VRMBlendShapeExportFilter(State.ExportRoot, m_settings)); } static bool s_foldT = true; @@ -358,26 +359,26 @@ namespace VRM return; } - m_merger = new BlendShapeMerger(avatar.Clips, proxy.transform); + m_merger = new BlendShapeMerger(avatar.Clips.Where(x => x != null), proxy.transform); GUILayout.Space(20); EditorGUILayout.HelpBox(BlendShapeTabMessages.SCENE_MESSAGE.Msg(), MessageType.Info); - var options = avatar.Clips.Select(x => x.ToString()).ToArray(); + var options = avatar.Clips.Where(x => x != null).Select(x => x.ToString()).ToArray(); m_selected = EditorGUILayout.Popup("select blendshape", m_selected, options); if (GUILayout.Button(BlendShapeTabMessages.APPLY_BLENDSHAPECLIP_BUTTON.Msg())) { - m_merger.SetValues(avatar.Clips.Select((x, i) => new KeyValuePair(x.Key, i == m_selected ? 1 : 0))); + m_merger.SetValues(avatar.Clips.Where(x => x != null).Select((x, i) => new KeyValuePair(x.Key, i == m_selected ? 1 : 0))); m_merger.Apply(); m_settings.PoseFreeze = true; } if (GUILayout.Button(BlendShapeTabMessages.CLEAR_BLENDSHAPE_BUTTON.Msg())) { - m_merger.SetValues(avatar.Clips.Select(x => new KeyValuePair(x.Key, 0))); + m_merger.SetValues(avatar.Clips.Where(x => x != null).Select(x => new KeyValuePair(x.Key, 0))); m_merger.Apply(); } } diff --git a/Assets/External/VRM/Editor/Format/VRMHumanoidNormalizerMenu.cs b/Assets/External/VRM/Editor/Format/VRMHumanoidNormalizerMenu.cs index 9ae3e725a..777de6e79 100644 --- a/Assets/External/VRM/Editor/Format/VRMHumanoidNormalizerMenu.cs +++ b/Assets/External/VRM/Editor/Format/VRMHumanoidNormalizerMenu.cs @@ -8,6 +8,7 @@ namespace VRM { public static class VRMHumanoidNormalizerMenu { + public const string MENU_NAME = "VRM 0.x Freeze T-Pose"; public static bool NormalizeValidation() { var root = Selection.activeObject as GameObject; @@ -45,8 +46,7 @@ namespace VRM { var go = Selection.activeObject as GameObject; - // BoneNormalizer.Execute はコピーを正規化する。UNDO無用 - Selection.activeGameObject = VRMBoneNormalizer.Execute(go, true); + VRMBoneNormalizer.Execute(go, true); } } } diff --git a/Assets/External/VRM/Editor/Format/VRMImporterMenu.cs b/Assets/External/VRM/Editor/Format/VRMImporterMenu.cs index 12071d70b..c99d1ff91 100644 --- a/Assets/External/VRM/Editor/Format/VRMImporterMenu.cs +++ b/Assets/External/VRM/Editor/Format/VRMImporterMenu.cs @@ -7,9 +7,10 @@ namespace VRM { public static class VRMImporterMenu { + public const string MENU_NAME = "Import VRM 0.x..."; public static void OpenImportMenu() { - var path = EditorUtility.OpenFilePanel("open vrm", "", "vrm"); + var path = EditorUtility.OpenFilePanel(MENU_NAME + ": open vrm", "", "vrm"); if (string.IsNullOrEmpty(path)) { return; diff --git a/Assets/External/VRM/Editor/Format/VRMMaterialValidator.cs b/Assets/External/VRM/Editor/Format/VRMMaterialValidator.cs index 941e59038..5d0cd30cf 100644 --- a/Assets/External/VRM/Editor/Format/VRMMaterialValidator.cs +++ b/Assets/External/VRM/Editor/Format/VRMMaterialValidator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace VRM @@ -10,10 +11,9 @@ namespace VRM { public override string GetGltfMaterialTypeFromUnityShaderName(string shaderName) { - var name = VRMMaterialExporter.VrmMaterialName(shaderName); - if (!string.IsNullOrEmpty(name)) + if (BuiltInVrmMaterialExporter.SupportedShaderNames.Contains(shaderName)) { - return name; + return "VRM0X"; } return base.GetGltfMaterialTypeFromUnityShaderName(shaderName); } @@ -30,7 +30,7 @@ namespace VRM // // extensions.VRM.materialProperties に記録する // - var prop = UniGLTF.ShaderPropExporter.PreShaderPropExporter.GetPropsForSupportedShader(m.shader.name); + var prop = UniGLTF.ShaderPropExporter.PreShaderPropExporter.GetPropsForMToon(); foreach (var kv in prop.Properties) { if (kv.ShaderPropertyType == UniGLTF.ShaderPropExporter.ShaderPropertyType.TexEnv) diff --git a/Assets/External/VRM/Editor/Format/VRMSampleCopy.cs b/Assets/External/VRM/Editor/Format/VRMSampleCopy.cs index 3253a7743..9724cbce1 100644 --- a/Assets/External/VRM/Editor/Format/VRMSampleCopy.cs +++ b/Assets/External/VRM/Editor/Format/VRMSampleCopy.cs @@ -1,11 +1,30 @@ using System; using System.IO; +using System.Linq; using UnityEngine; namespace VRM { public static class VRMSampleCopy { + struct CopyInfo + { + public string Src; + public string Dst; + + public CopyInfo(string src, string dst) + { + Src = src; + Dst = dst; + } + } + + static CopyInfo[] CopyList = new CopyInfo[]{ + new CopyInfo(Path.Combine(Application.dataPath, "VRM_Samples"), Path.Combine(Application.dataPath, "VRM/Samples~")), + new CopyInfo(Path.Combine(Application.dataPath, "VRM10_Samples"), Path.Combine(Application.dataPath, "VRM10/Samples~")), + new CopyInfo(Path.Combine(Application.dataPath, "UniGLTF_Samples"), Path.Combine(Application.dataPath, "UniGLTF/Samples~")), + }; + /// /// Assets/VRM_Samples /// を @@ -17,12 +36,17 @@ namespace VRM /// Assets/VRM10/Samples~ /// にコピーする /// - /// 南無 + /// Assets/UniGLTF_Samples + /// を + /// Assets/UniGLTF/Samples~ + /// にコピーする /// public static void Execute() { - Copy(Path.Combine(Application.dataPath, "VRM_Samples"), Path.Combine(Application.dataPath, "VRM/Samples~")); - Copy(Path.Combine(Application.dataPath, "VRM10_Samples"), Path.Combine(Application.dataPath, "VRM10/Samples~")); + foreach (var info in CopyList) + { + Copy(info.Src, info.Dst); + } } static void Copy(string srcDir, string dstDir) @@ -57,5 +81,61 @@ namespace VRM throw new FileNotFoundException(src); } } + + public static bool Validate() + { + return CopyList.All(x => _Validate(x.Src, x.Dst)); + } + + static bool _Validate(string src, string dst) + { + if (Directory.Exists(src)) + { + if (!Directory.Exists(dst)) + { + Debug.LogError($"{dst} not exists"); + return false; + + } + var list = Directory.EnumerateFileSystemEntries(dst).Select(x => x.Substring(dst.Length + 1)).ToList(); + foreach (var child in Directory.EnumerateFileSystemEntries(src)) + { + if (!_Validate(child, Path.Combine(dst, Path.GetFileName(child)).Replace("\\", "/"))) + { + return false; + } + var rel = child.Substring(src.Length + 1); + list.Remove(rel); + } + if (list.Count > 0) + { + var remain = string.Join(",", list); + Debug.LogError($"only dst: {remain}"); + return false; + } + return true; + } + else if (File.Exists(src)) + { + // same file + if (!File.Exists(dst)) + { + Debug.LogError($"{dst} not exists"); + return false; + } + if (!File.ReadAllBytes(src).SequenceEqual(File.ReadAllBytes(dst))) + { + Debug.LogError($"{src} != {dst}"); + return false; + } + return true; + } + else + { + // throw new FileNotFoundException(src); + Debug.LogError($"dir nor file"); + return false; + } + } } } diff --git a/Assets/External/VRM/Editor/Format/VRMVersionMenu.cs b/Assets/External/VRM/Editor/Format/VRMVersionMenu.cs index cc2efb9d1..95aea3333 100644 --- a/Assets/External/VRM/Editor/Format/VRMVersionMenu.cs +++ b/Assets/External/VRM/Editor/Format/VRMVersionMenu.cs @@ -40,11 +40,11 @@ namespace UniGLTF /// /// VRM /// - const string VrmVersionPath = "Assets/VRM/Runtime/Format/VRMVersion.cs"; + const string VrmVersionPath = "Assets/UniGLTF/Runtime/UniGLTF/PackageVersion.cs"; const string VrmVersionTemplate = @" -namespace VRM +namespace UniGLTF {{ - public static partial class VRMVersion + public static partial class PackageVersion {{ public const int MAJOR = {0}; public const int MINOR = {1}; @@ -74,13 +74,16 @@ namespace VRM ""version"": ""{1}"", ""displayName"": ""VRM Shaders"", ""description"": ""VRM Shaders"", - ""unity"": ""2019.4"", + ""unity"": ""2021.3"", ""keywords"": [ ""vrm"", ""shader"" ], ""author"": {{ ""name"": ""VRM Consortium"" + }}, + ""dependencies"": {{ + ""com.unity.modules.imageconversion"": ""1.0.0"" }} }} "), @@ -90,7 +93,7 @@ namespace VRM ""version"": ""{1}"", ""displayName"": ""VRM"", ""description"": ""VRM importer"", - ""unity"": ""2019.4"", + ""unity"": ""2021.3"", ""keywords"": [ ""vrm"", ""importer"", @@ -102,7 +105,8 @@ namespace VRM }}, ""dependencies"": {{ ""com.vrmc.vrmshaders"": ""{1}"", - ""com.vrmc.gltf"": ""{0}"" + ""com.vrmc.gltf"": ""{0}"", + ""com.unity.ugui"": ""1.0.0"" }}, ""samples"": [ {{ @@ -133,9 +137,9 @@ namespace VRM @"{{ ""name"": ""com.vrmc.vrm"", ""version"": ""{1}"", - ""displayName"": ""VRM-1.0β"", - ""description"": ""VRM-1.0β importer"", - ""unity"": ""2019.4"", + ""displayName"": ""VRM-1.0"", + ""description"": ""VRM-1.0 importer"", + ""unity"": ""2021.3"", ""keywords"": [ ""vrm"", ""importer"", @@ -172,7 +176,7 @@ namespace VRM ""version"": ""{0}"", ""displayName"": ""UniGLTF"", ""description"": ""GLTF importer and exporter"", - ""unity"": ""2019.4"", + ""unity"": ""2021.3"", ""keywords"": [ ""gltf"" ], @@ -180,8 +184,16 @@ namespace VRM ""name"": ""VRM Consortium"" }}, ""dependencies"": {{ - ""com.vrmc.vrmshaders"": ""{1}"" - }} + ""com.vrmc.vrmshaders"": ""{1}"", + ""com.unity.modules.animation"": ""1.0.0"" + }}, + ""samples"": [ + {{ + ""displayName"": ""GltfViewer"", + ""description"": ""UniGLTF runtime loader sample"", + ""path"": ""Samples~/GltfViewer"" + }} + ] }}"); [SerializeField] @@ -239,7 +251,7 @@ namespace VRM void OnGUI() { GUILayout.Label("VRM"); - GUILayout.Label($"Current version: {VRMVersion.VERSION}"); + GUILayout.Label($"Current version: {PackageVersion.VERSION}"); m_vrmVersion = EditorGUILayout.TextField("Major.Minor.Patch", m_vrmVersion); GUILayout.Space(30); @@ -312,7 +324,7 @@ namespace VRM public static void ShowVersionDialog() { var window = ScriptableObject.CreateInstance(); - window.m_vrmVersion = VRMVersion.VERSION; + window.m_vrmVersion = PackageVersion.VERSION; // window.m_uniGltfVersion = UniGLTFVersion.VERSION; window.ShowUtility(); } diff --git a/Assets/External/VRM/Editor/Format/vrmAssetPostprocessor.cs b/Assets/External/VRM/Editor/Format/vrmAssetPostprocessor.cs index fa328e9c9..4aa6197d6 100644 --- a/Assets/External/VRM/Editor/Format/vrmAssetPostprocessor.cs +++ b/Assets/External/VRM/Editor/Format/vrmAssetPostprocessor.cs @@ -17,7 +17,13 @@ namespace VRM { foreach (string path in importedAssets) { - if (UnityPath.FromUnityPath(path).IsStreamingAsset) + var unityPath = UnityPath.FromUnityPath(path); + + if (!unityPath.IsFileExists) { + continue; + } + + if (unityPath.IsStreamingAsset) { Debug.LogFormat("Skip StreamingAssets: {0}", path); continue; @@ -28,7 +34,7 @@ namespace VRM { try { - ImportVrm(UnityPath.FromUnityPath(path)); + ImportVrm(unityPath); } catch (NotVrm0Exception) { @@ -41,7 +47,7 @@ namespace VRM static void ImportVrm(UnityPath vrmPath) { - if (!vrmPath.IsUnderAssetsFolder) + if (!vrmPath.IsUnderWritableFolder) { throw new Exception(); } @@ -53,9 +59,9 @@ namespace VRM public static void ImportVrmAndCreatePrefab(string vrmPath, UnityPath prefabPath) { - if (!prefabPath.IsUnderAssetsFolder) + if (!prefabPath.IsUnderWritableFolder) { - Debug.LogWarningFormat("out of asset path: {0}", prefabPath); + Debug.LogWarningFormat("out of Asset or writable Packages folder: {0}", prefabPath); return; } @@ -75,7 +81,7 @@ namespace VRM // 確実に Dispose するために敢えて再パースしている using (var data = new GlbFileParser(vrmPath).Parse()) - using (var context = new VRMImporterContext(new VRMData(data), externalObjectMap: map)) + using (var context = new VRMImporterContext(new VRMData(data), externalObjectMap: map, loadAnimation: true)) { var editor = new VRMEditorImporterContext(context, prefabPath); foreach (var textureInfo in context.TextureDescriptorGenerator.Get().GetEnumerable()) diff --git a/Assets/External/VRM/Editor/Meta/VRMMetaObjectEditor.cs b/Assets/External/VRM/Editor/Meta/VRMMetaObjectEditor.cs index 92c82a082..19c4d1ac0 100644 --- a/Assets/External/VRM/Editor/Meta/VRMMetaObjectEditor.cs +++ b/Assets/External/VRM/Editor/Meta/VRMMetaObjectEditor.cs @@ -176,7 +176,7 @@ namespace VRM { serializedObject.Update(); - if (VRMVersion.IsNewer(m_exporterVersion.stringValue)) + if (PackageVersion.IsNewer(m_exporterVersion.stringValue)) { // モデルのバージョンが、ライブラリのバージョンより新しい EditorGUILayout.HelpBox("Check UniVRM new version.", MessageType.Warning); diff --git a/Assets/External/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs b/Assets/External/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs deleted file mode 100644 index af74ab1bd..000000000 --- a/Assets/External/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UniGLTF; -using UniGLTF.MeshUtility; -using UnityEditor; -using UnityEngine; - -namespace VRM -{ - /// - /// Meshを統合し、統合後のMeshのBlendShapeの変化をVRMのBlendShapeClipに反映する - /// - public static class VRMMeshIntegratorUtility - { - public static List FollowBlendshapeRendererChange(List results, GameObject root, string assetFolder) - { - var clips = new List(); - var proxy = root.GetComponent(); - if (proxy == null || proxy.BlendShapeAvatar == null) - { - return clips; - } - var result = results.FirstOrDefault(x => x.IntegratedRenderer.sharedMesh.blendShapeCount > 0); - if (result == null) - { - return clips; - } - - var rendererDict = new Dictionary(); - foreach (var x in result.SourceSkinnedMeshRenderers) - { - rendererDict.Add(x.transform.RelativePathFrom(root.transform), x); - } - var dstPath = result.IntegratedRenderer.transform.RelativePathFrom(root.transform); - - // copy modify and write - var clipAssetPathList = new List(); - var sb = new StringBuilder(); - foreach (var src in proxy.BlendShapeAvatar.Clips) - { - if (src == null) continue; - - // copy - var copy = ScriptableObject.CreateInstance(); - copy.CopyFrom(src); - copy.Prefab = null; - - // modify - for (var i = 0; i < copy.Values.Length; ++i) - { - var val = copy.Values[i]; - if (rendererDict.ContainsKey(val.RelativePath)) - { - var srcRenderer = rendererDict[val.RelativePath]; - var name = srcRenderer.sharedMesh.GetBlendShapeName(val.Index); - var newIndex = result.IntegratedRenderer.sharedMesh.GetBlendShapeIndex(name); - if (newIndex == -1) - { - throw new KeyNotFoundException($"blendshape:{name} not found"); - } - - val.RelativePath = dstPath; - val.Index = newIndex; - } - copy.Values[i] = val; - } - - // write - var assetPath = $"{assetFolder}/{copy.name}.asset"; - sb.AppendLine($"write: {assetPath}"); - AssetDatabase.CreateAsset(copy, assetPath); - - clipAssetPathList.Add(assetPath); - clips.Add(copy); - } - Debug.Log(sb.ToString()); - - { - // create blendshape avatar & replace - var copy = ScriptableObject.CreateInstance(); - copy.Clips.AddRange(clips); - var assetPath = $"{assetFolder}/blendshape.asset"; - AssetDatabase.CreateAsset(copy, assetPath); - - // assign - proxy.BlendShapeAvatar = copy; - } - - return clips; - } - } -} \ No newline at end of file diff --git a/Assets/External/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta b/Assets/External/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta deleted file mode 100644 index 84182f709..000000000 --- a/Assets/External/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fb47e24fc1463584fa0b6b685d75f25e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs b/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs new file mode 100644 index 000000000..99a7162bc --- /dev/null +++ b/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UniGLTF.MeshUtility; +using UnityEditor; +using UnityEngine; + + +namespace VRM +{ + /// + /// Meshを統合し、統合後のMeshのBlendShapeの変化をVRMのBlendShapeClipに反映する + /// + public class VrmBlendShapeUpdater + { + // BlendShapeBinding.RelativePath からの逆引き + Dictionary> _rendererPathMap = new(); + GameObject _root; + + VrmBlendShapeUpdater(GameObject root, List results) + { + _root = root; + foreach (var result in results) + { + foreach (var x in result.SourceSkinnedMeshRenderers) + { + var srcPath = x.transform.RelativePathFrom(root.transform); + if (_rendererPathMap.TryGetValue(srcPath, out var value)) + { + value.Add(result); + } + else + { + value = new List(); + value.Add(result); + _rendererPathMap.Add(srcPath, value); + } + } + } + } + + // 分割されて増える => 増えない BlendShape のある方にいく + // 統合されて減る => 名前が同じものが統合される + private IEnumerable ReplaceBlendShapeBinding(IEnumerable values) + { + var used = new HashSet(); + foreach (var val in values) + { + if (_rendererPathMap.TryGetValue(val.RelativePath, out var results)) + { + foreach (var result in results) + { + if (result.Integrated == null) + { + continue; + } + var name = result.Integrated.Mesh.GetBlendShapeName(val.Index); + var newIndex = result.Integrated.Mesh.GetBlendShapeIndex(name); + if (newIndex == -1) + { + throw new KeyNotFoundException($"blendshape:{name} not found"); + } + + var dstPath = result.Integrated.IntegratedRenderer.transform.RelativePathFrom(_root.transform); + var binding = new BlendShapeBinding + { + RelativePath = dstPath, + Index = newIndex, + Weight = val.Weight, + }; + if (used.Contains(binding)) + { + Debug.LogWarning($"duplicated: {binding}"); + } + else + { +#if VRM_DEVELOP + Debug.Log($"{val} >> {binding}"); +#endif + used.Add(binding); + yield return binding; + } + } + } + else + { + // skip + Debug.LogWarning($"SkinnedMeshRenderer not found: {val.RelativePath}"); + } + } + } + + public static List FollowBlendshapeRendererChange(string assetFolder, + GameObject root, + List results) + { + var clips = new List(); + var proxy = root.GetComponent(); + if (proxy == null || proxy.BlendShapeAvatar == null) + { + return clips; + } + + var util = new VrmBlendShapeUpdater(root, results); + + // create modified BlendShapeClip + var clipAssetPathList = new List(); + foreach (var src in proxy.BlendShapeAvatar.Clips.Where(x => x != null)) + { + var copy = util.RecreateBlendShapeClip(src, assetFolder); + var assetPath = $"{assetFolder}/{copy.name}.asset"; + AssetDatabase.CreateAsset(copy, assetPath); + clipAssetPathList.Add(assetPath); + clips.Add(copy); + } + + // create BlendShapeAvatar + proxy.BlendShapeAvatar = RecreateBlendShapeAvatar(clips, assetFolder); + + return clips; + } + + BlendShapeClip RecreateBlendShapeClip(BlendShapeClip src, string assetFolder) + { + if (src == null) + { + throw new ArgumentNullException(); + } + + // copy + var copy = ScriptableObject.CreateInstance(); + copy.CopyFrom(src); + copy.Prefab = null; + copy.Values = ReplaceBlendShapeBinding(copy.Values).ToArray(); + return copy; + } + + static BlendShapeAvatar RecreateBlendShapeAvatar(IReadOnlyCollection clips, string assetFolder) + { + var copy = ScriptableObject.CreateInstance(); + copy.Clips.AddRange(clips); + var assetPath = $"{assetFolder}/blendshape.asset"; + AssetDatabase.CreateAsset(copy, assetPath); + return copy; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs.meta b/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs.meta new file mode 100644 index 000000000..697660578 --- /dev/null +++ b/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 488693244cf1ec548a9eb4d81164706f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index 2f81c5571..d6fe6949a 100644 --- a/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/External/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -1,362 +1,135 @@ #pragma warning disable 0414, 0649 using UnityEditor; using UnityEngine; -using System.Linq; -using System; -using System.Collections.Generic; -using UniGLTF.MeshUtility; -using System.IO; using UniGLTF.M17N; +using UniGLTF; +using System.Collections.Generic; + namespace VRM { - public class VrmMeshIntegratorWizard : ScriptableWizard + public class VrmMeshIntegratorWizard : UniGLTF.MeshUtility.MeshUtilityDialog { - const string ASSET_SUFFIX = ".mesh.asset"; - - enum HelpMessage + public new const string MENU_NAME = "VRM 0.x MeshUtility"; + public new static void OpenWindow() { - Ready, - SetTarget, - InvalidTarget, + var window = + (VrmMeshIntegratorWizard)EditorWindow.GetWindow(typeof(VrmMeshIntegratorWizard)); + window.titleContent = new GUIContent(MENU_NAME); + window.Show(); } - - enum ValidationError + protected override void Validate() { - None, - NoTarget, - HasParent, - NotPrefab, - } - - [SerializeField] - GameObject m_root; - - [SerializeField] - bool m_separateByBlendShape = true; - - [Header("Validation")] - [SerializeField] - Material[] m_uniqueMaterials; - - [Serializable] - struct MaterialKey - { - public string Shader; - public KeyValuePair[] Properties; - - public override bool Equals(object obj) + base.Validate(); + if (_exportTarget.GetComponent() == null) { - if (!(obj is MaterialKey)) - { - return base.Equals(obj); - } - - var key = (MaterialKey)obj; - - return Shader == key.Shader - && Properties.SequenceEqual(key.Properties) - ; - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - } - - [Serializable] - struct MaterialList - { - public Material[] Materials; - - public MaterialList(Material[] list) - { - Materials = list; - } - } - [SerializeField] - MaterialList[] m_duplicateMaterials; - - [Serializable] - public class ExcludeItem - { - public Mesh Mesh; - public bool Exclude; - } - - [Header("Options")] - [SerializeField] - List m_excludes = new List(); - - [Header("Result")] - [SerializeField] - MeshMap[] integrationResults; - - public static void CreateWizard() - { - ScriptableWizard.DisplayWizard("MeshIntegratorWizard", "Integrate and close window", "Integrate"); - } - - private void OnEnable() - { - Clear(HelpMessage.Ready, ValidationError.None); - OnValidate(); - } - - protected override bool DrawWizardGUI() - { - var t = m_root.GetGameObjectType(); - EditorGUILayout.HelpBox($"{t}", MessageType.Info); - return base.DrawWizardGUI(); - } - - static object GetPropertyValue(Shader shader, int i, Material m) - { - var propType = ShaderUtil.GetPropertyType(shader, i); - switch (propType) - { - case ShaderUtil.ShaderPropertyType.Color: - return m.GetColor(ShaderUtil.GetPropertyName(shader, i)); - - case ShaderUtil.ShaderPropertyType.Range: - case ShaderUtil.ShaderPropertyType.Float: - return m.GetFloat(ShaderUtil.GetPropertyName(shader, i)); - - case ShaderUtil.ShaderPropertyType.Vector: - return m.GetVector(ShaderUtil.GetPropertyName(shader, i)); - - case ShaderUtil.ShaderPropertyType.TexEnv: - return m.GetTexture(ShaderUtil.GetPropertyName(shader, i)); - - default: - throw new NotImplementedException(propType.ToString()); - } - } - - static MaterialKey GetMaterialKey(Material m) - { - var key = new MaterialKey - { - Shader = m.shader.name, - }; - - key.Properties = Enumerable.Range(0, ShaderUtil.GetPropertyCount(m.shader)) - .Select(x => new KeyValuePair( - ShaderUtil.GetPropertyName(m.shader, x), - GetPropertyValue(m.shader, x, m)) - ) - .OrderBy(x => x.Key) - .ToArray() - ; - - return key; - } - - void Clear(HelpMessage help, ValidationError error) - { - helpString = help.Msg(); - errorString = error != ValidationError.None ? error.Msg() : null; - m_uniqueMaterials = new Material[] { }; - m_duplicateMaterials = new MaterialList[] { }; - m_excludes.Clear(); - isValid = false; - } - - void OnValidate() - { - isValid = false; - if (m_root == null) - { - Clear(HelpMessage.SetTarget, ValidationError.NoTarget); + _validations.Add(Validation.Error("target is not vrm1")); return; } - - if (m_root.GetGameObjectType() != GameObjectType.AssetPrefab) - { - Clear(HelpMessage.SetTarget, ValidationError.NotPrefab); - return; - } - - if (m_root.transform.parent != null) - { - Clear(HelpMessage.InvalidTarget, ValidationError.HasParent); - return; - } - - Clear(HelpMessage.Ready, ValidationError.None); - isValid = true; - m_uniqueMaterials = MeshIntegratorUtility.EnumerateSkinnedMeshRenderer(m_root.transform, MeshEnumerateOption.OnlyWithoutBlendShape) - .SelectMany(x => x.sharedMaterials) - .Distinct() - .ToArray(); - - m_duplicateMaterials = m_uniqueMaterials - .GroupBy(x => GetMaterialKey(x), x => x) - .Select(x => new MaterialList(x.ToArray())) - .Where(x => x.Materials.Length > 1) - .ToArray() - ; - - var exclude_map = new Dictionary(); - var excludes = new List(); - foreach (var x in m_root.GetComponentsInChildren()) - { - var mesh = x.GetMesh(); - if (mesh == null) - { - continue; - } - var item = new ExcludeItem { Mesh = mesh }; - excludes.Add(item); - exclude_map[mesh] = item; - } - foreach (var x in m_excludes) - { - if (exclude_map.TryGetValue(x.Mesh, out ExcludeItem item)) - { - // update - item.Exclude = x.Exclude; - } - } - m_excludes.Clear(); - foreach (var kv in exclude_map) - { - m_excludes.Add(kv.Value); - } } - void OnWizardUpdate() + VrmMeshUtility _meshUtil; + VrmMeshUtility VrmMeshUtility { + get + { + if (_meshUtil == null) + { + _meshUtil = new VrmMeshUtility(); + } + return _meshUtil; + } + } + protected override UniGLTF.MeshUtility.GltfMeshUtility MeshUtility => VrmMeshUtility; + + protected override bool MeshIntegrateGui() + { + var firstPerson = ToggleIsModified("FirstPerson == AUTO の生成", ref MeshUtility.GenerateMeshForFirstPersonAuto); + var mod = base.MeshIntegrateGui(); + return firstPerson || mod; } - /// 2022.05 仕様変更 - /// - /// * prefab 専用 - /// * backup するのではなく 変更した copy を作成する。元は変えない - /// * copy 先の統合前の renderer を disable で残さず destroy する - /// * 実行すると mesh, blendshape, blendShape を新規に作成する - /// * 新しいヒエラルキーを prefab に保存してから削除して終了する - /// - void Integrate() + List _clips; + protected override void WriteAssets(string assetFolder, + GameObject instance, List results) { - if (m_root.GetGameObjectType() != GameObjectType.AssetPrefab) - { - throw new Exception("for prefab only"); - } - - String folder = "Assets"; - var prefab = m_root.GetPrefab(); - if (prefab != null) - { - folder = AssetDatabase.GetAssetPath(prefab); - Debug.Log(folder); - } - - // 新規で作成されるアセットはすべてこのフォルダの中に作る。上書きチェックはしない - var assetFolder = EditorUtility.SaveFolderPanel("select asset save folder", Path.GetDirectoryName(folder), "VrmIntegrated"); - var unityPath = UniGLTF.UnityPath.FromFullpath(assetFolder); - if (!unityPath.IsUnderAssetsFolder) - { - EditorUtility.DisplayDialog("asset folder", "Target folder must be in the `Assets` folder", "cancel"); - return; - } - assetFolder = unityPath.Value; - - var copy = GameObject.Instantiate(m_root); - - // 統合 - var excludes = m_excludes.Where(x => x.Exclude).Select(x => x.Mesh); - var results = Integrate(copy, excludes, m_separateByBlendShape); - - // write mesh asset - foreach (var result in results) - { - var childAssetPath = $"{assetFolder}/{result.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; - Debug.LogFormat("CreateAsset: {0}", childAssetPath); - AssetDatabase.CreateAsset(result.IntegratedRenderer.sharedMesh, childAssetPath); - } - - // 統合した結果をヒエラルキーに追加する - foreach (var result in results) - { - if (result.IntegratedRenderer != null) - { - result.IntegratedRenderer.transform.SetParent(copy.transform, false); - } - } - // 統合した結果を反映した BlendShapeClip を作成して置き換える - var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, copy, assetFolder); + _clips = VrmBlendShapeUpdater.FollowBlendshapeRendererChange(assetFolder, instance, results); - // 用が済んだ 統合前 の renderer を削除する - foreach (var result in results) + // write mesh + base.WriteAssets(assetFolder, instance, results); + + // reset firstPerson + if (instance.GetComponent() is VRMFirstPerson firstPerson) { - foreach (var renderer in result.SourceMeshRenderers) - { - GameObject.DestroyImmediate(renderer); - } - foreach (var renderer in result.SourceSkinnedMeshRenderers) - { - GameObject.DestroyImmediate(renderer); - } + // TODO: + firstPerson.Reset(); } + } - // reset firstperson - var firstperson = copy.GetComponent(); - if (firstperson != null) - { - firstperson.Reset(); - } - - // prefab - var prefabPath = $"{assetFolder}/VrmIntegrated.prefab"; - Debug.Log(prefabPath); - PrefabUtility.SaveAsPrefabAsset(copy, prefabPath, out bool success); - if (!success) - { - throw new System.Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); - } - - // destroy scene - UnityEngine.Object.DestroyImmediate(copy); + protected override string WritePrefab(string assetFolder, + GameObject instance) + { + var prefabPath = base.WritePrefab(assetFolder, instance); + // PostProcess + // update prefab reference of BlendShapeClip var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); - foreach (var clip in clips) + foreach (var clip in _clips) { var so = new SerializedObject(clip); so.Update(); - // clip.Prefab = copy; var prop = so.FindProperty("m_prefab"); prop.objectReferenceValue = prefabReference; so.ApplyModifiedProperties(); } + + return prefabPath; } - static List Integrate(GameObject root, IEnumerable excludes, bool separateByBlendShape) + protected override void DialogMessage() { - var results = new List(); - if (separateByBlendShape) - { - results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape, excludes: excludes)); - results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape, excludes: excludes)); - } - else - { - results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.All, excludes: excludes)); - } - return results; + EditorGUILayout.HelpBox(Message.MESH_UTILITY.Msg(), MessageType.Info); } - void OnWizardCreate() + enum Message { - Integrate(); - // close - } + [LangMsg(Languages.ja, @"(VRM-0.x専用) 凍結 > 統合 > 分割 という一連の処理を実行します。 - void OnWizardOtherButton() - { - Integrate(); +[凍結] +- ヒエラルキーの 回転・拡縮を Mesh に焼き付けます。 +- BlendShape の現状を Mesh に焼き付けます。 + +- VRM-0.x の正規化処理です。 +- HumanoidAvatar の再生成。 +- BlendShapeClip, SpringBone, Constraint なども影響を受けます。 + +[統合] +- ヒエラルキーに含まれる MeshRenderer と SkinnedMeshRenderer をひとつの SkinnedMeshRenderer に統合します。 + +- VRM の FirstPerson 設定に応じて3種類(BOTH, FirstPerson, ThirdPerson) にグループ化して統合します。 +- FirstPerson=AUTO を前処理できます。 + - 元の Mesh は ThirdPerson として処理されます。頭なしのモデルを追加生成して FirstPersonOnly とします。 + +[分割] +- 統合結果を BlendShape の有無を基準に分割します。 +- BOTH, FirstPerson, ThirdPerson x 2 で、最大で 6Mesh になります。空の部分ができることが多いので 3Mesh くらいが多くなります。 + +[Scene と Prefab] +Scene と Prefab で挙動が異なります。 + +(Scene/Runtime) +- 対象のヒエラルキーを変更します。UNDO可能。 +- Asset の書き出しはしません。Unityを再起動すると、書き出していない Mesh などの Asset が消滅します。 + +(Prefab/Editor) +- 対象の prefab をシーンにコピーして処理を実行し、生成する Asset を指定されたフォルダに書き出します。 +- Asset 書き出し後にコピーを削除します。 +- Undo はありません。 +")] + [LangMsg(Languages.en, @"TODO +")] + MESH_UTILITY, } } } diff --git a/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneColliderGroupEditor.cs b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneColliderGroupEditor.cs index 9c2576196..fee110aa3 100644 --- a/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneColliderGroupEditor.cs +++ b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneColliderGroupEditor.cs @@ -16,30 +16,6 @@ namespace VRM m_target = (VRMSpringBoneColliderGroup)target; } - private void OnSceneGUI() - { - Undo.RecordObject(m_target, "VRMSpringBoneColliderGroupEditor"); - - Handles.matrix = m_target.transform.localToWorldMatrix; - Gizmos.color = Color.green; - - bool changed = false; - - foreach (var x in m_target.Colliders) - { - var offset = Handles.PositionHandle(x.Offset, Quaternion.identity); - if (offset != x.Offset) - { - changed = true; - x.Offset = offset; - } - } - - if (changed) - { - EditorUtility.SetDirty(m_target); - } - } override public void OnInspectorGUI() { diff --git a/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneEditor.cs b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneEditor.cs new file mode 100644 index 000000000..68e2027fc --- /dev/null +++ b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneEditor.cs @@ -0,0 +1,122 @@ +using UnityEditor; +using UnityEngine; + +namespace VRM +{ + [CustomEditor(typeof(VRMSpringBone))] + [CanEditMultipleObjects] + class VRMSpringBoneEditor : Editor + { + private VRMSpringBone m_target; + + private SerializedProperty m_commentProp; + private SerializedProperty m_gizmoColorProp; + private SerializedProperty m_stiffnessForceProp; + private SerializedProperty m_gravityPowerProp; + private SerializedProperty m_gravityDirProp; + private SerializedProperty m_dragForceProp; + private SerializedProperty m_centerProp; + private SerializedProperty m_rootBonesProp; + private SerializedProperty m_hitRadiusProp; + private SerializedProperty m_colliderGroupsProp; + private SerializedProperty m_updateTypeProp; + + void OnEnable() + { + if (target == null) + { + return; + } + m_target = (VRMSpringBone)target; + + m_commentProp = serializedObject.FindProperty(nameof(VRMSpringBone.m_comment)); + m_gizmoColorProp = serializedObject.FindProperty("m_gizmoColor"); + m_stiffnessForceProp = serializedObject.FindProperty(nameof(VRMSpringBone.m_stiffnessForce)); + m_gravityPowerProp = serializedObject.FindProperty(nameof(VRMSpringBone.m_gravityPower)); + m_gravityDirProp = serializedObject.FindProperty(nameof(VRMSpringBone.m_gravityDir)); + m_dragForceProp = serializedObject.FindProperty(nameof(VRMSpringBone.m_dragForce)); + m_centerProp = serializedObject.FindProperty(nameof(VRMSpringBone.m_center)); + m_rootBonesProp = serializedObject.FindProperty(nameof(VRMSpringBone.RootBones)); + m_hitRadiusProp = serializedObject.FindProperty(nameof(VRMSpringBone.m_hitRadius)); + m_colliderGroupsProp = serializedObject.FindProperty(nameof(VRMSpringBone.ColliderGroups)); + m_updateTypeProp = serializedObject.FindProperty(nameof(VRMSpringBone.m_updateType)); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_commentProp); + EditorGUILayout.PropertyField(m_gizmoColorProp); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel); + + LimitBreakSlider(m_stiffnessForceProp, 0.0f, 4.0f, 0.0f, Mathf.Infinity); + LimitBreakSlider(m_gravityPowerProp, 0.0f, 2.0f, 0.0f, Mathf.Infinity); + EditorGUILayout.PropertyField(m_gravityDirProp); + EditorGUILayout.PropertyField(m_dragForceProp); + EditorGUILayout.PropertyField(m_centerProp); + EditorGUILayout.PropertyField(m_rootBonesProp); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Collision", EditorStyles.boldLabel); + + LimitBreakSlider(m_hitRadiusProp, 0.0f, 0.5f, 0.0f, Mathf.Infinity); + EditorGUILayout.PropertyField(m_colliderGroupsProp); + EditorGUILayout.PropertyField(m_updateTypeProp); + + + serializedObject.ApplyModifiedProperties(); + } + + /// + /// スライダーと数値入力で限界値の違う、所謂「限界突破スライダー」を作成する + /// `EditorGUILayout.PropertyField` の代替として利用する + /// + private static void LimitBreakSlider(SerializedProperty property, float sliderLeft, float sliderRight, float numberLeft, float numberRight) + { + var label = new GUIContent(property.displayName); + var currentValue = property.floatValue; + + var rect = EditorGUILayout.GetControlRect(); + + EditorGUI.BeginProperty(rect, label, property); + + rect = EditorGUI.PrefixLabel(rect, label); + + // slider + { + EditorGUI.BeginChangeCheck(); + + var sliderRect = rect; + sliderRect.width -= 55.0f; + rect.xMin += rect.width - 50.0f; + + var clampedvalue = Mathf.Clamp(currentValue, sliderLeft, sliderRight); + var sliderValue = GUI.HorizontalSlider(sliderRect, clampedvalue, sliderLeft, sliderRight); + + if (EditorGUI.EndChangeCheck()) + { + property.floatValue = sliderValue; + } + } + + // number + { + EditorGUI.BeginChangeCheck(); + + var numberValue = Mathf.Clamp(EditorGUI.FloatField(rect, currentValue), numberLeft, numberRight); + + if (EditorGUI.EndChangeCheck()) + { + property.floatValue = numberValue; + } + } + + EditorGUI.EndProperty(); + } + } +} diff --git a/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneEditor.cs.meta b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneEditor.cs.meta new file mode 100644 index 000000000..64402c885 --- /dev/null +++ b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bcc37b2e1c446d4448718e89fcba946b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneUtilityEditor.cs b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneUtilityEditor.cs index f2fca496d..30f5b932e 100644 --- a/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneUtilityEditor.cs +++ b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneUtilityEditor.cs @@ -10,7 +10,7 @@ namespace VRM internal static class VRMSpringBoneUtilityEditor { #region save - + public const string SAVE_MENU_NAME = "VRM 0.x Save SpringBone to JSON..."; public static bool SaveSpringBoneToJsonValidation() { var root = Selection.activeObject as GameObject; @@ -57,7 +57,7 @@ namespace VRM #endregion #region load - + public const string LOAD_MENU_NAME = "VRM 0.x Load SpringBone from JSON..."; public static bool LoadSpringBoneFromJsonValidation() { var root = Selection.activeObject as GameObject; @@ -93,10 +93,18 @@ namespace VRM var root = go.transform; var nodes = root.Traverse().Skip(1).ToList(); - VRMSpringUtility.LoadSecondary(root, nodes, spring); + VRMSpringUtility.LoadSecondary(root, (int index, out Transform node) => + { + if (index < 0 || index >= nodes.Count) + { + Debug.LogWarning($"nodes[{index}] is not found !"); + node = default; + return false; + } + node = nodes[index]; + return true; + }, spring); } - #endregion - } } \ No newline at end of file diff --git a/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneValidator.cs b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneValidator.cs index 73baecc0b..6829540ec 100644 --- a/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneValidator.cs +++ b/Assets/External/VRM/Editor/SpringBone/VRMSpringBoneValidator.cs @@ -26,17 +26,17 @@ namespace VRM var springRoot = sb.RootBones[i]; if (springRoot == null) { - yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is null"); + yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is null", ValidationContext.Create(sb)); continue; } if (!hierarchy.Contains(springRoot)) { - yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is out of hierarchy"); + yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is out of hierarchy", ValidationContext.Create(sb)); continue; } if (!springRoot.transform.EnableForExport()) { - yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is not active"); + yield return Validation.Error($"[VRMSpringBone]{sb.name}.RootBones[{i}] is not active", ValidationContext.Create(sb)); continue; } diff --git a/Assets/External/VRM/Editor/VRM.Editor.asmdef b/Assets/External/VRM/Editor/VRM.Editor.asmdef index 88f69347e..1f917e647 100644 --- a/Assets/External/VRM/Editor/VRM.Editor.asmdef +++ b/Assets/External/VRM/Editor/VRM.Editor.asmdef @@ -1,5 +1,6 @@ { "name": "UniVRM.Editor", + "rootNamespace": "", "references": [ "GUID:05dd262a0c0a2f841b8252c8c3815582", "GUID:b7aa47b240b57de44a4b2021c143c9bf", @@ -8,7 +9,7 @@ "GUID:8d76e605759c3f64a957d63ef96ada7c", "GUID:5f875fdc81c40184c8333b9d63c6ddd5", "GUID:301b251fd9834274c9228e0532f444f7", - "GUID:bc66ece0f33b52446a0830c05781d4db" + "GUID:1cd941934d098654fa21a13f28346412" ], "includePlatforms": [ "Editor" diff --git a/Assets/External/VRM/Editor/VRMExportUnityPackage.cs b/Assets/External/VRM/Editor/VRMExportUnityPackage.cs index 4b43eac49..35be05607 100644 --- a/Assets/External/VRM/Editor/VRMExportUnityPackage.cs +++ b/Assets/External/VRM/Editor/VRMExportUnityPackage.cs @@ -73,7 +73,7 @@ namespace VRM.DevOnly.PackageExporter var path = string.Format("{0}/{1}-{2}_{3}.unitypackage", folder, prefix, - VRMVersion.VERSION, + UniGLTF.PackageVersion.VERSION, GetGitHash(Application.dataPath + "/VRM").Substring(0, 4) ).Replace("\\", "/"); @@ -187,6 +187,11 @@ namespace VRM.DevOnly.PackageExporter public static void CreateUnityPackages(string outputDir) { + if (!VRMSampleCopy.Validate()) + { + throw new Exception("SampleCopy is not same !"); + } + { var packages = new[]{ // VRM diff --git a/Assets/External/VRM/Editor/VrmTopMenu.cs b/Assets/External/VRM/Editor/VrmTopMenu.cs index 3ed060112..bcf9f937a 100644 --- a/Assets/External/VRM/Editor/VrmTopMenu.cs +++ b/Assets/External/VRM/Editor/VrmTopMenu.cs @@ -6,58 +6,57 @@ namespace VRM { public static class VrmTopMenu { - private const string UserMenuPrefix = VRMVersion.MENU; - private const string DevelopmentMenuPrefix = VRMVersion.MENU + "/Development"; + private const string UserMenuPrefix = PackageVersion.MENU; + private const string DevelopmentMenuPrefix = PackageVersion.MENU + "/Development"; - [MenuItem(UserMenuPrefix + "/Version: " + VRMVersion.VRM_VERSION, validate = true)] + + [MenuItem(UserMenuPrefix + "/" + PackageVersion.MENU_NAME, true, 0)] private static bool ShowVersionValidation() => false; - - [MenuItem(UserMenuPrefix + "/Version: " + VRMVersion.VRM_VERSION, priority = 0)] + [MenuItem(UserMenuPrefix + "/" + PackageVersion.MENU_NAME, false, 0)] private static void ShowVersion() { } - [MenuItem(UserMenuPrefix + "/Export to VRM 0.x", priority = 1)] + + [MenuItem(UserMenuPrefix + "/" + VRMExporterWizard.MENU_NAME, false, 1)] private static void ExportToVrmFile() => VRMExporterWizard.OpenExportMenu(); - [MenuItem(UserMenuPrefix + "/Import from VRM 0.x", priority = 2)] + + [MenuItem(UserMenuPrefix + "/" + VRMImporterMenu.MENU_NAME, false, 2)] private static void ImportFromVrmFile() => VRMImporterMenu.OpenImportMenu(); - [MenuItem(UserMenuPrefix + "/Freeze T-Pose", validate = true)] - private static bool FreezeTPoseValidation() => VRMHumanoidNormalizerMenu.NormalizeValidation(); - [MenuItem(UserMenuPrefix + "/Freeze T-Pose", priority = 20)] + [MenuItem(UserMenuPrefix + "/" + VrmMeshIntegratorWizard.MENU_NAME, false, 51)] + private static void OpenMeshIntegratorWizard() => VrmMeshIntegratorWizard.OpenWindow(); + + + [MenuItem(UserMenuPrefix + "/" + VRMHumanoidNormalizerMenu.MENU_NAME, true, 52)] + private static bool FreezeTPoseValidation() => VRMHumanoidNormalizerMenu.NormalizeValidation(); + [MenuItem(UserMenuPrefix + "/" + VRMHumanoidNormalizerMenu.MENU_NAME, false, 52)] private static void FreezeTPose() => VRMHumanoidNormalizerMenu.Normalize(); - [MenuItem(UserMenuPrefix + "/MeshIntegratorWizard", priority = 21)] - private static void OpenMeshIntegratorWizard() => VrmMeshIntegratorWizard.CreateWizard(); - [MenuItem(UserMenuPrefix + "/Save SpringBone to JSON", validate = true)] + [MenuItem(UserMenuPrefix + "/" + VRMSpringBoneUtilityEditor.SAVE_MENU_NAME, true, 53)] private static bool SaveSpringBoneToJsonValidation() => VRMSpringBoneUtilityEditor.SaveSpringBoneToJsonValidation(); - - [MenuItem(UserMenuPrefix + "/Save SpringBone to JSON", priority = 22)] + [MenuItem(UserMenuPrefix + "/" + VRMSpringBoneUtilityEditor.SAVE_MENU_NAME, false, 53)] private static void SaveSpringBoneToJson() => VRMSpringBoneUtilityEditor.SaveSpringBoneToJson(); - [MenuItem(UserMenuPrefix + "/Load SpringBone from JSON", validate = true)] - private static bool LoadSpringBoneFromJsonValidation() => VRMSpringBoneUtilityEditor.LoadSpringBoneFromJsonValidation(); - [MenuItem(UserMenuPrefix + "/Load SpringBone from JSON", priority = 23)] + [MenuItem(UserMenuPrefix + "/" + VRMSpringBoneUtilityEditor.LOAD_MENU_NAME, true, 54)] + private static bool LoadSpringBoneFromJsonValidation() => VRMSpringBoneUtilityEditor.LoadSpringBoneFromJsonValidation(); + [MenuItem(UserMenuPrefix + "/" + VRMSpringBoneUtilityEditor.LOAD_MENU_NAME, false, 54)] private static void LoadSpringBoneFromJson() => VRMSpringBoneUtilityEditor.LoadSpringBoneFromJson(); - #if VRM_DEVELOP - [MenuItem(DevelopmentMenuPrefix + "/Generate Serialization Code", priority = 30)] + [MenuItem(DevelopmentMenuPrefix + "/Generate Serialization Code", false, 91)] private static void GenerateSerializer() => VRMAOTCodeGenerator.GenerateCode(); - [MenuItem(DevelopmentMenuPrefix + "/Version Dialog", priority = 32)] + [MenuItem(DevelopmentMenuPrefix + "/Version Dialog", false, 92)] private static void ShowVersionDialog() => VRMVersionMenu.ShowVersionDialog(); - [MenuItem(DevelopmentMenuPrefix + "/Build dummy for CI", priority = 33)] + [MenuItem(DevelopmentMenuPrefix + "/Build dummy for CI", false, 93)] private static void BuildDummyForCi() => BuildClass.Build(); - [MenuItem(DevelopmentMenuPrefix + "/Create UnityPackage", priority = 34)] + [MenuItem(DevelopmentMenuPrefix + "/Create UnityPackage", false, 94)] private static void CreateUnityPackage() => VRMExportUnityPackage.CreateUnityPackageWithoutBuild(); - - [MenuItem(DevelopmentMenuPrefix + "/Export ShaderProps Code", priority = 35)] - private static void ExportShaderPropertyCode() => ShaderPropMenu.PreExport(); #endif } } \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/BlendShape/BlendShapeAvatar.cs b/Assets/External/VRM/Runtime/BlendShape/BlendShapeAvatar.cs index 6129050e3..743ef2001 100644 --- a/Assets/External/VRM/Runtime/BlendShape/BlendShapeAvatar.cs +++ b/Assets/External/VRM/Runtime/BlendShape/BlendShapeAvatar.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using UniGLTF; using System.IO; +using UniGLTF.Utils; #if UNITY_EDITOR using UnityEditor; #endif @@ -16,24 +17,6 @@ namespace VRM [SerializeField] public List Clips = new List(); - /// - /// NullのClipを削除して詰める - /// - public void RemoveNullClip() - { - if (Clips == null) - { - return; - } - for (int i = Clips.Count - 1; i >= 0; --i) - { - if (Clips[i] == null) - { - Clips.RemoveAt(i); - } - } - } - #if UNITY_EDITOR [ContextMenu("Restore")] void Restore() @@ -79,7 +62,7 @@ namespace VRM /// public void CreateDefaultPreset() { - var presets = CacheEnum.GetValues(); + var presets = CachedEnum.GetValues(); foreach (var preset in presets) { diff --git a/Assets/External/VRM/Runtime/BlendShape/PreviewSceneManager.cs b/Assets/External/VRM/Runtime/BlendShape/PreviewSceneManager.cs index 1a748011f..15875e7be 100644 --- a/Assets/External/VRM/Runtime/BlendShape/PreviewSceneManager.cs +++ b/Assets/External/VRM/Runtime/BlendShape/PreviewSceneManager.cs @@ -1,15 +1,10 @@ -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using UnityEngine; -using System.Reflection; using System; -#if UNITY_EDITOR -using UnityEditor; -#endif +using VRMShaders; using UniGLTF; - namespace VRM { /// @@ -56,14 +51,17 @@ namespace VRM // HideFlags are special editor-only settings that let you have *secret* GameObjects in a scene, or to tell Unity not to save that temporary GameObject as part of the scene foreach (var x in go.transform.Traverse()) { - x.gameObject.hideFlags = HideFlags.None - | HideFlags.DontSave - //| HideFlags.DontSaveInBuild -#if VRM_DEVELOP -#else - | HideFlags.HideAndDontSave -#endif - ; + if (Symbols.VRM_DEVELOP) + { + x.gameObject.hideFlags = HideFlags.None | + HideFlags.DontSave; + } + else + { + x.gameObject.hideFlags = HideFlags.None | + HideFlags.DontSave | + HideFlags.HideAndDontSave; + } } return manager; @@ -247,24 +245,29 @@ namespace VRM foreach (var x in bake.MaterialValueBindings) { - MaterialItem item; - if (m_materialMap.TryGetValue(x.MaterialName, out item)) + if (m_materialMap.TryGetValue(x.MaterialName, out var item)) { //Debug.Log("set material"); - PropItem prop; - if (item.PropMap.TryGetValue(x.ValueName, out prop)) + if (item.PropMap.TryGetValue(x.ValueName, out _)) { - var valueName = x.ValueName; - if (valueName.EndsWith("_ST_S") - || valueName.EndsWith("_ST_T")) + var offsetValue = x.TargetValue - x.BaseValue; + var targetPropName = x.ValueName; + if (x.ValueName.EndsWith("_ST_S")) { - valueName = valueName.Substring(0, valueName.Length - 2); + offsetValue.y = 0; + offsetValue.w = 0; + targetPropName = targetPropName.Substring(0, targetPropName.Length - 2); + } + else if (x.ValueName.EndsWith("_ST_T")) + { + offsetValue.x = 0; + offsetValue.z = 0; + targetPropName = targetPropName.Substring(0, targetPropName.Length - 2); } - var value = item.Material.GetVector(valueName); - //Debug.LogFormat("{0} => {1}", valueName, x.TargetValue); - value += ((x.TargetValue - x.BaseValue) * bake.Weight); - item.Material.SetColor(valueName, value); + var value = item.Material.GetVector(targetPropName); + value += offsetValue * bake.Weight; + item.Material.SetColor(targetPropName, value); } } } diff --git a/Assets/External/VRM/Runtime/BlendShape/VRMBlendShapeProxy.cs b/Assets/External/VRM/Runtime/BlendShape/VRMBlendShapeProxy.cs index 1721c6dab..ff74af168 100644 --- a/Assets/External/VRM/Runtime/BlendShape/VRMBlendShapeProxy.cs +++ b/Assets/External/VRM/Runtime/BlendShape/VRMBlendShapeProxy.cs @@ -17,9 +17,10 @@ namespace VRM } BlendShapeMerger m_merger; - + bool m_destroyed = false; private void OnDestroy() { + m_destroyed = true; if (m_merger != null) { m_merger.RestoreMaterialInitialValues(BlendShapeAvatar.Clips); @@ -28,13 +29,25 @@ namespace VRM private void Start() { - if (BlendShapeAvatar != null) + if (m_destroyed) { - if (m_merger == null) - { - m_merger = new BlendShapeMerger(BlendShapeAvatar.Clips, transform); - } + return; } + if (BlendShapeAvatar == null) + { + return; + } + // m_merger の null check は必用か? + m_merger = new BlendShapeMerger(BlendShapeAvatar.Clips, transform); + } + + /// + /// m_merger を(再)作成する。 + /// BlendShapeAvatar.Clips に対する変更を反映できます。 + /// + public void Reinitialize() + { + Start(); } /// diff --git a/Assets/External/VRM/Runtime/FirstPerson/VRMFirstPerson.cs b/Assets/External/VRM/Runtime/FirstPerson/VRMFirstPerson.cs index 1b600df6b..9f0ba8865 100644 --- a/Assets/External/VRM/Runtime/FirstPerson/VRMFirstPerson.cs +++ b/Assets/External/VRM/Runtime/FirstPerson/VRMFirstPerson.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using UniGLTF; using UniGLTF.MeshUtility; +using UniGLTF.Utils; using UnityEngine; @@ -56,7 +57,22 @@ namespace VRM var dst = _dst.AddComponent(); dst.FirstPersonBone = map[FirstPersonBone]; dst.FirstPersonOffset = FirstPersonOffset; - dst.Renderers = Renderers.Select(x => + dst.Renderers = Renderers + .Where(x => + { + if (x.Renderer == null || x.Renderer.transform == null) + { + Debug.LogWarning("[VRMFirstPerson] Renderer is null", this); + return false; + } + if (!map.ContainsKey(x.Renderer.transform)) + { + Debug.LogWarning("[VRMFirstPerson] Cannot copy. Not found ?", this); + return false; + } + return true; + }) + .Select(x => { var mapped = map[x.Renderer.transform]; var renderer = mapped.GetComponent(); @@ -126,7 +142,7 @@ namespace VRM { if (x.mesh == index) { - return CacheEnum.TryParseOrDefault(x.firstPersonFlag, true); + return CachedEnum.ParseOrDefault(x.firstPersonFlag, true); } } @@ -366,6 +382,17 @@ namespace VRM } } + /// + /// for MeshUtility interface + /// + public Mesh ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + SetVisibilityFunc dummy = (Renderer renderer, bool firstPerson, bool thirdPerson) => + { + }; + return CreateHeadlessModel(smr, FirstPersonBone, dummy); + } + void OnDestroy() { foreach (var mesh in m_headlessMeshes) diff --git a/Assets/External/VRM/Runtime/Format/VRMVersion.cs b/Assets/External/VRM/Runtime/Format/VRMVersion.cs deleted file mode 100644 index abb1af93c..000000000 --- a/Assets/External/VRM/Runtime/Format/VRMVersion.cs +++ /dev/null @@ -1,11 +0,0 @@ - -namespace VRM -{ - public static partial class VRMVersion - { - public const int MAJOR = 0; - public const int MINOR = 99; - public const int PATCH = 0; - public const string VERSION = "0.99.0"; - } -} diff --git a/Assets/External/VRM/Runtime/Format/VRMVersionPartial.cs.meta b/Assets/External/VRM/Runtime/Format/VRMVersionPartial.cs.meta deleted file mode 100644 index b505fdb09..000000000 --- a/Assets/External/VRM/Runtime/Format/VRMVersionPartial.cs.meta +++ /dev/null @@ -1,13 +0,0 @@ -fileFormatVersion: 2 -guid: 4ab9ac9856a4d4c4aa652c07c5b496e6 -timeCreated: 1522130257 -licenseType: Free -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/External/VRM/Runtime/Format/glTF_VRM_FirstPerson.cs b/Assets/External/VRM/Runtime/Format/glTF_VRM_FirstPerson.cs index f1ab7e968..1c7517bef 100644 --- a/Assets/External/VRM/Runtime/Format/glTF_VRM_FirstPerson.cs +++ b/Assets/External/VRM/Runtime/Format/glTF_VRM_FirstPerson.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using UniGLTF; +using UniGLTF.Utils; using UnityEngine; -using UniJSON; namespace VRM @@ -72,7 +72,7 @@ namespace VRM { get { - return CacheEnum.TryParseOrDefault(lookAtTypeName, true); + return CachedEnum.ParseOrDefault(lookAtTypeName, true); } set { lookAtTypeName = value.ToString(); } } diff --git a/Assets/External/VRM/Runtime/Format/glTF_VRM_Humanoid.cs b/Assets/External/VRM/Runtime/Format/glTF_VRM_Humanoid.cs index 27e1051f7..6477818ba 100644 --- a/Assets/External/VRM/Runtime/Format/glTF_VRM_Humanoid.cs +++ b/Assets/External/VRM/Runtime/Format/glTF_VRM_Humanoid.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using UniGLTF; +using UniGLTF.Utils; using UnityEngine; namespace VRM @@ -139,7 +140,7 @@ namespace VRM } get { - return CacheEnum.Parse(bone, true); + return CachedEnum.Parse(bone, true); } } diff --git a/Assets/External/VRM/Runtime/Format/glTF_VRM_Meta.cs b/Assets/External/VRM/Runtime/Format/glTF_VRM_Meta.cs index c1036ebc7..89a11be0a 100644 --- a/Assets/External/VRM/Runtime/Format/glTF_VRM_Meta.cs +++ b/Assets/External/VRM/Runtime/Format/glTF_VRM_Meta.cs @@ -1,6 +1,6 @@ using System; using UniGLTF; -using UniJSON; +using UniGLTF.Utils; namespace VRM { @@ -36,7 +36,7 @@ namespace VRM { static UssageLicense FromString(string src) { - return CacheEnum.TryParseOrDefault(src, true); + return CachedEnum.ParseOrDefault(src, true); } [JsonSchema(Description = "Title of VRM model")] @@ -69,7 +69,7 @@ namespace VRM { get { - return CacheEnum.TryParseOrDefault(allowedUserName, true); + return CachedEnum.ParseOrDefault(allowedUserName, true); } set { @@ -135,7 +135,7 @@ namespace VRM { get { - return CacheEnum.TryParseOrDefault(licenseName, true); + return CachedEnum.ParseOrDefault(licenseName, true); } set { diff --git a/Assets/External/VRM/Runtime/Format/glTF_VRM_extensions.cs b/Assets/External/VRM/Runtime/Format/glTF_VRM_extensions.cs index 19b41c3d4..631b3fc9e 100644 --- a/Assets/External/VRM/Runtime/Format/glTF_VRM_extensions.cs +++ b/Assets/External/VRM/Runtime/Format/glTF_VRM_extensions.cs @@ -15,8 +15,8 @@ VRM extension is for 3d humanoid avatars (and models) in VR applications. public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(ExtensionName); - [JsonSchema(Description = @"Version of exporter that vrm created. " + VRMVersion.VRM_VERSION)] - public string exporterVersion = "UniVRM-" + VRMVersion.VERSION; + [JsonSchema(Description = @"Version of exporter that vrm created. " + PackageVersion.VRM_VERSION)] + public string exporterVersion = "UniVRM-" + PackageVersion.VERSION; [JsonSchema(Description = @"Version of VRM specification. " + VRMSpecVersion.VERSION)] public string specVersion = VRMSpecVersion.Version; diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO.meta b/Assets/External/VRM/Runtime/IO/MaterialIO.meta new file mode 100644 index 000000000..b743ef755 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e19d2d0ec40e459daba62135926d7dc9 +timeCreated: 1667543937 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP.meta new file mode 100644 index 000000000..2a74108e6 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c0d00129f7e844259bb416832e692737 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export.meta new file mode 100644 index 000000000..04c0f1c6d --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4deb03e5216447f09accee57f66c1186 +timeCreated: 1667543899 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmExtensionMaterialPropertyExporter.cs b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmExtensionMaterialPropertyExporter.cs new file mode 100644 index 000000000..02275ad85 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmExtensionMaterialPropertyExporter.cs @@ -0,0 +1,130 @@ +using System; +using UniGLTF; +using UniGLTF.ShaderPropExporter; +using UnityEngine; +using VRMShaders; +using ColorSpace = VRMShaders.ColorSpace; + +namespace VRM +{ + /// + /// VRM/MToon のマテリアル情報をエクスポートする。 + /// VRM extension 内の materialProperties に記録するデータを用意する。 + /// + public static class BuiltInVrmExtensionMaterialPropertyExporter + { + private static readonly string[] ExportingTags = + { + "RenderType", + // "Queue", + }; + + public static glTF_VRM_Material ExportMaterial(Material m, ITextureExporter textureExporter) + { + var material = new glTF_VRM_Material + { + name = m.name, + shader = m.shader.name, + renderQueue = m.renderQueue, + }; + + if (m.shader.name != MToon.Utils.ShaderName) + { + material.shader = glTF_VRM_Material.VRM_USE_GLTFSHADER; + return material; + } + + var prop = PreShaderPropExporter.GetPropsForMToon(); + if (prop == null) + { + throw new Exception("arienai"); + } + else + { + foreach (var keyword in m.shaderKeywords) + { + material.keywordMap.Add(keyword, m.IsKeywordEnabled(keyword)); + } + + // get properties + //material.SetProp(prop); + foreach (var kv in prop.Properties) + { + switch (kv.ShaderPropertyType) + { + case ShaderPropertyType.Color: + { + // No color conversion. Because color property is serialized to raw float array. + var value = m.GetColor(kv.Key).ToFloat4(ColorSpace.Linear, ColorSpace.Linear); + material.vectorProperties.Add(kv.Key, value); + } + break; + + case ShaderPropertyType.Range: + case ShaderPropertyType.Float: + { + var value = m.GetFloat(kv.Key); + material.floatProperties.Add(kv.Key, value); + } + break; + + case ShaderPropertyType.TexEnv: + { + var texture = m.GetTexture(kv.Key); + if (texture != null) + { + var value = -1; + var isNormalMap = kv.Key == "_BumpMap"; + if (isNormalMap) + { + value = textureExporter.RegisterExportingAsNormal(texture); + } + else + { + var needsAlpha = kv.Key == "_MainTex"; + value = textureExporter.RegisterExportingAsSRgb(texture, needsAlpha); + } + if (value == -1) + { + Debug.LogFormat("not found {0}", texture.name); + } + else + { + material.textureProperties.Add(kv.Key, value); + } + } + + // offset & scaling + var offset = m.GetTextureOffset(kv.Key); + var scaling = m.GetTextureScale(kv.Key); + material.vectorProperties.Add(kv.Key, + new float[] { offset.x, offset.y, scaling.x, scaling.y }); + } + break; + + case ShaderPropertyType.Vector: + { + var value = m.GetVector(kv.Key).ToArray(); + material.vectorProperties.Add(kv.Key, value); + } + break; + + default: + throw new NotImplementedException(); + } + } + } + + foreach (var tag in ExportingTags) + { + var value = m.GetTag(tag, false); + if (!String.IsNullOrEmpty(value)) + { + material.tagMap.Add(tag, value); + } + } + + return material; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmExtensionMaterialPropertyExporter.cs.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmExtensionMaterialPropertyExporter.cs.meta new file mode 100644 index 000000000..7b78bd17d --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmExtensionMaterialPropertyExporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 656dd5e643384d7489070cc3759d2f45 +timeCreated: 1667405286 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmMaterialExporter.cs b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmMaterialExporter.cs new file mode 100644 index 000000000..9b3f99216 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmMaterialExporter.cs @@ -0,0 +1,29 @@ +using System; +using UniGLTF; +using UnityEngine; +using VRMShaders; + +namespace VRM +{ + public class BuiltInVrmMaterialExporter : IMaterialExporter + { + public static readonly string[] SupportedShaderNames = + { + BuiltInVrmMToonMaterialExporter.TargetShaderName, + }; + + private readonly BuiltInGltfMaterialExporter _gltfExporter = new BuiltInGltfMaterialExporter(); + + public glTFMaterial ExportMaterial(Material src, ITextureExporter textureExporter, GltfExportSettings settings) + { + switch (src.shader.name) + { + case BuiltInVrmMToonMaterialExporter.TargetShaderName: + if (BuiltInVrmMToonMaterialExporter.TryExportMaterial(src, textureExporter, out var dst)) return dst; + break; + } + + return _gltfExporter.ExportMaterial(src, textureExporter, settings); + } + } +} diff --git a/Assets/External/VRM/Runtime/IO/VRMMaterialExporter.cs.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmMaterialExporter.cs.meta similarity index 100% rename from Assets/External/VRM/Runtime/IO/VRMMaterialExporter.cs.meta rename to Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/BuiltInVrmMaterialExporter.cs.meta diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials.meta new file mode 100644 index 000000000..a1e59f85a --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c07da887c5e5488a9a642b5543464643 +timeCreated: 1667543948 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInVrmMToonMaterialExporter.cs b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInVrmMToonMaterialExporter.cs new file mode 100644 index 000000000..c376d22f2 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInVrmMToonMaterialExporter.cs @@ -0,0 +1,124 @@ +using System; +using MToon; +using UniGLTF; +using UnityEngine; +using VRMShaders; +using ColorSpace = VRMShaders.ColorSpace; +using RenderMode = MToon.RenderMode; + +namespace VRM +{ + /// + /// VRM/MToon のマテリアル情報をエクスポートする。 + /// ただし VRM 0.x としては VRM extension 内の materialProperties に記録されているデータが正である。 + /// したがって、ここで出力するデータはあくまで VRM を表示できない glTF ビューワでの見た目をある程度保証するために作成するものである。 + /// + public static class BuiltInVrmMToonMaterialExporter + { + public const string TargetShaderName = MToon.Utils.ShaderName; + + public static bool TryExportMaterial(Material src, ITextureExporter textureExporter, out glTFMaterial dst) + { + if (src.shader.name != TargetShaderName) + { + dst = default; + return false; + } + + var srcProps = MToon.Utils.GetMToonParametersFromMaterial(src); + + dst = glTF_KHR_materials_unlit.CreateDefault(); + dst.name = src.name; + ExportRenderingSettings(srcProps, dst); + ExportBaseColor(src, srcProps, textureExporter, dst); + ExportEmission(src, srcProps, textureExporter, dst); + + return true; + } + + private static void ExportRenderingSettings(MToonDefinition src, glTFMaterial dst) + { + switch (src.Rendering.RenderMode) + { + case RenderMode.Opaque: + dst.alphaMode = glTFBlendMode.OPAQUE.ToString(); + break; + case RenderMode.Cutout: + dst.alphaMode = glTFBlendMode.MASK.ToString(); + dst.alphaCutoff = src.Color.CutoutThresholdValue; + break; + case RenderMode.Transparent: + dst.alphaMode = glTFBlendMode.BLEND.ToString(); + break; + case RenderMode.TransparentWithZWrite: + // NOTE: Ambiguous but better. + dst.alphaMode = glTFBlendMode.BLEND.ToString(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + switch (src.Rendering.CullMode) + { + case CullMode.Off: + dst.doubleSided = true; + break; + case CullMode.Front: + // NOTE: Ambiguous but better. + dst.doubleSided = true; + break; + case CullMode.Back: + dst.doubleSided = false; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private static void ExportBaseColor(Material srcMaterial, MToonDefinition src, ITextureExporter textureExporter, glTFMaterial dst) + { + dst.pbrMetallicRoughness.baseColorFactor = src.Color.LitColor.ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); + + if (src.Color.LitMultiplyTexture != null) + { + var index = textureExporter.RegisterExportingAsSRgb(src.Color.LitMultiplyTexture, src.Rendering.RenderMode != RenderMode.Opaque); + if (index != -1) + { + dst.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo() + { + index = index, + }; + ExportMainTextureTransform(srcMaterial, dst.pbrMetallicRoughness.baseColorTexture); + } + } + } + + private static void ExportEmission(Material srcMaterial, MToonDefinition src, ITextureExporter textureExporter, glTFMaterial dst) + { + var emissionFactor = src.Emission.EmissionColor; + if (emissionFactor.maxColorComponent > 1) + { + emissionFactor /= emissionFactor.maxColorComponent; + } + dst.emissiveFactor = emissionFactor.ToFloat3(ColorSpace.Linear, ColorSpace.Linear); + + if (src.Emission.EmissionMultiplyTexture != null) + { + var index = textureExporter.RegisterExportingAsSRgb(src.Emission.EmissionMultiplyTexture, needsAlpha: false); + if (index != -1) + { + dst.emissiveTexture = new glTFMaterialEmissiveTextureInfo() + { + index = index, + }; + ExportMainTextureTransform(srcMaterial, dst.emissiveTexture); + } + } + } + + private static void ExportMainTextureTransform(Material src, glTFTextureInfo targetTextureInfo) + { + GltfMaterialExportUtils.ExportTextureTransform(src, targetTextureInfo, MToon.Utils.PropMainTex); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInVrmMToonMaterialExporter.cs.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInVrmMToonMaterialExporter.cs.meta new file mode 100644 index 000000000..ae1c2c4fb --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Export/Materials/BuiltInVrmMToonMaterialExporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1afab05a32ff435082b4ae879730886d +timeCreated: 1667405966 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import.meta new file mode 100644 index 000000000..aef4eca5a --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e6934570a2714a3291b8c054416d5b49 +timeCreated: 1667543979 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/VRMMaterialDescriptorGenerator.cs b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/BuiltInVrmMaterialDescriptorGenerator.cs similarity index 52% rename from Assets/External/VRM/Runtime/IO/VRMMaterialDescriptorGenerator.cs rename to Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/BuiltInVrmMaterialDescriptorGenerator.cs index 80de66b31..91c4cfd9c 100644 --- a/Assets/External/VRM/Runtime/IO/VRMMaterialDescriptorGenerator.cs +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/BuiltInVrmMaterialDescriptorGenerator.cs @@ -6,36 +6,37 @@ using VRMShaders; namespace VRM { - public sealed class VRMMaterialDescriptorGenerator : IMaterialDescriptorGenerator + public sealed class BuiltInVrmMaterialDescriptorGenerator : IMaterialDescriptorGenerator { - readonly glTF_VRM_extensions m_vrm; - public VRMMaterialDescriptorGenerator(glTF_VRM_extensions vrm) + private readonly glTF_VRM_extensions _vrm; + + public BuiltInVrmMaterialDescriptorGenerator(glTF_VRM_extensions vrm) { - m_vrm = vrm; + _vrm = vrm; } public MaterialDescriptor Get(GltfData data, int i) { // legacy "VRM/UnlitTransparentZWrite" - if (VRMUnlitTransparentZWriteMaterialImporter.TryCreateParam(data, m_vrm, i, out var matDesc)) + if (BuiltInVrmUnlitTransparentZWriteMaterialImporter.TryCreateParam(data, _vrm, i, out var matDesc)) { return matDesc; } // mtoon - if (VRMMToonMaterialImporter.TryCreateParam(data, m_vrm, i, out matDesc)) + if (BuiltInVrmMToonMaterialImporter.TryCreateParam(data, _vrm, i, out matDesc)) { return matDesc; } // unlit - if (GltfUnlitMaterialImporter.TryCreateParam(data, i, out matDesc)) + if (BuiltInGltfUnlitMaterialImporter.TryCreateParam(data, i, out matDesc)) { return matDesc; } // pbr - if (GltfPbrMaterialImporter.TryCreateParam(data, i, out matDesc)) + if (BuiltInGltfPbrMaterialImporter.TryCreateParam(data, i, out matDesc)) { return matDesc; } @@ -43,8 +44,8 @@ namespace VRM // fallback Debug.LogWarning($"fallback"); return new MaterialDescriptor( - GltfMaterialDescriptorGenerator.GetMaterialName(i, null), - GltfPbrMaterialImporter.ShaderName, + GltfMaterialImportUtils.ImportMaterialName(i, null), + BuiltInGltfPbrMaterialImporter.Shader, null, new Dictionary(), new Dictionary(), @@ -52,5 +53,10 @@ namespace VRM new Dictionary(), new Action[]{}); } + + public MaterialDescriptor GetGltfDefault() + { + return BuiltInGltfDefaultMaterialImporter.CreateParam(); + } } } diff --git a/Assets/External/VRM/Runtime/IO/VRMMaterialDescriptorGenerator.cs.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/BuiltInVrmMaterialDescriptorGenerator.cs.meta similarity index 100% rename from Assets/External/VRM/Runtime/IO/VRMMaterialDescriptorGenerator.cs.meta rename to Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/BuiltInVrmMaterialDescriptorGenerator.cs.meta diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials.meta new file mode 100644 index 000000000..91512b9d1 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5b2cd4b2f3b9486dae1d18ab15041612 +timeCreated: 1667543993 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/VRMMToonMaterialImporter.cs b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmMToonMaterialImporter.cs similarity index 68% rename from Assets/External/VRM/Runtime/IO/VRMMToonMaterialImporter.cs rename to Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmMToonMaterialImporter.cs index 21ce7553d..c855693f9 100644 --- a/Assets/External/VRM/Runtime/IO/VRMMToonMaterialImporter.cs +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmMToonMaterialImporter.cs @@ -1,13 +1,39 @@ using System; using System.Collections.Generic; +using System.Linq; using UniGLTF; using UnityEngine; using VRMShaders; namespace VRM { - public static class VRMMToonMaterialImporter + public static class BuiltInVrmMToonMaterialImporter { + /// + /// 過去バージョンに含まれていたが、廃止・統合された Shader のフォールバック情報 + /// + public static readonly Dictionary FallbackShaders = new Dictionary + { + {"VRM/UnlitTexture", "Unlit/Texture"}, + {"VRM/UnlitTransparent", "Unlit/Transparent"}, + {"VRM/UnlitCutout", "Unlit/Transparent Cutout"}, + {"UniGLTF/StandardVColor", UniGLTF.UniUnlit.UniUnlitUtil.ShaderName}, + }; + + private static readonly string[] MToonTextureSlots = new string[] + { + "_MainTex", + "_ShadeTexture", + "_BumpMap", + "_EmissionMap", + "_OutlineWidthTexture", + "_ReceiveShadowTexture", + "_RimTexture", + "_ShadingGradeTexture", + "_SphereAdd", + "_UvAnimMaskTexture", + }; + public static bool TryCreateParam(GltfData data, glTF_VRM_extensions vrm, int materialIdx, out MaterialDescriptor matDesc) { @@ -36,6 +62,12 @@ namespace VRM // // use material.name, because material name may renamed in GltfParser. var name = data.GLTF.materials[materialIdx].name; + var shaderName = vrmMaterial.shader; + if (FallbackShaders.ContainsKey(shaderName)) + { + shaderName = FallbackShaders[shaderName]; + } + var shader = Shader.Find(shaderName); var textureSlots = new Dictionary(); var floatValues = new Dictionary(); @@ -44,7 +76,7 @@ namespace VRM var actions = new List>(); matDesc = new MaterialDescriptor( name, - vrmMaterial.shader, + shader, vrmMaterial.renderQueue, textureSlots, floatValues, @@ -60,7 +92,10 @@ namespace VRM foreach (var kv in vrmMaterial.vectorProperties) { // vector4 exclude TextureOffsetScale - if (vrmMaterial.textureProperties.ContainsKey(kv.Key)) continue; + if (MToonTextureSlots.Contains(kv.Key)) + { + continue; + } var v = new Vector4(kv.Value[0], kv.Value[1], kv.Value[2], kv.Value[3]); vectors.Add(kv.Key, v); } @@ -68,9 +103,9 @@ namespace VRM foreach (var kv in vrmMaterial.textureProperties) { if (VRMMToonTextureImporter.TryGetTextureFromMaterialProperty(data, vrmMaterial, kv.Key, - out var texture)) + out var key, out var desc)) { - textureSlots.Add(kv.Key, texture.Item2); + textureSlots.Add(kv.Key, desc); } } diff --git a/Assets/External/VRM/Runtime/IO/VRMMToonMaterialImporter.cs.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmMToonMaterialImporter.cs.meta similarity index 100% rename from Assets/External/VRM/Runtime/IO/VRMMToonMaterialImporter.cs.meta rename to Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmMToonMaterialImporter.cs.meta diff --git a/Assets/External/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmUnlitTransparentZWriteMaterialImporter.cs similarity index 96% rename from Assets/External/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs rename to Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmUnlitTransparentZWriteMaterialImporter.cs index 9d8a57780..4efb4533d 100644 --- a/Assets/External/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmUnlitTransparentZWriteMaterialImporter.cs @@ -9,7 +9,7 @@ using RenderMode = MToon.RenderMode; namespace VRM { - public static class VRMUnlitTransparentZWriteMaterialImporter + public static class BuiltInVrmUnlitTransparentZWriteMaterialImporter { public const string UnlitTransparentZWriteShaderName = "VRM/UnlitTransparentZWrite"; public const string UnlitTransparentZWriteMainTexturePropName = "_MainTex"; @@ -48,9 +48,9 @@ namespace VRM if (vrmMaterial.textureProperties.ContainsKey(UnlitTransparentZWriteMainTexturePropName)) { if (VRMMToonTextureImporter.TryGetTextureFromMaterialProperty(data, vrmMaterial, - UnlitTransparentZWriteMainTexturePropName, out var texture)) + UnlitTransparentZWriteMainTexturePropName, out var key, out var desc)) { - textureSlots.Add(MToon.Utils.PropMainTex, texture.Item2); + textureSlots.Add(MToon.Utils.PropMainTex, desc); } } @@ -158,7 +158,10 @@ namespace VRM unityMaterial.renderQueue = vrmMaterial.renderQueue; }); - matDesc = new MaterialDescriptor(name, Utils.ShaderName, null, + matDesc = new MaterialDescriptor( + name, + Shader.Find(Utils.ShaderName), + null, textureSlots, floatValues, colors, diff --git a/Assets/External/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmUnlitTransparentZWriteMaterialImporter.cs.meta similarity index 100% rename from Assets/External/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs.meta rename to Assets/External/VRM/Runtime/IO/MaterialIO/BuiltInRP/Import/Materials/BuiltInVrmUnlitTransparentZWriteMaterialImporter.cs.meta diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/URP.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/URP.meta new file mode 100644 index 000000000..261d8486c --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/URP.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7880e6d28c764ab3be2416dad1018132 +timeCreated: 1667544057 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/URP/Import.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/URP/Import.meta new file mode 100644 index 000000000..b0c58daf7 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/URP/Import.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4233550115504b9287d6c0aee6a5bc4f +timeCreated: 1667544070 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/VRMURPMaterialDescriptorGenerator.cs b/Assets/External/VRM/Runtime/IO/MaterialIO/URP/Import/UrpVrmMaterialDescriptorGenerator.cs similarity index 51% rename from Assets/External/VRM/Runtime/IO/VRMURPMaterialDescriptorGenerator.cs rename to Assets/External/VRM/Runtime/IO/MaterialIO/URP/Import/UrpVrmMaterialDescriptorGenerator.cs index 1ca38753a..ac88061a7 100644 --- a/Assets/External/VRM/Runtime/IO/VRMURPMaterialDescriptorGenerator.cs +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/URP/Import/UrpVrmMaterialDescriptorGenerator.cs @@ -6,28 +6,30 @@ using VRMShaders; namespace VRM { - public sealed class VRMUrpMaterialDescriptorGenerator : IMaterialDescriptorGenerator + public sealed class UrpVrmMaterialDescriptorGenerator : IMaterialDescriptorGenerator { - readonly glTF_VRM_extensions m_vrm; - public VRMUrpMaterialDescriptorGenerator(glTF_VRM_extensions vrm) + private readonly glTF_VRM_extensions _vrm; + + public UrpVrmMaterialDescriptorGenerator(glTF_VRM_extensions vrm) { - m_vrm = vrm; + _vrm = vrm; } public MaterialDescriptor Get(GltfData data, int i) { // mtoon URP "MToon" shader is not ready. import fallback to unlit // unlit "UniUnlit" work in URP - if (GltfUnlitMaterialImporter.TryCreateParam(data, i, out var matDesc)) return matDesc; + if (BuiltInGltfUnlitMaterialImporter.TryCreateParam(data, i, out var matDesc)) return matDesc; // pbr "Standard" to "Universal Render Pipeline/Lit" - if (GltfPbrUrpMaterialImporter.TryCreateParam(data, i, out matDesc)) return matDesc; + if (UrpGltfPbrMaterialImporter.TryCreateParam(data, i, out matDesc)) return matDesc; // fallback -#if VRM_DEVELOP - Debug.LogWarning($"material: {i} out of range. fallback"); -#endif + if (Symbols.VRM_DEVELOP) + { + Debug.LogWarning($"material: {i} out of range. fallback"); + } return new MaterialDescriptor( - GltfMaterialDescriptorGenerator.GetMaterialName(i, null), - GltfPbrMaterialImporter.ShaderName, + GltfMaterialImportUtils.ImportMaterialName(i, null), + UrpGltfPbrMaterialImporter.Shader, null, new Dictionary(), new Dictionary(), @@ -35,5 +37,10 @@ namespace VRM new Dictionary(), new Action[]{}); } + + public MaterialDescriptor GetGltfDefault() + { + return UrpGltfDefaultMaterialImporter.CreateParam(); + } } } diff --git a/Assets/External/VRM/Runtime/IO/VRMURPMaterialDescriptorGenerator.cs.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/URP/Import/UrpVrmMaterialDescriptorGenerator.cs.meta similarity index 100% rename from Assets/External/VRM/Runtime/IO/VRMURPMaterialDescriptorGenerator.cs.meta rename to Assets/External/VRM/Runtime/IO/MaterialIO/URP/Import/UrpVrmMaterialDescriptorGenerator.cs.meta diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/VRMRenderPipelineMaterialDescriptorGeneratorUtility.cs b/Assets/External/VRM/Runtime/IO/MaterialIO/VRMRenderPipelineMaterialDescriptorGeneratorUtility.cs new file mode 100644 index 000000000..cf7b306c3 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/VRMRenderPipelineMaterialDescriptorGeneratorUtility.cs @@ -0,0 +1,21 @@ +using UniGLTF; +using VRM; + +namespace UniVRM +{ + public class VrmRenderPipelineMaterialDescriptorGeneratorDescriptorUtility : RenderPipelineMaterialDescriptorGeneratorUtility + { + public static IMaterialDescriptorGenerator GetValidVrm10MaterialDescriptorGenerator(glTF_VRM_extensions vrm) + { + switch (GetRenderPipelineType()) + { + case RenderPipelineTypes.UniversalRenderPipeline: + return new UrpVrmMaterialDescriptorGenerator(vrm); + case RenderPipelineTypes.BuiltinRenderPipeline: + return new BuiltInVrmMaterialDescriptorGenerator(vrm); + } + + return null; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/MaterialIO/VRMRenderPipelineMaterialDescriptorGeneratorUtility.cs.meta b/Assets/External/VRM/Runtime/IO/MaterialIO/VRMRenderPipelineMaterialDescriptorGeneratorUtility.cs.meta new file mode 100644 index 000000000..8ced90e48 --- /dev/null +++ b/Assets/External/VRM/Runtime/IO/MaterialIO/VRMRenderPipelineMaterialDescriptorGeneratorUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 11d340619a8149cea3dd74a933dc16cc +timeCreated: 1690283540 \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/IO/VRMData.cs b/Assets/External/VRM/Runtime/IO/VRMData.cs index 84e85eb82..763ccde72 100644 --- a/Assets/External/VRM/Runtime/IO/VRMData.cs +++ b/Assets/External/VRM/Runtime/IO/VRMData.cs @@ -16,6 +16,45 @@ namespace VRM throw new NotVrm0Exception(); } VrmExtension = vrm; + + UpdateMigrationFlags(Data.MigrationFlags, VrmExtension.exporterVersion); + } + + private static void UpdateMigrationFlags(MigrationFlags migrationFlags, string exportedVrmVersionString) + { + if (!PackageVersion.ParseVersion(exportedVrmVersionString, out var exportedVrmVersion)) return; + + migrationFlags.IsBaseColorFactorGamma = PackageVersion.IsNewer( + new PackageVersion.Version + { + Major = 0, + Minor = 54, + Patch = 0, + Pre = "", + }, + exportedVrmVersion + ); + + migrationFlags.IsRoughnessTextureValueSquared = PackageVersion.IsNewer( + new PackageVersion.Version + { + Major = 0, + Minor = 69, + Patch = 0, + Pre = "", + }, + exportedVrmVersion + ); + migrationFlags.IsEmissiveFactorGamma = PackageVersion.IsNewer( + new PackageVersion.Version + { + Major = 0, + Minor = 107, + Patch = 0, + Pre = "", + }, + exportedVrmVersion + ); } } } diff --git a/Assets/External/VRM/Runtime/IO/VRMExporter.cs b/Assets/External/VRM/Runtime/IO/VRMExporter.cs index 47178ed03..1cb958b68 100644 --- a/Assets/External/VRM/Runtime/IO/VRMExporter.cs +++ b/Assets/External/VRM/Runtime/IO/VRMExporter.cs @@ -1,10 +1,10 @@ using System; using System.Linq; using UniGLTF; +using UniGLTF.Utils; using UniJSON; using UnityEngine; using VRMShaders; -using ColorSpace = VRMShaders.ColorSpace; namespace VRM { @@ -25,19 +25,25 @@ namespace VRM public readonly VRM.glTF_VRM_extensions VRM = new glTF_VRM_extensions(); - public VRMExporter(ExportingGltfData data, GltfExportSettings exportSettings) : base(data, exportSettings) + public VRMExporter(ExportingGltfData data, GltfExportSettings exportSettings, IAnimationExporter animationExporter = null) : base( + data, exportSettings, animationExporter: animationExporter) { - if (exportSettings == null || exportSettings.InverseAxis != Vrm0xSpecificationInverseAxis) + if (exportSettings == null) { throw new Exception($"VRM specification requires InverseAxis settings as {Vrm0xSpecificationInverseAxis}"); } + if (exportSettings.InverseAxis != Vrm0xSpecificationInverseAxis) + { + // migration 用に reverseX を許す + Debug.LogWarning($"VRM specification requires InverseAxis settings as {Vrm0xSpecificationInverseAxis}"); + } _gltf.extensionsUsed.Add(glTF_VRM_extensions.ExtensionName); } protected override IMaterialExporter CreateMaterialExporter() { - return new VRMMaterialExporter(); + return new BuiltInVrmMaterialExporter(); } public override void ExportExtensions(ITextureSerializer textureSerializer) @@ -71,7 +77,7 @@ namespace VRM { // set humanoid bone mapping var avatar = animator.avatar; - foreach (HumanBodyBones key in Enum.GetValues(typeof(HumanBodyBones))) + foreach (HumanBodyBones key in CachedEnum.GetValues()) { if (key == HumanBodyBones.LastBone) { @@ -81,7 +87,15 @@ namespace VRM var transform = animator.GetBoneTransform(key); if (transform != null) { - VRM.humanoid.SetNodeIndex(key, nodes.IndexOf(transform)); + var nodeIndex = nodes.IndexOf(transform); + if (nodeIndex < 0) + { + Debug.LogError($"ヒューマンボーンが export 対象に含まれていない?", transform); + } + else + { + VRM.humanoid.SetNodeIndex(key, nodeIndex); + } } } } @@ -96,6 +110,10 @@ namespace VRM { foreach (var x in avatar.Clips) { + if (x == null) + { + continue; + } VRM.blendShapeMaster.Add(x, this); } } @@ -206,7 +224,7 @@ namespace VRM // materials foreach (var m in Materials) { - VRM.materialProperties.Add(VRMMaterialExporter.CreateFromMaterial(m, TextureExporter)); + VRM.materialProperties.Add(BuiltInVrmExtensionMaterialPropertyExporter.ExportMaterial(m, TextureExporter)); } // Serialize VRM diff --git a/Assets/External/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/External/VRM/Runtime/IO/VRMImporterContext.cs index 7510d6095..d5e56c82e 100644 --- a/Assets/External/VRM/Runtime/IO/VRMImporterContext.cs +++ b/Assets/External/VRM/Runtime/IO/VRMImporterContext.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Collections.Generic; using UniGLTF; using UnityEngine; -using UniJSON; using System.Threading.Tasks; +using UniGLTF.Utils; using VRMShaders; using Object = UnityEngine.Object; @@ -25,11 +25,13 @@ namespace VRM VRMData data, IReadOnlyDictionary externalObjectMap = null, ITextureDeserializer textureDeserializer = null, - IMaterialDescriptorGenerator materialGenerator = null) - : base(data.Data, externalObjectMap, textureDeserializer, materialGenerator ?? new VRMMaterialDescriptorGenerator(data.VrmExtension)) + IMaterialDescriptorGenerator materialGenerator = null, + bool loadAnimation = false) + : base(data.Data, externalObjectMap, textureDeserializer, materialGenerator ?? new BuiltInVrmMaterialDescriptorGenerator(data.VrmExtension)) { _data = data; TextureDescriptorGenerator = new VrmTextureDescriptorGenerator(Data, VRM); + LoadAnimation = loadAnimation; } #region OnLoad @@ -51,20 +53,20 @@ namespace VRM using (MeasureTime("VRM LoadBlendShapeMaster")) { - LoadBlendShapeMaster(); + await LoadBlendShapeMaster(awaitCaller); } await awaitCaller.NextFrame(); using (MeasureTime("VRM LoadSecondary")) { - VRMSpringUtility.LoadSecondary(Root.transform, Nodes, + VRMSpringUtility.LoadSecondary(Root.transform, TryGetNode, VRM.secondaryAnimation); } await awaitCaller.NextFrame(); using (MeasureTime("VRM LoadFirstPerson")) { - LoadFirstPerson(); + await LoadFirstPerson(awaitCaller); } } @@ -80,9 +82,10 @@ namespace VRM Meta = meta; } - void LoadFirstPerson() + async Task LoadFirstPerson(IAwaitCaller awaitCaller) { var firstPerson = Root.AddComponent(); + await awaitCaller.NextFrameIfTimedOut(); var gltfFirstPerson = VRM.firstPerson; if (gltfFirstPerson.firstPersonBone != -1) @@ -97,13 +100,16 @@ namespace VRM firstPerson.FirstPersonOffset = gltfFirstPerson.firstPersonBoneOffset; } firstPerson.TraverseRenderers(this); + await awaitCaller.NextFrameIfTimedOut(); // LookAt var lookAtHead = Root.AddComponent(); + await awaitCaller.NextFrameIfTimedOut(); lookAtHead.OnImported(this); + await awaitCaller.NextFrameIfTimedOut(); } - void LoadBlendShapeMaster() + async Task LoadBlendShapeMaster(IAwaitCaller awaitCaller) { BlendShapeAvatar = ScriptableObject.CreateInstance(); BlendShapeAvatar.name = "BlendShape"; @@ -113,6 +119,7 @@ namespace VRM { if (transform.GetSharedMesh() != null) { + await awaitCaller.NextFrameIfTimedOut(); transformMeshTable.Add(transform.GetSharedMesh(), transform); } } @@ -122,7 +129,8 @@ namespace VRM { foreach (var x in blendShapeList) { - BlendShapeAvatar.Clips.Add(LoadBlendShapeBind(x, transformMeshTable)); + await awaitCaller.NextFrameIfTimedOut(); + BlendShapeAvatar.Clips.Add(await LoadBlendShapeBind(x, transformMeshTable, awaitCaller)); } } @@ -131,7 +139,7 @@ namespace VRM proxy.BlendShapeAvatar = BlendShapeAvatar; } - BlendShapeClip LoadBlendShapeBind(glTF_VRM_BlendShapeGroup group, Dictionary transformMeshTable) + async Task LoadBlendShapeBind(glTF_VRM_BlendShapeGroup group, Dictionary transformMeshTable, IAwaitCaller awaitCaller) { var asset = ScriptableObject.CreateInstance(); var groupName = group.name; @@ -145,12 +153,12 @@ namespace VRM if (group != null) { asset.BlendShapeName = groupName; - asset.Preset = CacheEnum.TryParseOrDefault(group.presetName, true); + asset.Preset = CachedEnum.ParseOrDefault(group.presetName, true); asset.IsBinary = group.isBinary; if (asset.Preset == BlendShapePreset.Unknown) { // fallback - asset.Preset = CacheEnum.TryParseOrDefault(group.name, true); + asset.Preset = CachedEnum.ParseOrDefault(group.name, true); } asset.Values = group.binds.Select(x => { @@ -165,7 +173,8 @@ namespace VRM }; }) .ToArray(); - asset.MaterialValues = group.materialValues.Select(x => + await awaitCaller.NextFrameIfTimedOut(); + var materialValueBindings = group.materialValues.Select(x => { var value = new Vector4(); for (int i = 0; i < x.targetValue.Length; ++i) @@ -184,7 +193,7 @@ namespace VRM .FirstOrDefault(y => y.name == x.materialName); var propertyName = x.propertyName; if (x.propertyName.FastEndsWith("_ST_S") - || x.propertyName.FastEndsWith("_ST_T")) + || x.propertyName.FastEndsWith("_ST_T")) { propertyName = x.propertyName.Substring(0, x.propertyName.Length - 2); } @@ -210,10 +219,12 @@ namespace VRM } return binding; - }) - .Where(x => x.HasValue) - .Select(x => x.Value) - .ToArray(); + }); + await awaitCaller.NextFrameIfTimedOut(); + asset.MaterialValues = materialValueBindings + .Where(x => x.HasValue) + .Select(x => x.Value) + .ToArray(); } return asset; @@ -299,8 +310,10 @@ namespace VRM meta.Title = gltfMeta.title; if (gltfMeta.texture >= 0) { - var (key, param) = GltfTextureImporter.CreateSrgb(Data, gltfMeta.texture, Vector2.zero, Vector2.one); - meta.Thumbnail = await TextureFactory.GetTextureAsync(param, awaitCaller) as Texture2D; + if (GltfTextureImporter.TryCreateSrgb(Data, gltfMeta.texture, Vector2.zero, Vector2.one, out var key, out var desc)) + { + meta.Thumbnail = await TextureFactory.GetTextureAsync(desc, awaitCaller) as Texture2D; + } } meta.AllowedUser = gltfMeta.allowedUser; meta.ViolentUssage = gltfMeta.violentUssage; @@ -348,23 +361,23 @@ namespace VRM // VRM specific if (HumanoidAvatar != null) { - UnityObjectDestoyer.DestroyRuntimeOrEditor(HumanoidAvatar); + UnityObjectDestroyer.DestroyRuntimeOrEditor(HumanoidAvatar); } if (Meta != null) { - UnityObjectDestoyer.DestroyRuntimeOrEditor(Meta); + UnityObjectDestroyer.DestroyRuntimeOrEditor(Meta); } if (AvatarDescription != null) { - UnityObjectDestoyer.DestroyRuntimeOrEditor(AvatarDescription); + UnityObjectDestroyer.DestroyRuntimeOrEditor(AvatarDescription); } if (BlendShapeAvatar != null) { foreach (var clip in BlendShapeAvatar.Clips) { - UnityObjectDestoyer.DestroyRuntimeOrEditor(clip); + UnityObjectDestroyer.DestroyRuntimeOrEditor(clip); } - UnityObjectDestoyer.DestroyRuntimeOrEditor(BlendShapeAvatar); + UnityObjectDestroyer.DestroyRuntimeOrEditor(BlendShapeAvatar); } base.Dispose(); diff --git a/Assets/External/VRM/Runtime/IO/VRMMToonTextureImporter.cs b/Assets/External/VRM/Runtime/IO/VRMMToonTextureImporter.cs index 52485a320..cdb3f94d7 100644 --- a/Assets/External/VRM/Runtime/IO/VRMMToonTextureImporter.cs +++ b/Assets/External/VRM/Runtime/IO/VRMMToonTextureImporter.cs @@ -12,13 +12,13 @@ namespace VRM var vrmMaterial = vrm.materialProperties[materialIdx]; foreach (var kv in vrmMaterial.textureProperties) { - if (TryGetTextureFromMaterialProperty(data, vrmMaterial, kv.Key, out var texture)) + if (TryGetTextureFromMaterialProperty(data, vrmMaterial, kv.Key, out var key, out var desc)) { - yield return texture; + yield return (key, desc); } } } - public static bool TryGetTextureFromMaterialProperty(GltfData data, glTF_VRM_Material vrmMaterial, string textureKey, out (SubAssetKey, TextureDescriptor) texture) + public static bool TryGetTextureFromMaterialProperty(GltfData data, glTF_VRM_Material vrmMaterial, string textureKey, out SubAssetKey key, out TextureDescriptor desc) { // 任意の shader の import を許容する if (/*vrmMaterial.shader == MToon.Utils.ShaderName &&*/ vrmMaterial.textureProperties.TryGetValue(textureKey, out var textureIdx)) @@ -33,16 +33,14 @@ namespace VRM switch (textureKey) { case MToon.Utils.PropBumpMap: - texture = GltfTextureImporter.CreateNormal(data, textureIdx, offset, scale); - break; + return GltfTextureImporter.TryCreateNormal(data, textureIdx, offset, scale, out key, out desc); default: - texture = GltfTextureImporter.CreateSrgb(data, textureIdx, offset, scale); - break; + return GltfTextureImporter.TryCreateSrgb(data, textureIdx, offset, scale, out key, out desc); } - return true; } - texture = default; + key = default; + desc = default; return false; } diff --git a/Assets/External/VRM/Runtime/IO/VRMMaterialExporter.cs b/Assets/External/VRM/Runtime/IO/VRMMaterialExporter.cs deleted file mode 100644 index bf021f20b..000000000 --- a/Assets/External/VRM/Runtime/IO/VRMMaterialExporter.cs +++ /dev/null @@ -1,238 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UniGLTF; -using UniGLTF.ShaderPropExporter; -using UnityEngine; -using VRMShaders; -using ColorSpace = VRMShaders.ColorSpace; - -namespace VRM -{ - public class VRMMaterialExporter : MaterialExporter - { - public static string VrmMaterialName(string shaderName) - { - switch (shaderName) - { - case "VRM/UnlitTexture": - case "VRM/UnlitTransparent": - case "VRM/UnlitCutout": - case "VRM/UnlitTransparentZWrite": - return "KHR_materials_unlit"; - - case "VRM/MToon": - return "MToon"; - - default: - return null; - } - } - - protected override glTFMaterial CreateMaterial(Material m) - { - switch (m.shader.name) - { - case "VRM/UnlitTexture": - return Export_VRMUnlitTexture(m); - - case "VRM/UnlitTransparent": - return Export_VRMUnlitTransparent(m); - - case "VRM/UnlitCutout": - return Export_VRMUnlitCutout(m); - - case "VRM/UnlitTransparentZWrite": - return Export_VRMUnlitTransparentZWrite(m); - - case "VRM/MToon": - return Export_VRMMToon(m); - - default: - return base.CreateMaterial(m); - } - } - - static glTFMaterial Export_VRMUnlitTexture(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - material.alphaMode = "OPAQUE"; - return material; - } - static glTFMaterial Export_VRMUnlitTransparent(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - material.alphaMode = "BLEND"; - return material; - } - static glTFMaterial Export_VRMUnlitCutout(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - material.alphaMode = "MASK"; - return material; - } - static glTFMaterial Export_VRMUnlitTransparentZWrite(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - material.alphaMode = "BLEND"; - return material; - } - - static glTFMaterial Export_VRMMToon(Material m) - { - var material = glTF_KHR_materials_unlit.CreateDefault(); - - switch (m.GetTag("RenderType", true)) - { - case "Transparent": - material.alphaMode = "BLEND"; - break; - - case "TransparentCutout": - material.alphaMode = "MASK"; - material.alphaCutoff = m.GetFloat("_Cutoff"); - break; - - default: - material.alphaMode = "OPAQUE"; - break; - } - - switch ((int)m.GetFloat("_CullMode")) - { - case 0: - material.doubleSided = true; - break; - - case 1: - Debug.LogWarning("ignore cull front"); - break; - - case 2: - // cull back - break; - - default: - throw new NotImplementedException(); - } - - return material; - } - - #region CreateFromMaterial - - static readonly string[] TAGS = new string[]{ - "RenderType", - // "Queue", - }; - - public static glTF_VRM_Material CreateFromMaterial(Material m, ITextureExporter textureExporter) - { - var material = new glTF_VRM_Material - { - name = m.name, - shader = m.shader.name, - renderQueue = m.renderQueue, - }; - - if (!PreShaderPropExporter.VRMExtensionShaders.Contains(m.shader.name)) - { - material.shader = glTF_VRM_Material.VRM_USE_GLTFSHADER; - return material; - } - - var prop = PreShaderPropExporter.GetPropsForSupportedShader(m.shader.name); - if (prop == null) - { - Debug.LogWarningFormat("Fail to export shader: {0}", m.shader.name); - } - else - { - foreach (var keyword in m.shaderKeywords) - { - material.keywordMap.Add(keyword, m.IsKeywordEnabled(keyword)); - } - - // get properties - //material.SetProp(prop); - foreach (var kv in prop.Properties) - { - switch (kv.ShaderPropertyType) - { - case ShaderPropertyType.Color: - { - // No color conversion. Because color property is serialized to raw float array. - var value = m.GetColor(kv.Key).ToFloat4(ColorSpace.Linear, ColorSpace.Linear); - material.vectorProperties.Add(kv.Key, value); - } - break; - - case ShaderPropertyType.Range: - case ShaderPropertyType.Float: - { - var value = m.GetFloat(kv.Key); - material.floatProperties.Add(kv.Key, value); - } - break; - - case ShaderPropertyType.TexEnv: - { - var texture = m.GetTexture(kv.Key); - if (texture != null) - { - var value = -1; - var isNormalMap = kv.Key == "_BumpMap"; - if (isNormalMap) - { - value = textureExporter.RegisterExportingAsNormal(texture); - } - else - { - var needsAlpha = kv.Key == "_MainTex"; - value = textureExporter.RegisterExportingAsSRgb(texture, needsAlpha); - } - if (value == -1) - { - Debug.LogFormat("not found {0}", texture.name); - } - else - { - material.textureProperties.Add(kv.Key, value); - } - } - - // offset & scaling - var offset = m.GetTextureOffset(kv.Key); - var scaling = m.GetTextureScale(kv.Key); - material.vectorProperties.Add(kv.Key, - new float[] { offset.x, offset.y, scaling.x, scaling.y }); - } - break; - - case ShaderPropertyType.Vector: - { - var value = m.GetVector(kv.Key).ToArray(); - material.vectorProperties.Add(kv.Key, value); - } - break; - - default: - throw new NotImplementedException(); - } - } - } - - foreach (var tag in TAGS) - { - var value = m.GetTag(tag, false); - if (!String.IsNullOrEmpty(value)) - { - material.tagMap.Add(tag, value); - } - } - - return material; - } - #endregion - } -} diff --git a/Assets/External/VRM/Runtime/IO/VrmTextureDescriptorGenerator.cs b/Assets/External/VRM/Runtime/IO/VrmTextureDescriptorGenerator.cs index 047d866cb..8a02a9bc0 100644 --- a/Assets/External/VRM/Runtime/IO/VrmTextureDescriptorGenerator.cs +++ b/Assets/External/VRM/Runtime/IO/VrmTextureDescriptorGenerator.cs @@ -59,21 +59,21 @@ namespace VRM } // Thumbnail - if (TryGetThumbnailTexture(data, vrm, out var thumbnail)) + if (TryGetThumbnailTexture(data, vrm, out var key, out var desc)) { - yield return thumbnail; + yield return (key, desc); } } - private static bool TryGetThumbnailTexture(GltfData data, glTF_VRM_extensions vrm, out (SubAssetKey, TextureDescriptor) texture) + private static bool TryGetThumbnailTexture(GltfData data, glTF_VRM_extensions vrm, out SubAssetKey key, out TextureDescriptor desc) { if (vrm.meta.texture > -1) { - texture = GltfTextureImporter.CreateSrgb(data, vrm.meta.texture, Vector2.zero, Vector2.one); - return true; + return GltfTextureImporter.TryCreateSrgb(data, vrm.meta.texture, Vector2.zero, Vector2.one, out key, out desc); } - texture = default; + key = default; + desc = default; return false; } } diff --git a/Assets/External/VRM/Runtime/IO/VrmUtility.cs b/Assets/External/VRM/Runtime/IO/VrmUtility.cs index 22f2db8d5..19d320b26 100644 --- a/Assets/External/VRM/Runtime/IO/VrmUtility.cs +++ b/Assets/External/VRM/Runtime/IO/VrmUtility.cs @@ -14,7 +14,9 @@ namespace VRM public static async Task LoadAsync(string path, IAwaitCaller awaitCaller = null, MaterialGeneratorCallback materialGeneratorCallback = null, - MetaCallback metaCallback = null + MetaCallback metaCallback = null, + ITextureDeserializer textureDeserializer = null, + bool loadAnimation = false ) { if (!File.Exists(path)) @@ -38,7 +40,68 @@ namespace VRM { materialGen = materialGeneratorCallback(vrm.VrmExtension); } - using (var loader = new VRMImporterContext(vrm, materialGenerator: materialGen)) + using (var loader = new VRMImporterContext( + vrm, + textureDeserializer: textureDeserializer, + materialGenerator: materialGen, + loadAnimation: loadAnimation)) + { + if (metaCallback != null) + { + var meta = await loader.ReadMetaAsync(awaitCaller, true); + metaCallback(meta); + } + return await loader.LoadAsync(awaitCaller); + } + } + catch (NotVrm0Exception) + { + // retry + Debug.LogWarning("file extension is vrm. but not vrm ?"); + using (var loader = new UniGLTF.ImporterContext(data)) + { + return await loader.LoadAsync(awaitCaller); + } + } + } + } + + + public static async Task LoadBytesAsync(string path, + byte[] bytes, + IAwaitCaller awaitCaller = null, + MaterialGeneratorCallback materialGeneratorCallback = null, + MetaCallback metaCallback = null, + ITextureDeserializer textureDeserializer = null, + bool loadAnimation = false + ) + { + if (bytes == null) + { + throw new ArgumentNullException("bytes"); + } + + if (awaitCaller == null) + { + Debug.LogWarning("VrmUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller."); + awaitCaller = new ImmediateCaller(); + } + + using (GltfData data = new GlbBinaryParser(bytes, path).Parse()) + { + try + { + var vrm = new VRMData(data); + IMaterialDescriptorGenerator materialGen = default; + if (materialGeneratorCallback != null) + { + materialGen = materialGeneratorCallback(vrm.VrmExtension); + } + using (var loader = new VRMImporterContext( + vrm, + textureDeserializer: textureDeserializer, + materialGenerator: materialGen, + loadAnimation: loadAnimation)) { if (metaCallback != null) { diff --git a/Assets/External/VRM/Runtime/Meta/VRMMetaObject.cs b/Assets/External/VRM/Runtime/Meta/VRMMetaObject.cs index 2e5848488..ffbf76c30 100644 --- a/Assets/External/VRM/Runtime/Meta/VRMMetaObject.cs +++ b/Assets/External/VRM/Runtime/Meta/VRMMetaObject.cs @@ -5,6 +5,7 @@ using UnityEngine; namespace VRM { + [CreateAssetMenu(menuName = "VRM/MetaObject")] public class VRMMetaObject : ScriptableObject { [SerializeField] diff --git a/Assets/External/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs b/Assets/External/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs index 8d9154692..f7b19239d 100644 --- a/Assets/External/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs +++ b/Assets/External/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using UniGLTF; using UniGLTF.MeshUtility; +using UniGLTF.Utils; using UniHumanoid; using UnityEngine; @@ -39,17 +41,26 @@ namespace VRM /// /// モデルの正規化を実行する + /// + /// v0.115 ヒエラルキーのコピーをしなくまりました(仕様変更) + /// v0.116 Animator.avatar 代入の副作用回避修正 + /// + /// v0.114以前: 非破壊 + /// - return コピーされて正規化されたヒエラルキー + /// v0.115以降: 対象のヒエラルキーが正規化されます。 + /// - Transform が変更されます。 + /// - Animator.avatar が差し替えられます。 + /// - SkinnedMeshRenderer.sharedMesh が差し替えられます。 + /// - MeshFilter.sharedMesh が差し替えられます。 + /// - return void /// /// 対象モデルのルート /// 強制的にT-Pose化するか - /// 正規化済みのモデル - public static GameObject Execute(GameObject go, bool forceTPose) + public static void Execute(GameObject go, bool forceTPose) { - // - // T-Poseにする - // if (forceTPose) { + // T-Poseにする var hips = go.GetComponent().GetBoneTransform(HumanBodyBones.Hips); var hipsPosition = hips.position; var hipsRotation = hips.rotation; @@ -64,51 +75,31 @@ namespace VRM } } - // - // 正規化されたヒエラルキーを作る - // - var (normalized, bMap) = BoneNormalizer.Execute(go, (_src, dst, boneMap) => + // Transform の回転とスケールを Mesh に適用します。 + // - BlendShape は現状がbakeされます + // - 回転とスケールが反映された新しい Mesh が作成されます + // - Transform の回転とスケールはクリアされます。world position を維持します + var newMeshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); + + // SkinnedMeshRenderer.sharedMesh と MeshFilter.sharedMesh を新しいMeshで置き換える + BoneNormalizer.Replace(go, newMeshMap, true, true); + + // 回転とスケールが除去された新しいヒエラルキーからAvatarを作る + var animator = go.GetComponent(); + var newAvatar = UniHumanoid.AvatarDescription.RecreateAvatar(animator); + + // Animator.avatar を代入したときに副作用でTransformが変更されるのを回避するために削除します。 + if (Application.isPlaying) { - var src = _src.GetComponent(); + GameObject.Destroy(animator); + } + else + { + GameObject.DestroyImmediate(animator); + } + animator = go.AddComponent(); - var srcHumanBones = Enum.GetValues(typeof(HumanBodyBones)) - .Cast() - .Where(x => x != HumanBodyBones.LastBone) - .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) - .Where(x => x.Value != null) - ; - - var map = - srcHumanBones - .Where(x => boneMap.ContainsKey(x.Value)) - .ToDictionary(x => x.Key, x => boneMap[x.Value]) - ; - - if (dst.GetComponent() == null) - { - var animator = dst.AddComponent(); - } - var vrmHuman = go.GetComponent(); - var avatarDescription = AvatarDescription.Create(); - if (vrmHuman != null && vrmHuman.Description != null) - { - avatarDescription.armStretch = vrmHuman.Description.armStretch; - avatarDescription.legStretch = vrmHuman.Description.legStretch; - avatarDescription.upperArmTwist = vrmHuman.Description.upperArmTwist; - avatarDescription.lowerArmTwist = vrmHuman.Description.lowerArmTwist; - avatarDescription.upperLegTwist = vrmHuman.Description.upperLegTwist; - avatarDescription.lowerLegTwist = vrmHuman.Description.lowerLegTwist; - avatarDescription.feetSpacing = vrmHuman.Description.feetSpacing; - avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF; - } - avatarDescription.SetHumanBones(map); - var avatar = avatarDescription.CreateAvatar(dst.transform); - return avatar; - }); - - CopyVRMComponents(go, normalized, bMap); - - return normalized; + animator.avatar = newAvatar; } /// diff --git a/Assets/External/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/External/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs new file mode 100644 index 000000000..49c8d020d --- /dev/null +++ b/Assets/External/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniHumanoid; +using UnityEngine; +using UnityEngine.XR; + + +namespace VRM +{ + public class VrmMeshUtility : UniGLTF.MeshUtility.GltfMeshUtility + { + bool _generateFirstPerson = false; + public override IEnumerable CopyInstantiate(GameObject go, GameObject instance) + { + _generateFirstPerson = false; + + var copy = base.CopyInstantiate(go, instance); + if (GenerateMeshForFirstPersonAuto) + { + foreach (var g in copy) + { + if (g.Name == "auto") + { + _generateFirstPerson = true; + // 元のメッシュを三人称に変更 + yield return new UniGLTF.MeshUtility.MeshIntegrationGroup + { + Name = FirstPersonFlag.ThirdPersonOnly.ToString(), + IntegrationType = UniGLTF.MeshUtility.MeshIntegrationGroup.MeshIntegrationTypes.ThirdPersonOnly, + Renderers = g.Renderers.ToList(), + }; + } + yield return g; + } + } + else + { + foreach (var g in copy) + { + yield return g; + } + } + } + + protected override bool + TryIntegrate( + GameObject empty, + UniGLTF.MeshUtility.MeshIntegrationGroup group, + out (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) resultAndAdded) + { + if (!base.TryIntegrate(empty, group, out resultAndAdded)) + { + resultAndAdded = default; + return false; + } + + var (result, newGo) = resultAndAdded; + if (_generateFirstPerson && group.Name == nameof(FirstPersonFlag.Auto)) + { + // Mesh 統合の後処理 + // FirstPerson == "auto" の場合に + // 頭部の無いモデルを追加で作成する + Debug.Log("generateFirstPerson"); + if (result.Integrated.Mesh != null) + { + // BlendShape 有り + _ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.Integrated.IntegratedRenderer); + } + if (result.IntegratedNoBlendShape.Mesh != null) + { + // BlendShape 無しの方 + _ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.IntegratedNoBlendShape.IntegratedRenderer); + } + } + return true; + } + + private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + var mesh = _vrmInstance.ProcessFirstPerson(firstPersonBone, smr); + if (mesh != null) + { + smr.sharedMesh = mesh; + smr.name = "auto.headless"; + } + else + { + Debug.LogWarning("no result"); + } + } + + VRMFirstPerson _vrmInstance = null; + /// + /// glTF に比べて Humanoid や FirstPerson の処理が追加される + /// + public override (List, List) Process( + GameObject target, IEnumerable copyGroup) + { + _vrmInstance = target.GetComponent(); + if (_vrmInstance == null) + { + throw new ArgumentException(); + } + + // TODO: update: spring + // TODO: update: constraint + // TODO: update: firstPerson offset + var (list, newList) = base.Process(target, copyGroup); + + if (FreezeBlendShapeRotationAndScaling) + { + var animator = target.GetComponent(); + var newAvatar = AvatarDescription.RecreateAvatar(animator); + + // ??? clear old avatar ??? + var t = animator.gameObject; + if (Application.isPlaying) + { + GameObject.Destroy(animator); + } + else + { + GameObject.DestroyImmediate(animator); + } + + t.AddComponent().avatar = newAvatar; + } + + return (list, newList); + } + + public override void UpdateMeshIntegrationGroups(GameObject root) + { + MeshIntegrationGroups.Clear(); + if (root == null) + { + return; + } + var vrm0 = root.GetComponent(); + if (vrm0 == null) + { + return; + } + foreach (var a in vrm0.Renderers) + { + var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString()); + g.Renderers.Add(a.Renderer); + } + + var orphan = root.GetComponentsInChildren().Where(x => !_HasRenderer(x)).ToArray(); + if (orphan.Length > 0) + { + var g = _GetOrCreateGroup("both"); + g.Renderers.AddRange(orphan); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta b/Assets/External/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta new file mode 100644 index 000000000..851cb3e0c --- /dev/null +++ b/Assets/External/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb346da8b7688c74eb627bebe1b21060 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM/Runtime/SpringBone/VRMSpringBone.cs b/Assets/External/VRM/Runtime/SpringBone/VRMSpringBone.cs index e505b8914..5e9d8c7d0 100644 --- a/Assets/External/VRM/Runtime/SpringBone/VRMSpringBone.cs +++ b/Assets/External/VRM/Runtime/SpringBone/VRMSpringBone.cs @@ -19,15 +19,13 @@ namespace VRM [SerializeField] private Color m_gizmoColor = Color.yellow; [SerializeField] - [Range(0, 4)] - [Header("Settings")] public float m_stiffnessForce = 1.0f; - [SerializeField] [Range(0, 2)] public float m_gravityPower; + [SerializeField] public float m_gravityPower; [SerializeField] public Vector3 m_gravityDir = new Vector3(0, -1.0f, 0); - [SerializeField] [Range(0, 1)] public float m_dragForce = 0.4f; + [SerializeField][Range(0, 1)] public float m_dragForce = 0.4f; [SerializeField] public Transform m_center; @@ -35,8 +33,6 @@ namespace VRM Dictionary m_initialLocalRotationMap; [SerializeField] - [Range(0, 0.5f)] - [Header("Collider")] public float m_hitRadius = 0.02f; [SerializeField] @@ -46,6 +42,7 @@ namespace VRM { LateUpdate, FixedUpdate, + Manual, } [SerializeField] public SpringBoneUpdateType m_updateType = SpringBoneUpdateType.LateUpdate; @@ -263,6 +260,15 @@ namespace VRM } } + public void ManualUpdate(float deltaTime) + { + if (m_updateType != SpringBoneUpdateType.Manual) + { + throw new System.ArgumentException("require SpringBoneUpdateType.Manual"); + } + UpdateProcess(deltaTime); + } + public struct SphereCollider { // public Transform Transform; diff --git a/Assets/External/VRM/Runtime/SpringBone/VRMSpringUtility.cs b/Assets/External/VRM/Runtime/SpringBone/VRMSpringUtility.cs index 9ed6d1a93..634d43ebe 100644 --- a/Assets/External/VRM/Runtime/SpringBone/VRMSpringUtility.cs +++ b/Assets/External/VRM/Runtime/SpringBone/VRMSpringUtility.cs @@ -21,13 +21,17 @@ namespace VRM .Select(x => x.GetComponent()) .Where(x => x != null)) { - colliders.Add(vrmColliderGroup); + var index = nodes.IndexOf(vrmColliderGroup.transform); + if (index == -1) + { + continue; + } + colliders.Add(vrmColliderGroup); var colliderGroup = new glTF_VRM_SecondaryAnimationColliderGroup { - node = nodes.IndexOf(vrmColliderGroup.transform) + node = index }; - colliderGroup.colliders = vrmColliderGroup.Colliders.Select(x => { return new glTF_VRM_SecondaryAnimationCollider @@ -62,7 +66,12 @@ namespace VRM } } - public static void LoadSecondary(Transform root, List nodes, + /// + /// Node getter. If not found, Never throw, return false. + /// + public delegate bool TryGetNode(int index, out Transform transform); + + public static void LoadSecondary(Transform root, TryGetNode tryGetNode, glTF_VRM_SecondaryAnimation secondaryAnimation) { var secondary = root.Find("secondary"); @@ -108,20 +117,27 @@ namespace VRM } } - //var secondaryAnimation = context.VRM.extensions.VRM.secondaryAnimation; var colliders = new List(); foreach (var colliderGroup in secondaryAnimation.colliderGroups) { - var vrmGroup = nodes[colliderGroup.node].gameObject.AddComponent(); - vrmGroup.Colliders = colliderGroup.colliders.Select(x => + if (tryGetNode(colliderGroup.node, out var node)) { - return new VRMSpringBoneColliderGroup.SphereCollider + var vrmGroup = node.gameObject.AddComponent(); + vrmGroup.Colliders = colliderGroup.colliders.Select(x => { - Offset = x.offset, - Radius = x.radius - }; - }).ToArray(); - colliders.Add(vrmGroup); + return new VRMSpringBoneColliderGroup.SphereCollider + { + Offset = x.offset, + Radius = x.radius + }; + }).ToArray(); + colliders.Add(vrmGroup); + } + else + { + Debug.LogError("Broken collider group"); + break; + } } if (secondaryAnimation.boneGroups.Count > 0) @@ -129,9 +145,9 @@ namespace VRM foreach (var boneGroup in secondaryAnimation.boneGroups) { var vrmBoneGroup = secondary.gameObject.AddComponent(); - if (boneGroup.center != -1) + if (boneGroup.center != -1 && tryGetNode(boneGroup.center, out var node)) { - vrmBoneGroup.m_center = nodes[boneGroup.center]; + vrmBoneGroup.m_center = node; } vrmBoneGroup.m_comment = boneGroup.comment; @@ -147,14 +163,20 @@ namespace VRM for (int i = 0; i < boneGroup.colliderGroups.Length; ++i) { var colliderGroup = boneGroup.colliderGroups[i]; - vrmBoneGroup.ColliderGroups[i] = colliders[colliderGroup]; + if (colliderGroup >= 0 && colliderGroup < colliders.Count) + { + vrmBoneGroup.ColliderGroups[i] = colliders[colliderGroup]; + } } } var boneList = new List(); foreach (var x in boneGroup.bones) { - boneList.Add(nodes[x]); + if (tryGetNode(x, out var boneNode)) + { + boneList.Add(boneNode); + } } vrmBoneGroup.RootBones = boneList; diff --git a/Assets/External/VRM/Runtime/VRM.asmdef b/Assets/External/VRM/Runtime/VRM.asmdef index c89f8bc23..e18ce1e85 100644 --- a/Assets/External/VRM/Runtime/VRM.asmdef +++ b/Assets/External/VRM/Runtime/VRM.asmdef @@ -1,12 +1,15 @@ { "name": "VRM", + "rootNamespace": "", "references": [ "GUID:b7aa47b240b57de44a4b2021c143c9bf", "GUID:8d76e605759c3f64a957d63ef96ada7c", "GUID:da3e51d19d51a544fa14d43fee843098", "GUID:301b251fd9834274c9228e0532f444f7", "GUID:a9bc101fb0471f94a8f99fd242fdd934", - "GUID:ac229b552c3025545b074203f857547c" + "GUID:ac229b552c3025545b074203f857547c", + "GUID:1cd941934d098654fa21a13f28346412", + "GUID:60c8346e00a8ddd4cafc5a02eceeec57" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/External/VRM/Tests/InvalidFileNameTest.cs b/Assets/External/VRM/Tests/InvalidFileNameTest.cs index 935bb0a41..26741209e 100644 --- a/Assets/External/VRM/Tests/InvalidFileNameTest.cs +++ b/Assets/External/VRM/Tests/InvalidFileNameTest.cs @@ -1,6 +1,5 @@ using NUnit.Framework; using System.Linq; -using System.IO; using UniGLTF; namespace VRM @@ -31,19 +30,5 @@ namespace VRM var result = fileName.Any(x => char.IsControl(x)); Assert.AreEqual(result, isIllegal); } - - [Test] - [TestCase("VRM|Alicia?VRM", true)] - [TestCase("UniVRMUniVRM:UniVRM", true)] - [TestCase("VRMIsVRFileFormat", false)] - [TestCase("AliciaAlicia", true)] - [TestCase("UniVRMIsVRMImplementationInUnityPlatform", false)] - [TestCase("Avator*Avator/Avator", true)] - public void DetectInvalidCharacters(string fileName, bool isIllegal) - { - char[] invalidPathChars = Path.GetInvalidFileNameChars(); - var result = fileName.Any(x => invalidPathChars.Contains(x)); - Assert.AreEqual(result, isIllegal); - } } } diff --git a/Assets/External/VRM/Tests/MToonTest.cs b/Assets/External/VRM/Tests/MToonTest.cs index dd4eec418..c9d91a63c 100644 --- a/Assets/External/VRM/Tests/MToonTest.cs +++ b/Assets/External/VRM/Tests/MToonTest.cs @@ -28,11 +28,10 @@ namespace VRM srcMaterial.mainTextureOffset = offset; srcMaterial.mainTextureScale = scale; - var materialExporter = new VRMMaterialExporter(); - var vrmMaterial = VRMMaterialExporter.CreateFromMaterial(srcMaterial, textureExporter); + var vrmMaterial = BuiltInVrmExtensionMaterialPropertyExporter.ExportMaterial(srcMaterial, textureExporter); Assert.AreEqual(vrmMaterial.vectorProperties["_MainTex"], new float[] { 0.3f, 0.2f, 0.5f, 0.6f }); - var materialImporter = new VRMMaterialDescriptorGenerator(new glTF_VRM_extensions + var materialImporter = new BuiltInVrmMaterialDescriptorGenerator(new glTF_VRM_extensions { materialProperties = new System.Collections.Generic.List { vrmMaterial } }); @@ -52,7 +51,7 @@ namespace VRM var importer = new VRMImporterContext(vrm, null); Assert.AreEqual(73, vrm.Data.GLTF.materials.Count); - Assert.True(VRMMToonMaterialImporter.TryCreateParam(vrm.Data, importer.VRM, 0, out MaterialDescriptor matDesc)); + Assert.True(BuiltInVrmMToonMaterialImporter.TryCreateParam(vrm.Data, importer.VRM, 0, out MaterialDescriptor matDesc)); } } @@ -72,8 +71,8 @@ namespace VRM using (var data = new GlbFileParser(path).Parse()) { var vrmImporter = new VRMImporterContext(new VRMData(data), null); - var materialParam = new VRMMaterialDescriptorGenerator(vrmImporter.VRM).Get(data, 0); - Assert.AreEqual("VRM/MToon", materialParam.ShaderName); + var materialParam = new BuiltInVrmMaterialDescriptorGenerator(vrmImporter.VRM).Get(data, 0); + Assert.AreEqual("VRM/MToon", materialParam.Shader.name); Assert.AreEqual("Alicia_body", materialParam.TextureSlots["_MainTex"].UnityObjectName); var (key, value) = materialParam.EnumerateSubAssetKeyValue().First(); diff --git a/Assets/External/VRM/Tests/NormalizeTests.cs b/Assets/External/VRM/Tests/NormalizeTests.cs index ea8bd0e42..e683af574 100644 --- a/Assets/External/VRM/Tests/NormalizeTests.cs +++ b/Assets/External/VRM/Tests/NormalizeTests.cs @@ -59,7 +59,7 @@ namespace VRM map.Add(null, new GameObject("null")); // map.Add(new GameObject("c"), null); // ありえないので Exception にしてある var boneWeights = map.CreateBoneWeight(64).ToArray(); - var newBoneWeight = BoneNormalizer.MapBoneWeight(boneWeights, map.Map, + var newBoneWeight = MeshFreezer.MapBoneWeight(boneWeights, map.Map, map.SrcBones.ToArray(), map.DstBones.ToArray()); // 正常系 @@ -75,7 +75,7 @@ namespace VRM map.Add(null, new GameObject("null")); // map.Add(new GameObject("c"), null); // ありえないので Exception にしてある var boneWeights = map.CreateBoneWeight(64).ToArray(); - var newBoneWeight = BoneNormalizer.MapBoneWeight(boneWeights, map.Map, + var newBoneWeight = MeshFreezer.MapBoneWeight(boneWeights, map.Map, map.SrcBones.ToArray(), map.DstBones.ToArray()); // 4 つめが 0 になる diff --git a/Assets/External/VRM/Tests/SampleTests/VRMImportExportTests.cs b/Assets/External/VRM/Tests/SampleTests/VRMImportExportTests.cs index 3b57264ba..fae94b210 100644 --- a/Assets/External/VRM/Tests/SampleTests/VRMImportExportTests.cs +++ b/Assets/External/VRM/Tests/SampleTests/VRMImportExportTests.cs @@ -11,15 +11,6 @@ namespace VRM.Samples { public static class JsonExtensions { - public static void SetValue(this JsonNode node, string key, T value, Action serialize) - { - var f = new JsonFormatter(); - serialize(f, value); - var p = Utf8String.From(key); - var bytes = f.GetStoreBytes(); - node.SetValue(p, bytes); - } - public static string ToJson(this glTF self) { var f = new JsonFormatter(); @@ -122,67 +113,13 @@ namespace VRM.Samples { var gltfBlendShapeClip = context.VRM.blendShapeMaster.blendShapeGroups[i]; var unityBlendShapeClip = blendshapeProxy.BlendShapeAvatar.Clips[i]; + if (unityBlendShapeClip == null) + { + continue; + } Assert.AreEqual(Enum.Parse(typeof(BlendShapePreset), gltfBlendShapeClip.presetName, true), unityBlendShapeClip.Preset); } } - - var importedJson = JsonParser.Parse(context.Json); - importedJson.SetValue("/extensions/VRM/exporterVersion", VRMVersion.VRM_VERSION, (f, x) => f.Value(x)); - importedJson.SetValue("/asset/generator", UniGLTF.UniGLTFVersion.UNIGLTF_VERSION, (f, x) => f.Value(x)); - importedJson.SetValue("/scene", 0, (f, x) => f.Value(x)); - importedJson.SetValue("/materials/*/doubleSided", false, (f, x) => f.Value(x)); - //importJson.SetValue("/materials/*/pbrMetallicRoughness/roughnessFactor", 0); - //importJson.SetValue("/materials/*/pbrMetallicRoughness/baseColorFactor", new float[] { 1, 1, 1, 1 }); - importedJson.SetValue("/accessors/*/normalized", false, (f, x) => f.Value(x)); - importedJson.RemoveValue(Utf8String.From("/nodes/*/extras")); - /* - importJson.SetValue("/bufferViews/12/byteStride", 4); - importJson.SetValue("/bufferViews/13/byteStride", 4); - importJson.SetValue("/bufferViews/14/byteStride", 4); - importJson.SetValue("/bufferViews/15/byteStride", 4); - importJson.SetValue("/bufferViews/22/byteStride", 4); - importJson.SetValue("/bufferViews/29/byteStride", 4); - importJson.SetValue("/bufferViews/45/byteStride", 4); - importJson.SetValue("/bufferViews/46/byteStride", 4); - importJson.SetValue("/bufferViews/47/byteStride", 4); - importJson.SetValue("/bufferViews/201/byteStride", 4); - importJson.SetValue("/bufferViews/202/byteStride", 4); - importJson.SetValue("/bufferViews/203/byteStride", 4); - importJson.SetValue("/bufferViews/204/byteStride", 4); - importJson.SetValue("/bufferViews/211/byteStride", 4); - importJson.SetValue("/bufferViews/212/byteStride", 4); - importJson.SetValue("/bufferViews/213/byteStride", 4); - importJson.SetValue("/bufferViews/214/byteStride", 4); - importJson.SetValue("/bufferViews/215/byteStride", 4); - importJson.SetValue("/bufferViews/243/byteStride", 4); - importJson.SetValue("/bufferViews/247/byteStride", 64); - importJson.SetValue("/bufferViews/248/byteStride", 64); - importJson.SetValue("/bufferViews/249/byteStride", 64); - importJson.SetValue("/bufferViews/250/byteStride", 64); - importJson.SetValue("/bufferViews/251/byteStride", 64); - importJson.SetValue("/bufferViews/252/byteStride", 64); - importJson.SetValue("/bufferViews/253/byteStride", 64); - */ - importedJson.RemoveValue(Utf8String.From("/bufferViews/*/byteStride")); - - var vrm = VRMExporter.Export(new GltfExportSettings(), loaded.gameObject, new EditorTextureSerializer()); - - // TODO: Check contents in JSON - /*var exportJson = */ - JsonParser.Parse(vrm.Gltf.ToJson()); - - // TODO: Check contents in JSON - /*var newExportedJson = */ - // JsonParser.Parse(JsonSchema.FromType().Serialize(vrm)); - - /* - foreach (var kv in importJson.Diff(exportJson)) - { - Debug.Log(kv); - } - - Assert.AreEqual(importJson, exportJson); - */ } } diff --git a/Assets/External/VRM/Tests/SampleTests/VRMMaterialTests.cs b/Assets/External/VRM/Tests/SampleTests/VRMMaterialTests.cs index e79f78d3a..08071b284 100644 --- a/Assets/External/VRM/Tests/SampleTests/VRMMaterialTests.cs +++ b/Assets/External/VRM/Tests/SampleTests/VRMMaterialTests.cs @@ -10,7 +10,7 @@ namespace VRM.Samples static UniGLTF.glTFMaterial ExportLoaded(string resourceName) { var material = Resources.Load(resourceName); - var exporter = new VRMMaterialExporter(); + var exporter = new BuiltInVrmMaterialExporter(); var textureExporter = new TextureExporter(new EditorTextureSerializer()); var exported = exporter.ExportMaterial(material, textureExporter, new GltfExportSettings()); diff --git a/Assets/External/VRM/Tests/VRMLookAtTests.cs b/Assets/External/VRM/Tests/VRMLookAtTests.cs index 95c197326..a9a07b4a3 100644 --- a/Assets/External/VRM/Tests/VRMLookAtTests.cs +++ b/Assets/External/VRM/Tests/VRMLookAtTests.cs @@ -1,4 +1,5 @@ +using System; using System.IO; using NUnit.Framework; using UniGLTF; @@ -32,11 +33,10 @@ namespace VRM var fp = go.GetComponent(); GameObject.DestroyImmediate(go.GetComponent()); var lookAt = go.AddComponent(); - bytes = VRMEditorExporter.Export(go, null, new VRMExportSettings - { - PoseFreeze = true, - }); - } + var settings = (VRMExportSettings)ScriptableObject.CreateInstance(); + settings.PoseFreeze = true; + bytes = VRMEditorExporter.Export(go, null, settings); + } using (var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse()) using (var loader2 = new VRMImporterContext(new VRMData(data2))) @@ -61,10 +61,9 @@ namespace VRM var fp = go.GetComponent(); var lookAt = go.GetComponent(); horizontalInner = lookAt.HorizontalInner; - bytes = VRMEditorExporter.Export(go, null, new VRMExportSettings - { - PoseFreeze = true, - }); + var settings = ScriptableObject.CreateInstance(); + settings.PoseFreeze = true; + bytes = VRMEditorExporter.Export(go, null, settings); } using (var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse()) @@ -95,10 +94,9 @@ namespace VRM var fp = go.GetComponent(); var lookAt = go.GetComponent(); horizontalInner = lookAt.HorizontalInner; - bytes = VRMEditorExporter.Export(go, null, new VRMExportSettings - { - PoseFreeze = false, - }); + var settings = (VRMExportSettings)ScriptableObject.CreateInstance(); + settings.PoseFreeze = false; + bytes = VRMEditorExporter.Export(go, null, settings); } using (var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse()) diff --git a/Assets/External/VRM/Tests/VRMTextureEnumerateTests.cs b/Assets/External/VRM/Tests/VRMTextureEnumerateTests.cs index 9ae342c83..29c292d45 100644 --- a/Assets/External/VRM/Tests/VRMTextureEnumerateTests.cs +++ b/Assets/External/VRM/Tests/VRMTextureEnumerateTests.cs @@ -59,7 +59,7 @@ namespace VRM }, } }, - default + new ArraySegment(Array.Empty()) )) { var vrm = new glTF_VRM_extensions @@ -122,7 +122,7 @@ namespace VRM }, } }, - default + new ArraySegment(Array.Empty()) )) { var vrm = new glTF_VRM_extensions @@ -141,7 +141,7 @@ namespace VRM }; // 2系統ある? - Assert.IsTrue(VRMMToonMaterialImporter.TryCreateParam(data, vrm, 0, out VRMShaders.MaterialDescriptor matDesc)); + Assert.IsTrue(BuiltInVrmMToonMaterialImporter.TryCreateParam(data, vrm, 0, out VRMShaders.MaterialDescriptor matDesc)); Assert.AreEqual(1, matDesc.TextureSlots.Count); var items = new VrmTextureDescriptorGenerator(data, vrm).Get().GetEnumerable().ToArray(); diff --git a/Assets/External/VRM/Tests/VersionTests.cs b/Assets/External/VRM/Tests/VersionTests.cs index db40493cc..a55a5331b 100644 --- a/Assets/External/VRM/Tests/VersionTests.cs +++ b/Assets/External/VRM/Tests/VersionTests.cs @@ -1,22 +1,17 @@ using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using UniJSON; -using UnityEngine; namespace VRM { public class UniVRMVersionTests { [Test] - [TestCase(VRMVersion.VERSION, false)] + [TestCase(UniGLTF.PackageVersion.VERSION, false)] [TestCase("0.199", true)] [TestCase("0.199.0", true)] [TestCase("1.0.0", true)] public void IsNewerTest(string newer, bool isNewer) { - Assert.AreEqual(isNewer, VRMVersion.IsNewer(newer)); + Assert.AreEqual(isNewer, UniGLTF.PackageVersion.IsNewer(newer)); } [Test] @@ -31,7 +26,7 @@ namespace VRM [TestCase("1.0.0", "0.51.0", true)] public void IsNewerTest(string newer, string older, bool isNewer) { - Assert.AreEqual(isNewer, VRMVersion.IsNewer(newer, older)); + Assert.AreEqual(isNewer, UniGLTF.PackageVersion.IsNewer(newer, older)); } [Test] @@ -43,8 +38,8 @@ namespace VRM [TestCase("aaaaa", false, 0, 0, 0, "")] public void ParseVersionTest(string version, bool canBeParsed, int major, int minor, int patch, string pre) { - VRMVersion.Version v; - var res = VRMVersion.ParseVersion(version, out v); + UniGLTF.PackageVersion.Version v; + var res = UniGLTF.PackageVersion.ParseVersion(version, out v); Assert.AreEqual(canBeParsed, res); if (res) { diff --git a/Assets/External/VRM/package.json b/Assets/External/VRM/package.json index 0ffd0e5b4..06e160ecd 100644 --- a/Assets/External/VRM/package.json +++ b/Assets/External/VRM/package.json @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c0fb9880db74fe46a03b0637a89d34ce3c879b5292e6e481e3b4c9d903651824 -size 988 +oid sha256:bef9b9fe3ca6711c998e6372435c41f91af479ad6c3a4ebbccb8514a8617cb82 +size 1022 diff --git a/Assets/External/VRM10.meta b/Assets/External/VRM10.meta new file mode 100644 index 000000000..3d5c5d632 --- /dev/null +++ b/Assets/External/VRM10.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4fcd733d82a0cc54f9b4c88f8ee97155 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor.meta b/Assets/External/VRM10/Editor.meta new file mode 100644 index 000000000..79495e16c --- /dev/null +++ b/Assets/External/VRM10/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7d2fdd9f95a38e641a1b3f56cf5eaf16 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components.meta b/Assets/External/VRM10/Editor/Components.meta new file mode 100644 index 000000000..af07ad9a9 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fbb107c1888c945489ac2c567af3385e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Attribute.meta b/Assets/External/VRM10/Editor/Components/Attribute.meta new file mode 100644 index 000000000..9030e509f --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Attribute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 165ab9c04d7db604586dd5175eec153f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Attribute/ReadOnlyDrawer.cs b/Assets/External/VRM10/Editor/Components/Attribute/ReadOnlyDrawer.cs new file mode 100644 index 000000000..f94f3cc74 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Attribute/ReadOnlyDrawer.cs @@ -0,0 +1,26 @@ +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + public class ReadOnlyAttribute : PropertyAttribute + { + + } + + [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] + public class ReadOnlyDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUI.GetPropertyHeight(property, label, true); + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + GUI.enabled = false; + EditorGUI.PropertyField(position, property, label, true); + GUI.enabled = true; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Components/Attribute/ReadOnlyDrawer.cs.meta b/Assets/External/VRM10/Editor/Components/Attribute/ReadOnlyDrawer.cs.meta new file mode 100644 index 000000000..b5cbb78aa --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Attribute/ReadOnlyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 06a80a5d47e6b31458e2714ed692e1a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression.meta b/Assets/External/VRM10/Editor/Components/Expression.meta new file mode 100644 index 000000000..cfb1a56f8 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4dcc84ae9f5201a479ca8df8fc991824 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs b/Assets/External/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs new file mode 100644 index 000000000..4791a460a --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs @@ -0,0 +1,249 @@ +using System; +using UnityEditor; +using UnityEngine; + + +namespace UniVRM10 +{ + public static class ExpressionEditorHelper + { + public static bool StringPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) + { + if (options == null) + { + newIndex = -1; + return false; + } + + var oldIndex = Array.IndexOf(options, prop.stringValue); + newIndex = EditorGUI.Popup(rect, oldIndex, options); + if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) + { + prop.stringValue = options[newIndex]; + return true; + } + else + { + return false; + } + } + + public static T EnumPopup(Rect rect, T value) where T : Enum + { + return (T)EditorGUI.EnumPopup(rect, (Enum)value); + } + + public static bool IntPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) + { + if (options == null) + { + newIndex = -1; + return false; + } + + var oldIndex = prop.intValue; + newIndex = EditorGUI.Popup(rect, oldIndex, options); + if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) + { + prop.intValue = newIndex; + return true; + } + else + { + return false; + } + } + + public static bool FloatSlider(Rect rect, SerializedProperty prop, float maxValue) + { + var oldValue = prop.floatValue; + var newValue = EditorGUI.Slider(rect, prop.floatValue, 0, maxValue); + if (newValue != oldValue) + { + prop.floatValue = newValue; + return true; + } + else + { + return false; + } + } + + public static bool ColorProp(Rect rect, SerializedProperty prop) + { + var oldValue = (Color)prop.vector4Value; + var newValue = EditorGUI.ColorField(rect, prop.displayName, oldValue); + if (newValue != oldValue) + { + prop.vector4Value = newValue; + return true; + } + else + { + return false; + } + } + + public static bool UVProp(Rect rect, SerializedProperty prop) + { + var oldValue = prop.vector2Value; + var newValue = EditorGUI.Vector2Field(rect, prop.displayName, oldValue); + if (newValue != oldValue) + { + prop.vector2Value = newValue; + return true; + } + else + { + return false; + } + } + + static Rect AdvanceRect(ref float x, float y, float w, float h) + { + var rect = new Rect(x, y, w, h); + x += w; + return rect; + } + + static float[] v2 = new float[2]; + static GUIContent[] l2 = new GUIContent[]{ + new GUIContent("x"), + new GUIContent("y") + }; + static Vector4 TilingOffset(Rect rect, string label, Vector4 src) + { + /* + var style = new GUIStyle() + { + alignment = TextAnchor.MiddleRight, + }; + */ + + var quad = (rect.width - 56); + var x = rect.x; + //EditorGUIUtility.labelWidth = 18; + + EditorGUI.LabelField(AdvanceRect(ref x, rect.y, 40, rect.height), "Tiling"); + v2[0] = src.x; + v2[1] = src.y; + EditorGUI.MultiFloatField(AdvanceRect(ref x, rect.y, quad, rect.height), l2, v2); + src.x = v2[0]; + src.y = v2[1]; + + //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); + //src.y = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", src.y); + + rect.y += EditorGUIUtility.singleLineHeight; + x = rect.x; + EditorGUI.LabelField(AdvanceRect(ref x, rect.y, 40, rect.height), "Offset"); + v2[0] = src.z; + v2[1] = src.w; + EditorGUI.MultiFloatField(AdvanceRect(ref x, rect.y, quad, rect.height), l2, v2); + src.z = v2[0]; + src.w = v2[1]; + + //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad * 2, rect.height), "Offset X", style); + //src.z = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "X", src.z); + + //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); + //src.w = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", src.w); + + return src; + } + + static bool OffsetProp(Rect rect, SerializedProperty prop) + { + var oldValue = prop.vector4Value; + //var newValue = EditorGUI.Vector4Field(rect, prop.displayName, oldValue); + var newValue = TilingOffset(rect, prop.displayName, oldValue); + if (newValue != oldValue) + { + prop.vector4Value = newValue; + return true; + } + else + { + return false; + } + } + } + + /// https://gist.github.com/gszauer/7799899 + public class TextureScale + { + private static Color[] texColors; + private static Color[] newColors; + private static int w; + private static float ratioX; + private static float ratioY; + private static int w2; + + public static void Scale(Texture2D tex, int newWidth, int newHeight) + { + texColors = tex.GetPixels(); + newColors = new Color[newWidth * newHeight]; + ratioX = 1.0f / ((float)newWidth / (tex.width - 1)); + ratioY = 1.0f / ((float)newHeight / (tex.height - 1)); + w = tex.width; + w2 = newWidth; + + BilinearScale(0, newHeight); + +#if UNITY_2021_2_OR_NEWER + tex.Reinitialize(newWidth, newHeight); +#else + tex.Resize(newWidth, newHeight); +#endif + tex.SetPixels(newColors); + tex.Apply(); + } + + private static void BilinearScale(int start, int end) + { + for (var y = start; y < end; y++) + { + int yFloor = (int)Mathf.Floor(y * ratioY); + var y1 = yFloor * w; + var y2 = (yFloor + 1) * w; + var yw = y * w2; + + for (var x = 0; x < w2; x++) + { + int xFloor = (int)Mathf.Floor(x * ratioX); + var xLerp = x * ratioX - xFloor; + newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor + 1], xLerp), + ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor + 1], xLerp), + y * ratioY - yFloor); + } + } + } + + private static Color ColorLerpUnclamped(Color c1, Color c2, float value) + { + return new Color(c1.r + (c2.r - c1.r) * value, + c1.g + (c2.g - c1.g) * value, + c1.b + (c2.b - c1.b) * value, + c1.a + (c2.a - c1.a) * value); + } + + /// http://light11.hatenadiary.com/entry/2018/04/19/194015 + public static Texture2D GetResized(Texture2D texture, int width, int height) + { + // リサイズ後のサイズを持つRenderTextureを作成して書き込む + var rt = RenderTexture.GetTemporary(width, height); + Graphics.Blit(texture, rt); + + // リサイズ後のサイズを持つTexture2Dを作成してRenderTextureから書き込む + var preRT = RenderTexture.active; + RenderTexture.active = rt; + var ret = new Texture2D(width, height); + ret.ReadPixels(new Rect(0, 0, width, height), 0, 0); + ret.Apply(); + RenderTexture.active = preRT; + + RenderTexture.ReleaseTemporary(rt); + return ret; + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs.meta new file mode 100644 index 000000000..1ac65abfb --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dfbaf4fb19a693244b0fde44542b18b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression/ExpressionSlider.cs b/Assets/External/VRM10/Editor/Components/Expression/ExpressionSlider.cs new file mode 100644 index 000000000..d84d385d6 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ExpressionSlider.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + public class ExpressionSlider + { + Dictionary m_expressionKeys; + ExpressionKey m_key; + + public ExpressionSlider(Dictionary expressionKeys, ExpressionKey key) + { + m_expressionKeys = expressionKeys; + m_key = key; + } + + public KeyValuePair Slider() + { + var oldValue = m_expressionKeys[m_key]; + var enable = GUI.enabled; + GUI.enabled = Application.isPlaying; + var newValue = EditorGUILayout.Slider(m_key.ToString(), oldValue, 0, 1.0f); + GUI.enabled = enable; + return new KeyValuePair(m_key, newValue); + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/Expression/ExpressionSlider.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/ExpressionSlider.cs.meta new file mode 100644 index 000000000..878fc07fd --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ExpressionSlider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1d6be45aa67f5445884833ae12546bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs b/Assets/External/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs new file mode 100644 index 000000000..4020fcf06 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs @@ -0,0 +1,168 @@ +using System; +using UnityEditor; +using UnityEngine; + + +namespace UniVRM10 +{ + /// + /// based + /// + /// * https://gist.github.com/radiatoryang/a2282d44ba71848e498bb2e03da98991 + /// + + /// + /// PreviewRenderUtilityを管理する + /// PreviewSceneをレンダリングする + /// + public class PreviewFaceRenderer : IDisposable + { + PreviewRenderUtility m_previewUtility; + public Camera PreviewCamera + { + get + { +#if UNITY_2017_1_OR_NEWER + return m_previewUtility.camera; +#else + return m_previewUtility.m_Camera; +#endif + } + } + + public Light[] PreviewLights + { + get + { +#if UNITY_2017_1_OR_NEWER + return m_previewUtility.lights; +#else + return m_previewUtility.m_Light; +#endif + } + } + + public void SetAmbientColor(Color color) + { +#if UNITY_2017_1_OR_NEWER + m_previewUtility.ambientColor = color; +#else + // ? +#endif + } + + public PreviewFaceRenderer() + { + m_previewUtility = new PreviewRenderUtility(); + + foreach (var light in PreviewLights) + { + if (light == null) continue; + light.intensity = 0f; + } + + if (PreviewLights.Length > 0 && PreviewLights[0] != null) + { + PreviewLights[0].intensity = 1f; + PreviewLights[0].transform.rotation = Quaternion.Euler(20f, 200f, 0); + PreviewLights[0].color = new Color(1f, 1f, 1f, 1f); + } + + SetAmbientColor(new Color(0.1f, 0.1f, 0.1f, 1f)); + } + + class FogScope : IDisposable + { + bool fog; + + public FogScope() + { + fog = RenderSettings.fog; // ... let's remember the current fog setting... + // we are technically rendering everything in the scene, so scene fog might affect it... + Unsupported.SetRenderSettingsUseFogNoDirty(false); // ... and then temporarily turn it off + } + + public void Dispose() + { + Unsupported.SetRenderSettingsUseFogNoDirty(fog); + } + } + + //const float FACTOR = 0.1f; + + public Texture Render(Rect r, GUIStyle background, PreviewSceneManager scene, + float yaw, float pitch, Vector3 position) + { + if (scene == null) return null; + + using (var fog = new FogScope()) + { + m_previewUtility.BeginPreview(r, background); // set up the PreviewRenderUtility's mini internal scene + + // setup the ObjectPreview's camera + scene.SetupCamera(PreviewCamera, scene.TargetPosition, yaw, pitch, position); + + foreach (var item in scene.EnumRenderItems) + { + // now, actually render out the RenderTexture + //RenderMeshPreview(previewMesh, skinMeshRender.sharedMaterials); + // submesh support, in case the mesh is made of multiple parts + int subMeshCount = item.Mesh.subMeshCount; + for (int i = 0; i < subMeshCount; i++) + { + m_previewUtility.DrawMesh(item.Mesh, + item.Position, item.Rotation, + item.Materials[i], i); + } + } + + // VERY IMPORTANT: this manually tells the camera to render and produce the render texture + PreviewCamera.Render(); + //m_previewUtility.Render(false, false); + + // reset the scene's fog from before + return m_previewUtility.EndPreview(); + } + } + + #region IDisposable Support + private bool disposedValue = false; // 重複する呼び出しを検出するには + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: マネージ状態を破棄します (マネージ オブジェクト)。 + if (this.m_previewUtility != null) + { + this.m_previewUtility.Cleanup(); + this.m_previewUtility = null; + } + } + + // TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。 + // TODO: 大きなフィールドを null に設定します。 + + disposedValue = true; + } + } + + // TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。 + // ~PreviewFaceRenderer() { + // // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。 + // Dispose(false); + // } + + // このコードは、破棄可能なパターンを正しく実装できるように追加されました。 + public void Dispose() + { + // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。 + Dispose(true); + // TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。 + // GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonDiff.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs.meta similarity index 76% rename from Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonDiff.cs.meta rename to Assets/External/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs.meta index 3c221f2f4..38da77a05 100644 --- a/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonDiff.cs.meta +++ b/Assets/External/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 97356eb7e23aca64c84f836d6c298f43 -timeCreated: 1543427903 +guid: 9de8d16a3d572ea4da3fc4a69ba61964 +timeCreated: 1522931965 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialColorBindingList.cs b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialColorBindingList.cs new file mode 100644 index 000000000..aab93c0d4 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialColorBindingList.cs @@ -0,0 +1,88 @@ +using System; +using UniGLTF.Utils; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + + +namespace UniVRM10 +{ + public class ReorderableMaterialColorBindingList + { + ReorderableList m_list; + SerializedProperty m_serializedProperty; + bool m_changed; + public ReorderableMaterialColorBindingList(SerializedObject serializedObject, string[] materialNames, int height) + { + m_serializedProperty = serializedObject.FindProperty(nameof(VRM10Expression.MaterialColorBindings)); + m_list = new ReorderableList(serializedObject, m_serializedProperty); + m_list.elementHeight = height * 3; + m_list.drawElementCallback = + (rect, index, isActive, isFocused) => + { + var element = m_serializedProperty.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + if (DrawMaterialValueBinding(rect, element, materialNames, height)) + { + m_changed = true; + } + }; + } + + /// + /// Material List のElement描画 + /// + static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, + string[] materialNames, int height) + { + bool changed = false; + if (materialNames != null) + { + // Material を選択する + var y = position.y; + var rect = new Rect(position.x, y, position.width, height); + int materialIndex; + if (ExpressionEditorHelper.StringPopup(rect, property.FindPropertyRelative(nameof(MaterialColorBinding.MaterialName)), materialNames, out materialIndex)) + { + changed = true; + } + + y += height; + rect = new Rect(position.x, y, position.width, height); + + // 対象のプロパティを enum から選択する + var bindTypeProp = property.FindPropertyRelative("BindType"); + var bindTypes = CachedEnum.GetValues(); + var bindType = bindTypes[bindTypeProp.enumValueIndex]; + var newBindType = ExpressionEditorHelper.EnumPopup(rect, bindType); + if (newBindType != bindType) + { + bindTypeProp.enumValueIndex = Array.IndexOf(bindTypes, newBindType); + changed = true; + } + + // 目標の色 + y += height; + rect = new Rect(position.x, y, position.width, height); + if (ExpressionEditorHelper.ColorProp(rect, property.FindPropertyRelative(nameof(MaterialColorBinding.TargetValue)))) + { + changed = true; + } + } + return changed; + } + + public bool Draw(string label) + { + m_changed = false; + m_list.DoLayoutList(); + if (GUILayout.Button($"Clear {label}")) + { + m_changed = true; + m_serializedProperty.arraySize = 0; + } + return m_changed; + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialColorBindingList.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialColorBindingList.cs.meta new file mode 100644 index 000000000..4d366d723 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialColorBindingList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e6f6fcbf32b1c674aa717d3a7daabf23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialUVBindingList.cs b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialUVBindingList.cs new file mode 100644 index 000000000..ebe151753 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialUVBindingList.cs @@ -0,0 +1,95 @@ +using System; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + + +namespace UniVRM10 +{ + public class ReorderableMaterialUVBindingList + { + ReorderableList m_list; + SerializedProperty m_serializedProperty; + bool m_changed; + + public ReorderableMaterialUVBindingList(SerializedObject serializedObject, string[] materialNames, int height) + { + m_serializedProperty = serializedObject.FindProperty(nameof(VRM10Expression.MaterialUVBindings)); + m_list = new ReorderableList(serializedObject, m_serializedProperty); + m_list.elementHeight = height * 3; + m_list.drawElementCallback = + (rect, index, isActive, isFocused) => + { + var element = m_serializedProperty.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + if (DrawMaterialUVBinding(rect, element, materialNames, height)) + { + m_changed = true; + } + }; + m_list.onAddCallback = (m_list) => + { + // first add one element + m_serializedProperty.arraySize++; + + // then get that element + var newIndex = m_serializedProperty.arraySize - 1; + var newElement = m_serializedProperty.GetArrayElementAtIndex(newIndex); + + // now reset all properties like + var scaling = newElement.FindPropertyRelative(nameof(MaterialUVBinding.Scaling)); + scaling.vector2Value = Vector2.one; + }; + } + + /// + /// Material List のElement描画 + /// + static bool DrawMaterialUVBinding(Rect position, SerializedProperty property, + string[] materialNames, int height) + { + bool changed = false; + if (materialNames != null) + { + // Materialを選択する + var y = position.y; + var rect = new Rect(position.x, y, position.width, height); + int materialIndex; + if (ExpressionEditorHelper.StringPopup(rect, property.FindPropertyRelative(nameof(MaterialUVBinding.MaterialName)), materialNames, out materialIndex)) + { + changed = true; + } + + // offset + y += height; + rect = new Rect(position.x, y, position.width, height); + if (ExpressionEditorHelper.UVProp(rect, property.FindPropertyRelative(nameof(MaterialUVBinding.Offset)))) + { + changed = true; + } + + // scale + y += height; + rect = new Rect(position.x, y, position.width, height); + if (ExpressionEditorHelper.UVProp(rect, property.FindPropertyRelative(nameof(MaterialUVBinding.Scaling)))) + { + changed = true; + } + } + return changed; + } + + public bool Draw(string label) + { + m_changed = false; + m_list.DoLayoutList(); + if (GUILayout.Button($"Clear {label}")) + { + m_changed = true; + m_serializedProperty.arraySize = 0; + } + return m_changed; + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialUVBindingList.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialUVBindingList.cs.meta new file mode 100644 index 000000000..3c0c7ba13 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMaterialUVBindingList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38d1e54e633fb654c812d4718e27c71b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs new file mode 100644 index 000000000..98f962115 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs @@ -0,0 +1,118 @@ +using System; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + + +namespace UniVRM10 +{ + public class ReorderableMorphTargetBindingList + { + ReorderableList m_ValuesList; + SerializedProperty m_valuesProp; + bool m_changed; + + public ReorderableMorphTargetBindingList(SerializedObject serializedObject, PreviewSceneManager previewSceneManager, int height) + { + m_valuesProp = serializedObject.FindProperty(nameof(VRM10Expression.MorphTargetBindings)); + m_ValuesList = new ReorderableList(serializedObject, m_valuesProp); + m_ValuesList.elementHeight = height * 3; + m_ValuesList.drawElementCallback = + (rect, index, isActive, isFocused) => + { + var element = m_valuesProp.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + if (DrawMorphTargetBinding(rect, element, previewSceneManager, height)) + { + m_changed = true; + } + }; + } + + /// + /// MorphTarget List のElement描画 + /// + static bool DrawMorphTargetBinding(Rect position, SerializedProperty property, + PreviewSceneManager scene, int height) + { + bool changed = false; + if (scene != null) + { + var y = position.y; + var rect = new Rect(position.x, y, position.width, height); + int pathIndex; + if (ExpressionEditorHelper.StringPopup(rect, property.FindPropertyRelative(nameof(MorphTargetBinding.RelativePath)), scene.SkinnedMeshRendererPathList, out pathIndex)) + { + changed = true; + } + + y += height; + rect = new Rect(position.x, y, position.width, height); + int morphTargetIndex; + if (ExpressionEditorHelper.IntPopup(rect, property.FindPropertyRelative(nameof(MorphTargetBinding.Index)), scene.GetBlendShapeNames(pathIndex), out morphTargetIndex)) + { + changed = true; + } + + y += height; + rect = new Rect(position.x, y, position.width, height); + if (ExpressionEditorHelper.FloatSlider(rect, property.FindPropertyRelative(nameof(MorphTargetBinding.Weight)), MorphTargetBinding.MAX_WEIGHT)) + { + changed = true; + } + } + return changed; + } + + public void SetValues(MorphTargetBinding[] bindings) + { + m_valuesProp.ClearArray(); + m_valuesProp.arraySize = bindings.Length; + for (int i = 0; i < bindings.Length; ++i) + { + var item = m_valuesProp.GetArrayElementAtIndex(i); + + var endProperty = item.GetEndProperty(); + while (item.NextVisible(true)) + { + if (SerializedProperty.EqualContents(item, endProperty)) + { + break; + } + + switch (item.name) + { + case nameof(MorphTargetBinding.RelativePath): + item.stringValue = bindings[i].RelativePath; + break; + + case nameof(MorphTargetBinding.Index): + item.intValue = bindings[i].Index; + break; + + case nameof(MorphTargetBinding.Weight): + item.floatValue = bindings[i].Weight; + break; + + default: + throw new Exception(); + } + } + } + + } + + public bool Draw(string label) + { + m_changed = false; + m_ValuesList.DoLayoutList(); + if (GUILayout.Button($"Clear {label}")) + { + m_changed = true; + m_valuesProp.arraySize = 0; + } + return m_changed; + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs.meta new file mode 100644 index 000000000..159bb3796 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b82126a68b53be745936ee0115e3708a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs b/Assets/External/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs new file mode 100644 index 000000000..782d355a3 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs @@ -0,0 +1,281 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Expression カスタムエディタの実装 + /// + public class SerializedExpressionEditor + { + VRM10Expression m_targetObject; + + SerializedObject m_serializedObject; + + #region Properties + SerializedProperty m_thumbnail; + SerializedProperty m_isBinaryProp; + + public bool IsBinary => m_isBinaryProp.boolValue; + + SerializedProperty m_ignoreBlinkProp; + SerializedProperty m_ignoreLookAtProp; + SerializedProperty m_ignoreMouthProp; + #endregion + + ReorderableMorphTargetBindingList m_morphTargetBindings; + ReorderableMaterialColorBindingList m_materialColorBindings; + ReorderableMaterialUVBindingList m_materialUVBindings; + + #region Editor values + + bool m_changed; + + static int s_Mode; + static bool s_MorphTargetFoldout = true; + static bool s_OptionFoldout; + static bool s_ListFoldout; + + static string[] MODES = new[]{ + "MorphTarget", + "Material Color", + "Texture Transform" + }; + + PreviewMeshItem[] m_items; + #endregion + + public SerializedExpressionEditor(SerializedObject serializedObject, + PreviewSceneManager previewSceneManager) : this( + serializedObject, (VRM10Expression)serializedObject.targetObject, previewSceneManager) + { } + + public SerializedExpressionEditor(VRM10Expression expression, + PreviewSceneManager previewSceneManager) : this( + new SerializedObject(expression), expression, previewSceneManager) + { } + + public SerializedExpressionEditor(SerializedObject serializedObject, VRM10Expression targetObject, + PreviewSceneManager previewSceneManager) + { + this.m_serializedObject = serializedObject; + this.m_targetObject = targetObject; + + m_isBinaryProp = serializedObject.FindProperty(nameof(targetObject.IsBinary)); + m_ignoreBlinkProp = serializedObject.FindProperty(nameof(targetObject.OverrideBlink)); + m_ignoreLookAtProp = serializedObject.FindProperty(nameof(targetObject.OverrideLookAt)); + m_ignoreMouthProp = serializedObject.FindProperty(nameof(targetObject.OverrideMouth)); + + m_morphTargetBindings = new ReorderableMorphTargetBindingList(serializedObject, previewSceneManager, 20); + m_materialColorBindings = new ReorderableMaterialColorBindingList(serializedObject, previewSceneManager?.MaterialNames, 20); + m_materialUVBindings = new ReorderableMaterialUVBindingList(serializedObject, previewSceneManager?.MaterialNames, 20); + + m_items = previewSceneManager.EnumRenderItems + .Where(x => x.SkinnedMeshRenderer != null) + .ToArray(); + } + + public bool Draw(out VRM10Expression bakeValue) + { + m_changed = false; + + m_serializedObject.Update(); + + // Readonly の Expression 参照 + GUI.enabled = false; + EditorGUILayout.ObjectField("Current clip", + m_targetObject, typeof(VRM10Expression), false); + GUI.enabled = true; + + s_MorphTargetFoldout = CustomUI.Foldout(s_MorphTargetFoldout, "MorphTarget"); + if (s_MorphTargetFoldout) + { + EditorGUI.indentLevel++; + var changed = MorphTargetBindsGUI(); + if (changed) + { + string maxWeightName; + var bindings = GetBindings(out maxWeightName); + m_morphTargetBindings.SetValues(bindings); + + m_changed = true; + } + EditorGUI.indentLevel--; + } + + s_ListFoldout = CustomUI.Foldout(s_ListFoldout, "List"); + if (s_ListFoldout) + { + EditorGUI.indentLevel++; + s_Mode = GUILayout.Toolbar(s_Mode, MODES); + switch (s_Mode) + { + case 0: + // MorphTarget + { + if (m_morphTargetBindings.Draw("MorphTarget")) + { + m_changed = true; + } + } + break; + + case 1: + // Material + { + if (m_materialColorBindings.Draw("MaterialColor")) + { + m_changed = true; + } + } + break; + + case 2: + // TextureTransform + { + if (m_materialUVBindings.Draw("TextureTransform")) + { + m_changed = true; + } + } + break; + } + EditorGUI.indentLevel--; + } + + s_OptionFoldout = CustomUI.Foldout(s_OptionFoldout, "Option"); + if (s_OptionFoldout) + { + EditorGUI.indentLevel++; + + // v0.45 Added. Binary flag + EditorGUILayout.PropertyField(m_isBinaryProp, true); + + // v1.0 Ignore State + EditorGUILayout.PropertyField(m_ignoreBlinkProp, true); + EditorGUILayout.PropertyField(m_ignoreLookAtProp, true); + EditorGUILayout.PropertyField(m_ignoreMouthProp, true); + + + EditorGUI.indentLevel--; + } + + m_serializedObject.ApplyModifiedProperties(); + + bakeValue = m_targetObject; + return m_changed; + } + + static List m_meshFolds = new List(); + bool MorphTargetBindsGUI() + { + bool changed = false; + int foldIndex = 0; + // すべてのSkinnedMeshRendererを列挙する + foreach (var renderer in m_items.Select(x => x.SkinnedMeshRenderer)) + { + var mesh = renderer.sharedMesh; + if (mesh != null && mesh.blendShapeCount > 0) + { + //var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, m_target.transform); + //EditorGUILayout.LabelField(m_target.name + "/" + item.Path); + + if (foldIndex >= m_meshFolds.Count) + { + m_meshFolds.Add(false); + } + m_meshFolds[foldIndex] = EditorGUILayout.Foldout(m_meshFolds[foldIndex], renderer.name); + if (m_meshFolds[foldIndex]) + { + //EditorGUI.indentLevel += 1; + for (int i = 0; i < mesh.blendShapeCount; ++i) + { + var src = renderer.GetBlendShapeWeight(i) * MorphTargetBinding.UNITY_TO_VRM; + var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, MorphTargetBinding.MAX_WEIGHT); + if (dst != src) + { + renderer.SetBlendShapeWeight(i, dst * MorphTargetBinding.VRM_TO_UNITY); + changed = true; + } + } + //EditorGUI.indentLevel -= 1; + } + ++foldIndex; + } + } + return changed; + } + + MorphTargetBinding[] GetBindings(out string _maxWeightName) + { + var maxUnityWeight = 0.0f; + var maxWeightName = ""; + // weightのついたblendShapeを集める + var values = m_items + .SelectMany(x => + { + var mesh = x.SkinnedMeshRenderer.sharedMesh; + + var relativePath = x.Path; + + var list = new List(); + if (mesh != null) + { + for (int i = 0; i < mesh.blendShapeCount; ++i) + { + var unityWeight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i); + if (unityWeight == 0) + { + continue; + } + var name = mesh.GetBlendShapeName(i); + if (unityWeight > maxUnityWeight) + { + maxWeightName = name; + maxUnityWeight = unityWeight; + } + list.Add(new MorphTargetBinding(relativePath, i, unityWeight * MorphTargetBinding.UNITY_TO_VRM)); + } + } + return list; + }).ToArray() + ; + _maxWeightName = maxWeightName; + return values; + } + } + + /// http://tips.hecomi.com/entry/2016/10/15/004144 + public static class CustomUI + { + public static bool Foldout(bool display, string title) + { + var style = new GUIStyle("ShurikenModuleTitle"); + style.font = new GUIStyle(EditorStyles.label).font; + style.border = new RectOffset(15, 7, 4, 4); + style.fixedHeight = 22; + style.contentOffset = new Vector2(20f, -2f); + + var rect = GUILayoutUtility.GetRect(16f, 22f, style); + GUI.Box(rect, title, style); + + var e = Event.current; + + var toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f); + if (e.type == EventType.Repaint) + { + EditorStyles.foldout.Draw(toggleRect, false, false, display, false); + } + + if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) + { + display = !display; + e.Use(); + } + + return display; + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs.meta new file mode 100644 index 000000000..12959d8ca --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b0f700f0a01ce24dbc7f7d0b684cc03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression/VRM10ExpressionEditor.cs b/Assets/External/VRM10/Editor/Components/Expression/VRM10ExpressionEditor.cs new file mode 100644 index 000000000..1f69bf86f --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/VRM10ExpressionEditor.cs @@ -0,0 +1,340 @@ +using System; +using System.IO; +using UniGLTF; +using UnityEditor; +using UnityEngine; + + +namespace UniVRM10 +{ + [CustomEditor(typeof(VRM10Expression))] + public class ExpressionEditor : Editor + { + /// + /// Preview(Inspectorの下方)を描画するクラス + /// + /// * PreviewRenderUtility.m_cameraのUnityVersionによる切り分け + /// + /// + PreviewFaceRenderer m_renderer; + + /// + /// Previewを描画するのにシーンが必用である。 + /// m_target.Prefabをインスタンス化したシーンを管理する。 + /// + /// * ExpressionのBake + /// * MaterialMorphの適用 + /// * Previewカメラのコントロール + /// * Previewライティングのコントロール + /// + /// + PreviewSceneManager m_scene; + + /// + /// Preview シーンに Expression を適用する + /// + void Bake() + { + if (m_scene != null) + { + //Debug.Log("Bake"); + m_scene.Bake(CurrentExpression(), 1.0f); + } + } + + void ClearScene() + { + if (m_scene != null) + { + //Debug.LogFormat("OnDestroy"); + m_scene.Clean(); + GameObject.DestroyImmediate(m_scene.gameObject); + m_scene = null; + } + } + + void PrefabGUI() + { + var prefab = (GameObject)EditorGUILayout.ObjectField("Preview Prefab", m_target.Prefab, typeof(GameObject), false); + if (prefab == m_target.Prefab) + { + return; + } + ClearPreview(); + m_target.Prefab = prefab; + Initialize(); + } + + void OnEnable() + { + Initialize(); + } + + void OnDisable() + { + ClearPreview(); + } + + void Initialize() + { + m_target = (VRM10Expression)target; + m_renderer = new PreviewFaceRenderer(); + } + + void ClearPreview() + { + if (m_renderer != null) + { + m_renderer.Dispose(); + m_renderer = null; + } + + m_serializedEditor = null; + ClearScene(); + } + + void OnDestroy() + { + // 2018/2019 で OnDisable/OnDestroy の呼ばれ方が違う? + ClearScene(); + } + + static void Separator() + { + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + //GUILayout.Space(); + GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + } + + private static int sliderHash = "Slider".GetHashCode(); + float m_yaw = 180.0f; + float m_pitch; + Vector3 m_position = new Vector3(0, 0, -0.8f); + + // very important to override this, it tells Unity to render an ObjectPreview at the bottom of the inspector + public override bool HasPreviewGUI() { return true; } + + public RenderTexture PreviewTexture; + + // the main ObjectPreview function... it's called constantly, like other IMGUI On*GUI() functions + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + // if this is happening, you have bigger problems + if (!ShaderUtil.hardwareSupportsRectRenderTexture) + { + if (Event.current.type == EventType.Repaint) + { + EditorGUI.DropShadowLabel(new Rect(r.x, r.y, r.width, 40f), + "Mesh preview requires\nrender texture support"); + } + return; + } + + var src = r; + + var min = Mathf.Min(r.width, r.height); + r.width = min; + r.height = min; + r.x = src.x + (src.width - min) / 2; + r.y = src.y + (src.height - min) / 2; + + //previewDir = Drag2D(previewDir, r); + { + int controlId = GUIUtility.GetControlID(sliderHash, FocusType.Passive); + Event e = Event.current; + switch (e.GetTypeForControl(controlId)) + { + case EventType.MouseDown: + if (r.Contains(e.mousePosition) && (double)r.width > 50.0) + { + GUIUtility.hotControl = controlId; + e.Use(); + EditorGUIUtility.SetWantsMouseJumping(1); + break; + } + break; + + case EventType.MouseUp: + if (GUIUtility.hotControl == controlId) + GUIUtility.hotControl = 0; + EditorGUIUtility.SetWantsMouseJumping(0); + break; + + case EventType.MouseDrag: + if (GUIUtility.hotControl == controlId) + { + if (e.button == 2) + { + var shift = e.delta * (!e.shift ? 1f : 3f) / Mathf.Min(r.width, r.height); + m_position.x -= shift.x; + m_position.y += shift.y; + e.Use(); + GUI.changed = true; + } + else if ( + e.button == 0 || + e.button == 1) + { + var shift = e.delta * (!e.shift ? 1f : 3f) / Mathf.Min(r.width, r.height) * 140f; + m_yaw += shift.x; + m_pitch += shift.y; + m_pitch = Mathf.Clamp(m_pitch, -90f, 90f); + e.Use(); + GUI.changed = true; + } + break; + } + break; + + case EventType.ScrollWheel: + //Debug.LogFormat("wheel: {0}", current.delta); + if (r.Contains(e.mousePosition)) + { + if (e.delta.y > 0) + { + m_position.z *= 1.1f; + Repaint(); + } + else if (e.delta.y < 0) + { + m_position.z *= 0.9f; + Repaint(); + } + } + break; + } + //return scrollPosition; + } + //Debug.LogFormat("{0}", previewDir); + + if (Event.current.type != EventType.Repaint) + { + // if we don't need to update yet, then don't + return; + } + + if (m_renderer != null && m_scene != null) + { + PreviewTexture = m_renderer.Render(r, background, m_scene, m_yaw, m_pitch, m_position) as RenderTexture; + if (PreviewTexture != null) + { + // draw the RenderTexture in the ObjectPreview pane + GUI.DrawTexture(r, PreviewTexture, ScaleMode.StretchToFill, false); + } + } + } + + SerializedExpressionEditor m_serializedEditor; + + VRM10Expression m_target; + VRM10Expression CurrentExpression() + { + return m_target; + } + + float m_previewSlider = 1.0f; + + static Texture2D SaveResizedImage(RenderTexture rt, UnityPath path, int size) + { + var tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false); + RenderTexture.active = rt; + tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); + tex.Apply(); + + //TextureScale.Scale(tex, size, size); + tex = TextureScale.GetResized(tex, size, size); + + byte[] bytes; + switch (path.Extension.ToLower()) + { + case ".png": + bytes = tex.EncodeToPNG(); + break; + + case ".jpg": + bytes = tex.EncodeToJPG(); + break; + + default: + throw new Exception(); + } + + if (Application.isPlaying) + { + UnityEngine.Object.Destroy(tex); + } + else + { + UnityEngine.Object.DestroyImmediate(tex); + } + File.WriteAllBytes(path.FullPath, bytes); + + path.ImportAsset(); + return path.LoadAsset(); + } + + public override void OnInspectorGUI() + { + var changed = false; + serializedObject.Update(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.BeginVertical(); + PrefabGUI(); + EditorGUILayout.LabelField("Preview Weight"); + var previewSlider = EditorGUILayout.Slider(m_previewSlider, 0, 1.0f); + if (m_target.IsBinary) + { + previewSlider = Mathf.Round(previewSlider); + } + if (previewSlider != m_previewSlider) + { + m_previewSlider = previewSlider; + changed = true; + } + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + Separator(); + + if (m_scene == null) + { + if (m_target.Prefab != null) + { + m_scene = UniVRM10.PreviewSceneManager.GetOrCreate(m_target.Prefab); + if (m_scene != null) + { + m_scene.gameObject.SetActive(false); + } + Bake(); + } + } + + if (m_scene != null) + { + if (m_serializedEditor == null) + { + m_serializedEditor = new SerializedExpressionEditor(serializedObject, m_scene); + } + if (m_serializedEditor.Draw(out VRM10Expression bakeValue)) + { + changed = true; + } + if (changed) + { + m_scene.Bake(bakeValue, m_previewSlider); + } + } + + serializedObject.ApplyModifiedProperties(); + } + + public override string GetInfoString() + { + if (m_scene == null) return ""; + return m_scene.hasError ? "An error occurred while previewing. Check the console log for details." : ""; + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/Expression/VRM10ExpressionEditor.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/VRM10ExpressionEditor.cs.meta new file mode 100644 index 000000000..bf5603ac9 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/VRM10ExpressionEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0565a023d1e0a114691e3e6f10e59039 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs b/Assets/External/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs new file mode 100644 index 000000000..7787dd1ef --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + // + // Expression 向けの Inspector + // + // Runtime に Expression 操作用の Slider を表示する + // + class Vrm10InstanceEditorExpression + { + Vrm10Instance m_target; + Dictionary m_expressionKeyWeights = new Dictionary(); + List m_sliders; + + public Vrm10InstanceEditorExpression(Vrm10Instance target) + { + m_target = target; + + m_expressionKeyWeights = m_target.Vrm.Expression.Clips.ToDictionary(x => target.Vrm.Expression.CreateKey(x.Clip), x => 0.0f); + m_sliders = m_target.Vrm.Expression.Clips + .Where(x => x.Clip != null) + .Select(x => new ExpressionSlider(m_expressionKeyWeights, target.Vrm.Expression.CreateKey(x.Clip))) + .ToList() + ; + } + + public void OnGUI() + { + EditorGUILayout.Space(); + + if (!Application.isPlaying) + { + EditorGUILayout.HelpBox("Enable when playing", MessageType.Info); + return; + } + + if (m_sliders != null) + { + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Expression Weights", EditorStyles.boldLabel); + + var sliders = m_sliders.Select(x => x.Slider()); + foreach (var slider in sliders) + { + m_expressionKeyWeights[slider.Key] = slider.Value; + } + m_target.Runtime.Expression.SetWeights(m_expressionKeyWeights); + } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Override rates", EditorStyles.boldLabel); + EditorGUI.BeginDisabledGroup(true); + { + EditorGUILayout.Slider("Blink override rate", m_target.Runtime.Expression.BlinkOverrideRate, 0f, 1f); + EditorGUILayout.Slider("LookAt override rate", m_target.Runtime.Expression.LookAtOverrideRate, 0f, 1f); + EditorGUILayout.Slider("Mouth override rate", m_target.Runtime.Expression.MouthOverrideRate, 0f, 1f); + } + EditorGUI.EndDisabledGroup(); + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs.meta b/Assets/External/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs.meta new file mode 100644 index 000000000..e3a414e6f --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/Expression/Vrm10InstanceEditorExpression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 531a88b434472bc498231c4b6f9fc217 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/FirstPerson.meta b/Assets/External/VRM10/Editor/Components/FirstPerson.meta new file mode 100644 index 000000000..af8a45f62 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/FirstPerson.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 33642286ccbb52542afb65da8ab0a667 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/FirstPerson/RendererFirstPersonFlagsDrawer.cs b/Assets/External/VRM10/Editor/Components/FirstPerson/RendererFirstPersonFlagsDrawer.cs new file mode 100644 index 000000000..714cefd5d --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/FirstPerson/RendererFirstPersonFlagsDrawer.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + + +namespace UniVRM10 +{ + [CustomPropertyDrawer(typeof(RendererFirstPersonFlags))] + public class RendererFirstPersonFlagsDrawer : PropertyDrawer + { + static Rect LeftSide(Rect position, float width) + { + return new Rect(position.x, position.y, position.width - width, position.height); + } + static Rect RightSide(Rect position, float width) + { + return new Rect(position.x + (position.width - width), position.y, width, position.height); + } + + const float WIDTH = 140.0f; + + public override void OnGUI(Rect position, + SerializedProperty property, GUIContent label) + { + var rendererProp = property.FindPropertyRelative("Renderer"); + var flagProp = property.FindPropertyRelative("FirstPersonFlag"); + + var root = (property.serializedObject.targetObject as VRM10Object).Prefab; + if (root != null) + { + var renderers = root.GetComponentsInChildren(); + var paths = renderers.Select(x => x.transform.RelativePathFrom(root.transform)).ToArray(); + var selected = Array.IndexOf(paths, rendererProp.stringValue); + var newSelect = EditorGUI.Popup(LeftSide(position, WIDTH), selected, renderers.Select(x => x.name).ToArray()); + if (newSelect != selected && newSelect != -1) + { + rendererProp.stringValue = paths[newSelect]; + } + EditorGUI.PropertyField(RightSide(position, WIDTH), flagProp, new GUIContent(""), true); + } + else + { + EditorGUI.PropertyField(LeftSide(position, WIDTH), rendererProp, new GUIContent(""), true); + EditorGUI.PropertyField(RightSide(position, WIDTH), flagProp, new GUIContent(""), true); + } + } + + /* + public override float GetPropertyHeight(SerializedProperty property, + GUIContent label) + { + return 60.0f; + } + */ + } +} diff --git a/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonPointer.cs.meta b/Assets/External/VRM10/Editor/Components/FirstPerson/RendererFirstPersonFlagsDrawer.cs.meta similarity index 76% rename from Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonPointer.cs.meta rename to Assets/External/VRM10/Editor/Components/FirstPerson/RendererFirstPersonFlagsDrawer.cs.meta index c672f6aa4..2b7afb22f 100644 --- a/Assets/External/UniGLTF/Runtime/UniJSON/Json/JsonPointer.cs.meta +++ b/Assets/External/VRM10/Editor/Components/FirstPerson/RendererFirstPersonFlagsDrawer.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 8b7033668ce791e40819d16e664efe18 -timeCreated: 1543321766 +guid: eba8708502533514b9fe5211d55eb7df +timeCreated: 1520848617 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Assets/External/VRM10/Editor/Components/ScrollView.cs b/Assets/External/VRM10/Editor/Components/ScrollView.cs new file mode 100644 index 000000000..0a35ab38d --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/ScrollView.cs @@ -0,0 +1,44 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + public class ScrollView + { + Vector2 m_scrollPosition; + + public void Draw(float height, Action content, Action repaint) + { + m_scrollPosition = EditorGUILayout.BeginScrollView(m_scrollPosition); + + // mouse wheel scroll part 1 + var isScroll = Event.current.isScrollWheel; + if (isScroll) + { + m_scrollPosition += Event.current.delta * EditorGUIUtility.singleLineHeight; + if (m_scrollPosition.y < 0) + { + m_scrollPosition = Vector2.zero; + } + } + + content(); + + // mouse wheel scroll part 2 + var bottom = EditorGUILayout.GetControlRect(); + if (isScroll) + { + var maxScroll = bottom.y - (height - EditorGUIUtility.singleLineHeight * 2); + // Debug.Log($"{bottom.y}: {this.position.size.y}: {maxScroll}"); + if (m_scrollPosition.y > maxScroll) + { + m_scrollPosition = new Vector2(0, maxScroll); + } + repaint(); + } + + EditorGUILayout.EndScrollView(); + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/ScrollView.cs.meta b/Assets/External/VRM10/Editor/Components/ScrollView.cs.meta new file mode 100644 index 000000000..4e62944ad --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/ScrollView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8a1e5efc02576543b0a7f051bde4eca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/SpringBone.meta b/Assets/External/VRM10/Editor/Components/SpringBone.meta new file mode 100644 index 000000000..0e6c12cb5 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1ac8223d120f39b4a9734061b3a598aa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/CustomInspector.cs b/Assets/External/VRM10/Editor/Components/SpringBone/CustomInspector.cs new file mode 100644 index 000000000..fb8d83a76 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/CustomInspector.cs @@ -0,0 +1,59 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + struct CustomInspector : IDisposable + { + SerializedObject serializedObject; + int m_depth; + + Func m_callback; + + public CustomInspector(SerializedObject so, int depth = 0, Func callback = null) + { + m_depth = depth; + m_callback = callback; + serializedObject = so; + serializedObject.Update(); + } + + public void OnInspectorGUI() + { + int currentDepth = 0; + for (var iterator = serializedObject.GetIterator(); iterator.NextVisible(true);) + { + var isCollapsed = currentDepth < iterator.depth; + if (isCollapsed) + { + continue; + } + +#if DEBUG + // Debug.Log($"{iterator.propertyPath}({iterator.propertyType})"); +#endif + + if (m_callback is null || !m_callback(iterator)) + { + EditorGUI.indentLevel = iterator.depth + m_depth; + EditorGUILayout.PropertyField(iterator, false); + } + + if (iterator.isExpanded) + { + currentDepth = iterator.depth + 1; + } + else + { + currentDepth = iterator.depth; + } + } + } + + public void Dispose() + { + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/CustomInspector.cs.meta b/Assets/External/VRM10/Editor/Components/SpringBone/CustomInspector.cs.meta new file mode 100644 index 000000000..a85877f7e --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/CustomInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2539e35b249361d40aad74d271dcb34e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/SelectedGUI.cs b/Assets/External/VRM10/Editor/Components/SpringBone/SelectedGUI.cs new file mode 100644 index 000000000..6eee18938 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/SelectedGUI.cs @@ -0,0 +1,260 @@ +using System.Linq; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace UniVRM10 +{ + abstract class SelectedGUIBase + { + protected SerializedObject _so { get; private set; } + protected int _index { get; private set; } + + protected SelectedGUIBase(SerializedObject so, int i) + { + _so = so; + _index = i; + } + + public SerializedProperty Property { get; protected set; } + public abstract void Draw2D(Rect r); + public abstract void Draw3D(); + + /// + /// 領域を1行と残りに分割する + /// + /// + /// + public static (Rect line, Rect remain) LayoutLine(Rect rect) + { + return ( + new Rect( + rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight + ), + new Rect( + rect.x, rect.y + EditorGUIUtility.singleLineHeight, rect.width, rect.height - EditorGUIUtility.singleLineHeight + ) + ); + } + + /// + /// 領域を上下2分割 + /// + /// + /// + /// + public static (Rect layout, Rect remain) LayoutVerticalHalf(Rect r) + { + var half = r.height / 2; + return ( + new Rect( + r.x, r.y, r.width, half + ), + new Rect( + r.x, r.y + half, r.width, r.height + ) + ); + } + } + + class SelectedColliderGroupGUI + { + SerializedObject _so; + int _index; + ReorderableList _colliderGroupList; + + public SelectedColliderGroupGUI(SerializedObject so, int i) + { + var target_prop = so.FindProperty($"SpringBone.ColliderGroups.Array.data[{i}]"); + _index = i; + _so = new SerializedObject(target_prop.objectReferenceValue); + + var prop = _so.FindProperty("Colliders"); + _colliderGroupList = new ReorderableList(_so, prop); + + _colliderGroupList.drawElementCallback = (rect, index, isActive, isFocused) => + { + SerializedProperty element = prop.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + EditorGUI.PropertyField(rect, element); + + if (isFocused) + { + var id = element.objectReferenceValue.GetInstanceID(); + if (id != VRM10SpringBoneCollider.SelectedGuid) + { + VRM10SpringBoneCollider.SelectedGuid = id; + SceneView.RepaintAll(); + EditorUtility.SetDirty(element.objectReferenceValue); + } + } + }; + } + + public void Draw2D(Rect r) + { + Rect layout = default; + (layout, r) = SelectedGUIBase.LayoutLine(r); + EditorGUI.PropertyField(layout, _so.FindProperty("Name")); + + (layout, r) = SelectedGUIBase.LayoutLine(r); + GUI.Label(layout, "colliders"); + _colliderGroupList.DoList(r); + } + + public static void DrawWireCapsule(Vector3 headPos, Vector3 tailPos, float radius) + { + var headToTail = tailPos - headPos; + if (headToTail.sqrMagnitude <= float.Epsilon) + { + Handles.DrawWireDisc(headPos, -SceneView.currentDrawingSceneView.camera.transform.forward, radius); + return; + } + + var forward = headToTail.normalized * radius; + + var xLen = Mathf.Abs(forward.x); + var yLen = Mathf.Abs(forward.y); + var zLen = Mathf.Abs(forward.z); + var rightWorldAxis = (yLen > xLen && yLen > zLen) ? Vector3.right : Vector3.up; + + var up = Vector3.Cross(forward, rightWorldAxis).normalized * radius; + var right = Vector3.Cross(up, forward).normalized * radius; + + const int division = 24; + DrawWireCircle(headPos, up, right, division, division); + DrawWireCircle(headPos, up, -forward, division, division / 2); + DrawWireCircle(headPos, right, -forward, division, division / 2); + + DrawWireCircle(tailPos, up, right, division, division); + DrawWireCircle(tailPos, up, forward, division, division / 2); + DrawWireCircle(tailPos, right, forward, division, division / 2); + + Handles.DrawLine(headPos + right, tailPos + right); + Handles.DrawLine(headPos - right, tailPos - right); + Handles.DrawLine(headPos + up, tailPos + up); + Handles.DrawLine(headPos - up, tailPos - up); + } + + private static void DrawWireCircle(Vector3 centerPos, Vector3 xAxis, Vector3 yAxis, int division, int count) + { + for (var idx = 0; idx < division && idx < count; ++idx) + { + var s = ((idx + 0) % division) / (float)division * Mathf.PI * 2f; + var t = ((idx + 1) % division) / (float)division * Mathf.PI * 2f; + + Gizmos.DrawLine( + centerPos + xAxis * Mathf.Cos(s) + yAxis * Mathf.Sin(s), + centerPos + xAxis * Mathf.Cos(t) + yAxis * Mathf.Sin(t) + ); + } + } + + public void Draw3D() + { + var target = _so.targetObject as VRM10SpringBoneColliderGroup; + + foreach (var c in target.Colliders) + { + Handles.color = c.IsSelected ? Color.red : Color.cyan; + + Matrix4x4 mat = c.transform.localToWorldMatrix; + Handles.matrix = mat * Matrix4x4.Scale(new Vector3( + 1.0f / c.transform.lossyScale.x, + 1.0f / c.transform.lossyScale.y, + 1.0f / c.transform.lossyScale.z + )); + switch (c.ColliderType) + { + case VRM10SpringBoneColliderTypes.Sphere: + Handles.DrawWireDisc(c.Offset, -SceneView.currentDrawingSceneView.camera.transform.forward, c.Radius); + break; + + case VRM10SpringBoneColliderTypes.Capsule: + DrawWireCapsule(c.Offset, c.Tail, c.Radius); + break; + } + + if (c.IsSelected) + { + Handles.color = Color.green; + EditorGUI.BeginChangeCheck(); + Handles.matrix = c.transform.localToWorldMatrix; + var offset = Handles.PositionHandle(c.Offset, Quaternion.identity); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(c, "VRM10SpringBoneCollider"); + c.Offset = offset; + EditorUtility.SetDirty(_so.targetObject); + } + } + } + } + } + + class SelectedSpringGUI : SelectedGUIBase + { + ReorderableList _springColliderGroupList; + ReorderableList _springJointList; + + public SelectedSpringGUI(Vrm10Instance target, SerializedObject so, int i) : base(so, i) + { + Property = so.FindProperty($"SpringBone.Springs.Array.data[{i}]"); + + { + var prop = Property.FindPropertyRelative("ColliderGroups"); + _springColliderGroupList = new ReorderableList(so, prop); + _springColliderGroupList.drawElementCallback = (rect, index, isActive, isFocused) => + { + rect.height -= 4; + rect.y += 2; + + SerializedProperty element = prop.GetArrayElementAtIndex(index); + var elements = target.SpringBone.ColliderGroups; + var element_index = elements.IndexOf(element.objectReferenceValue as VRM10SpringBoneColliderGroup); + var colliderGroups = target.SpringBone.ColliderGroups.Select((x, y) => x.GUIName(y)).ToArray(); + var new_index = EditorGUI.Popup(rect, element_index, colliderGroups); + if (new_index != element_index) + { + element.objectReferenceValue = elements[new_index]; + } + }; + } + + { + var prop = Property.FindPropertyRelative("Joints"); + _springJointList = new ReorderableList(so, prop); + _springJointList.drawElementCallback = (rect, index, isActive, isFocused) => + { + SerializedProperty element = prop.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + EditorGUI.PropertyField(rect, element); + }; + } + } + + public override void Draw2D(Rect r) + { + Rect layout = default; + (layout, r) = LayoutLine(r); + EditorGUI.PropertyField(layout, Property.FindPropertyRelative("Name")); + + var (top, bottom) = LayoutVerticalHalf(r); + + (layout, r) = LayoutLine(top); + GUI.Label(layout, "collider groups"); + _springColliderGroupList.DoList(r); + + (layout, r) = LayoutLine(bottom); + GUI.Label(layout, "joints"); + _springJointList.DoList(r); + } + + public override void Draw3D() + { + + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/SelectedGUI.cs.meta b/Assets/External/VRM10/Editor/Components/SpringBone/SelectedGUI.cs.meta new file mode 100644 index 000000000..8e02b3e70 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/SelectedGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3afd3f6a158933546aa5d979acdf7030 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/SpringBoneTreeView.cs b/Assets/External/VRM10/Editor/Components/SpringBone/SpringBoneTreeView.cs new file mode 100644 index 000000000..03ec1f6d6 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/SpringBoneTreeView.cs @@ -0,0 +1,304 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.IMGUI.Controls; +using UnityEngine; + +namespace UniVRM10 +{ + public class SpringBoneTreeView : TreeView + { + public Vrm10Instance Target { get; private set; } + SerializedObject _so; + + TreeViewItem _root; + TreeViewItem _colliderGroups; + TreeViewItem _springs; + + int _nextNodeID = 0; + + Dictionary _map = new Dictionary(); + + public SpringBoneTreeView(TreeViewState state, Vrm10Instance target, SerializedObject so) : base(state) + { + Target = target; + _so = so; + + _root = new TreeViewItem(_nextNodeID++, -1, "Root"); + var springBone = new TreeViewItem(_nextNodeID++, 0, "SpringBone"); + _root.AddChild(springBone); + + _colliderGroups = new TreeViewItem(_nextNodeID++, 1, "ColliderGroups"); + springBone.AddChild(_colliderGroups); + + _springs = new TreeViewItem(_nextNodeID++, 1, "Springs"); + springBone.AddChild(_springs); + + // load + _map = new Dictionary(); + if (target != null) + { + if (target.SpringBone?.ColliderGroups != null) + { + for (var i = 0; i < target.SpringBone.ColliderGroups.Count; ++i) + { + var colliderGroup = target.SpringBone.ColliderGroups[i]; + var name = colliderGroup.GUIName(i); + var id = _nextNodeID++; + var item = new TreeViewItem(id, 2, name); + _map.Add(id, colliderGroup); + _colliderGroups.AddChild(item); + } + } + + if (target.SpringBone?.Springs != null) + { + for (var i = 0; i < target.SpringBone.Springs.Count; ++i) + { + var spring = target.SpringBone.Springs[i]; + var name = spring.GUIName(i); + var id = _nextNodeID++; + var item = new TreeViewItem(id, 2, name); + _map.Add(id, spring); + _springs.AddChild(item); + } + } + } + } + + protected override TreeViewItem BuildRoot() + { + return _root; + } + + object _selected; + + protected override void SelectionChanged(IList selectedIds) + { + _selected = null; + if (selectedIds.Count > 0 && _map.TryGetValue(selectedIds[0], out object value)) + { + if (value is VRM10SpringBoneColliderGroup colliderGroup) + { + var i = Target.SpringBone.ColliderGroups.IndexOf(colliderGroup); + _selected = new SelectedColliderGroupGUI(_so, i); + } + else if (value is Vrm10InstanceSpringBone.Spring spring) + { + var i = Target.SpringBone.Springs.IndexOf(spring); + _selected = new SelectedSpringGUI(Target, _so, i); + } + } + } + + const int WINDOW_HEIGHT = 500; + const int TREE_WIDTH = 160; + + // | + // left | right + // | + public void Draw2D() + { + var r = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.Height(WINDOW_HEIGHT)); + + // left + OnGUI(new Rect(r.x, r.y, TREE_WIDTH, r.height)); + + // right + if (_selected is SelectedColliderGroupGUI colliderGroup) + { + colliderGroup.Draw2D(new Rect(r.x + TREE_WIDTH, r.y, r.width - TREE_WIDTH, r.height)); + } + else if (_selected is SelectedSpringGUI spring) + { + spring.Draw2D(new Rect(r.x + TREE_WIDTH, r.y, r.width - TREE_WIDTH, r.height)); + } + } + + Color s_selectedColor = new Color(0.5f, 0, 0, 0.5f); + Color s_hoverColor = new Color(0.5f, 0.5f, 0, 0.5f); + Color s_Color = new Color(0.6f, 0.6f, 0.6f, 0.5f); + + Color GetColor(MonoBehaviour target) + { + if (target == Active) + { + return s_selectedColor; + } + if (target == Hover) + { + return s_hoverColor; + } + return s_Color; + } + + Vrm10InstanceSpringBone last = null; + MonoBehaviour Hover = null; + public MonoBehaviour Active = null; + + public bool Draw3D(Vrm10InstanceSpringBone springBone) + { + var lastActive = Active; + var lastHover = Hover; + + if (springBone != last) + { + Active = null; + Hover = null; + last = springBone; + } + + if (_selected is SelectedColliderGroupGUI colliderGroup) + { + // colliderGroup.Draw3D(); + } + else if (_selected is SelectedSpringGUI spring) + { + // TODO + } + + MonoBehaviour newActive = null; + + // + // collider + // + foreach (var group in springBone.ColliderGroups) + { + foreach (var collider in group.Colliders) + { + var color = GetColor(collider); + var (isActive, isHover) = DrawCollider(collider, color); + if (isActive) + { + newActive = collider; + } + if (isHover) + { + Hover = collider; + } + } + } + + // + // joint + // + foreach (var spring in springBone.Springs) + { + VRM10SpringBoneJoint head = null; + for (int i = 0; i < spring.Joints.Count; ++i) + { + var joint = spring.Joints[i]; + var color = GetColor(joint); + var (isActive, isHover) = DrawJoint(joint, color, head); + if (isActive) + { + newActive = joint; + } + if (isHover) + { + Hover = joint; + } + head = joint; + } + } + + if (Active is VRM10SpringBoneCollider activeCollider) + { + // Active な collider の移動ハンドル(Offset, Tail) + EditorGUI.BeginChangeCheck(); + Handles.matrix = activeCollider.transform.localToWorldMatrix; + var offset = Handles.PositionHandle(activeCollider.Offset, Quaternion.identity); + var tail = Vector3.zero; + if (activeCollider.ColliderType == VRM10SpringBoneColliderTypes.Capsule) + { + tail = Handles.PositionHandle(activeCollider.Tail, Quaternion.identity); + } + var offsetChanged = EditorGUI.EndChangeCheck(); + if (offsetChanged) + { + // apply + Undo.RecordObject(activeCollider, "activeCollider"); + activeCollider.Offset = offset; + if (activeCollider.ColliderType == VRM10SpringBoneColliderTypes.Capsule) + { + activeCollider.Tail = tail; + } + } + Handles.matrix = Matrix4x4.identity; + } + + if (newActive != null) + { + Selection.activeObject = newActive.gameObject; + Active = newActive; + } + if (Hover != null) + { + Handles.Label(Hover.transform.position, Hover.name); + } + + return lastActive != Active || lastHover != Hover; + } + + static bool IsLeftDown() + { + return Event.current.type == EventType.MouseDown && Event.current.button == 0; + } + + (bool IsActive, bool IsHover) DrawCollider(VRM10SpringBoneCollider collider, Color color) + { + if (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout) + { + Handles.matrix = collider.transform.localToWorldMatrix; + Handles.color = color; + switch (collider.ColliderType) + { + case VRM10SpringBoneColliderTypes.Sphere: + // Handles.color = Color.magenta; + Handles.SphereHandleCap(collider.GetInstanceID(), collider.Offset, Quaternion.identity, collider.Radius * 2, Event.current.type); + break; + + case VRM10SpringBoneColliderTypes.Capsule: + // Handles.color = Color.cyan; + Handles.SphereHandleCap(collider.GetInstanceID(), collider.Offset, Quaternion.identity, collider.Radius * 2, Event.current.type); + Handles.SphereHandleCap(collider.GetInstanceID(), collider.Tail, Quaternion.identity, collider.Radius * 2, Event.current.type); + Handles.DrawLine(collider.Offset, collider.Tail); + break; + } + Handles.matrix = Matrix4x4.identity; + } + + var isHover = HandleUtility.nearestControl == collider.GetInstanceID(); + return (IsLeftDown() && isHover, isHover); + } + + (bool IsActive, bool IsHover) DrawJoint(VRM10SpringBoneJoint joint, Color color, VRM10SpringBoneJoint head) + { + if (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout) + { + + if (head == null) + { + // 先頭 + Handles.color = color; + Handles.CubeHandleCap(joint.GetInstanceID(), joint.transform.position, joint.transform.rotation, + // head の radius + joint.m_jointRadius, Event.current.type); + } + else + { + // line + Handles.color = Color.green; + Handles.DrawLine(joint.transform.position, head.transform.position); + // joint + Handles.color = color; + Handles.SphereHandleCap(joint.GetInstanceID(), joint.transform.position, joint.transform.rotation, + // head の radius + head.m_jointRadius * 2, Event.current.type); + } + } + + var isHover = HandleUtility.nearestControl == joint.GetInstanceID(); + return (IsLeftDown() && isHover, isHover); + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/SpringBoneTreeView.cs.meta b/Assets/External/VRM10/Editor/Components/SpringBone/SpringBoneTreeView.cs.meta new file mode 100644 index 000000000..026cd2717 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/SpringBoneTreeView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 735a730511f68da4da8d2cf2dcba722e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderEditor.cs b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderEditor.cs new file mode 100644 index 000000000..adb525d6a --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderEditor.cs @@ -0,0 +1,19 @@ +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + [CustomEditor(typeof(VRM10SpringBoneCollider))] + class VRM10SpringBoneColliderEditor : Editor + { + public override void OnInspectorGUI() + { + if (VRM10Window.Active == target) + { + GUI.backgroundColor = Color.cyan; + Repaint(); + } + base.OnInspectorGUI(); + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderEditor.cs.meta b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderEditor.cs.meta new file mode 100644 index 000000000..42024cfa0 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b1b992b7266d6d8429b8aeac90efa6a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderGroupDrawer.cs b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderGroupDrawer.cs new file mode 100644 index 000000000..3159fd8fd --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderGroupDrawer.cs @@ -0,0 +1,22 @@ + +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + [CustomPropertyDrawer(typeof(VRM10SpringBoneColliderGroup))] + public class VRM10SpringBoneColliderGroupDrawer : PropertyDrawer + { + public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) + { + try + { + EditorGUI.ObjectField(rect, property, new GUIContent(((VRM10SpringBoneColliderGroup)property.objectReferenceValue).Name)); + } + catch + { + EditorGUI.ObjectField(rect, property, new GUIContent("fallback")); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderGroupDrawer.cs.meta b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderGroupDrawer.cs.meta new file mode 100644 index 000000000..e144f3f0f --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneColliderGroupDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f5afdd3051fad24e9c7cb8caa29dc7f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs new file mode 100644 index 000000000..5f2e5329e --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs @@ -0,0 +1,99 @@ +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + [CustomEditor(typeof(VRM10SpringBoneJoint))] + [CanEditMultipleObjects] + class VRM10SpringBoneJointEditor : Editor + { + private VRM10SpringBoneJoint m_target; + private SerializedProperty m_stiffnessForceProp; + private SerializedProperty m_gravityPowerProp; + private SerializedProperty m_gravityDirProp; + private SerializedProperty m_dragForceProp; + private SerializedProperty m_jointRadiusProp; + + void OnEnable() + { + if (target == null) + { + return; + } + m_target = (VRM10SpringBoneJoint)target; + + m_stiffnessForceProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_stiffnessForce)); + m_gravityPowerProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_gravityPower)); + m_gravityDirProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_gravityDir)); + m_dragForceProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_dragForce)); + m_jointRadiusProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_jointRadius)); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel); + + LimitBreakSlider(m_stiffnessForceProp, 0.0f, 4.0f, 0.0f, Mathf.Infinity); + LimitBreakSlider(m_gravityPowerProp, 0.0f, 2.0f, 0.0f, Mathf.Infinity); + EditorGUILayout.PropertyField(m_gravityDirProp); + EditorGUILayout.PropertyField(m_dragForceProp); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Collision", EditorStyles.boldLabel); + + LimitBreakSlider(m_jointRadiusProp, 0.0f, 0.5f, 0.0f, Mathf.Infinity); + + serializedObject.ApplyModifiedProperties(); + } + + /// + /// スライダーと数値入力で限界値の違う、所謂「限界突破スライダー」を作成する + /// `EditorGUILayout.PropertyField` の代替として利用する + /// + private static void LimitBreakSlider(SerializedProperty property, float sliderLeft, float sliderRight, float numberLeft, float numberRight) + { + var label = new GUIContent(property.displayName); + var currentValue = property.floatValue; + + var rect = EditorGUILayout.GetControlRect(); + + EditorGUI.BeginProperty(rect, label, property); + + rect = EditorGUI.PrefixLabel(rect, label); + + // slider + { + EditorGUI.BeginChangeCheck(); + + var sliderRect = rect; + sliderRect.width -= 55.0f; + rect.xMin += rect.width - 50.0f; + + var clampedvalue = Mathf.Clamp(currentValue, sliderLeft, sliderRight); + var sliderValue = GUI.HorizontalSlider(sliderRect, clampedvalue, sliderLeft, sliderRight); + + if (EditorGUI.EndChangeCheck()) + { + property.floatValue = sliderValue; + } + } + + // number + { + EditorGUI.BeginChangeCheck(); + + var numberValue = Mathf.Clamp(EditorGUI.FloatField(rect, currentValue), numberLeft, numberRight); + + if (EditorGUI.EndChangeCheck()) + { + property.floatValue = numberValue; + } + } + + EditorGUI.EndProperty(); + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs.meta b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs.meta new file mode 100644 index 000000000..5dba9344a --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb6829ce1ea93194fbd08e175456a797 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/VRM10MetaEditor.cs b/Assets/External/VRM10/Editor/Components/VRM10MetaEditor.cs new file mode 100644 index 000000000..67d442e0e --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/VRM10MetaEditor.cs @@ -0,0 +1,242 @@ +using UniGLTF; +using UniGLTF.M17N; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Editor for VRM10ObjectMeta + /// + public class VRM10MetaEditor : SerializedPropertyEditor + { + SerializedProperty m_thumbnail; + VRM10MetaProperty m_name; + VRM10MetaProperty m_version; + VRM10MetaProperty m_copyright; + VRM10MetaProperty m_authors; + VRM10MetaProperty m_references; + VRM10MetaProperty m_contact; + VRM10MetaProperty m_thirdPartyLicenses; + VRM10MetaProperty m_OtherLicenseUrl; + + SerializedProperty m_AvatarPermission; + SerializedProperty m_ViolentUssage; + SerializedProperty m_SexualUssage; + SerializedProperty m_CommercialUssage; + SerializedProperty m_PoliticalOrReligiousUsage; + SerializedProperty m_AntisocialOrHateUsage; + SerializedProperty m_CreditNotation; + SerializedProperty m_Redistribution; + SerializedProperty m_Modification; + + static string RequiredMessage(string name) + { + switch (LanguageGetter.Lang) + { + case Languages.ja: + return $"必須項目。{name} を入力してください"; + + case Languages.en: + return $"{name} is required"; + + default: + throw new System.NotImplementedException(); + } + } + + enum MessageKeys + { + [LangMsg(Languages.ja, "アバターの人格に関する許諾範囲")] + [LangMsg(Languages.en, "Personation / Characterization Permission")] + PERSONATION, + + [LangMsg(Languages.ja, "アバターに人格を与えることの許諾範囲")] + [LangMsg(Languages.en, "A person who can perform with this avatar")] + ALLOWED_USER, + + [LangMsg(Languages.ja, "このアバターを用いて暴力表現を演じること")] + [LangMsg(Languages.en, "Violent acts using this avatar")] + VIOLENT_USAGE, + + [LangMsg(Languages.ja, "このアバターを用いて性的表現を演じること")] + [LangMsg(Languages.en, "Sexuality acts using this avatar")] + SEXUAL_USAGE, + + [LangMsg(Languages.ja, "商用利用")] + [LangMsg(Languages.en, "For commercial use")] + COMMERCIAL_USAGE, + + [LangMsg(Languages.ja, "政治・宗教用途での利用")] + [LangMsg(Languages.en, "Permits to use this model in political or religious contents")] + POLITICAL_USAGE, + + [LangMsg(Languages.ja, "反社会的・憎悪表現を含むコンテンツでの利用")] + [LangMsg(Languages.en, "Permits to use this model in contents contain anti-social activities or hate speeches")] + ANTI_USAGE, + + [LangMsg(Languages.ja, "再配布・改変に関する許諾範囲")] + [LangMsg(Languages.en, "Redistribution / Modifications License")] + REDISTRIBUTION_MODIFICATIONS, + + [LangMsg(Languages.ja, "クレジット表記")] + [LangMsg(Languages.en, "Forces or abandons to display the credit")] + MOD_CREDIT, + + [LangMsg(Languages.ja, "再配布")] + [LangMsg(Languages.en, "Permits redistribution")] + MOD_REDISTRIBUTION, + + [LangMsg(Languages.ja, "改変")] + [LangMsg(Languages.en, "Controls the condition to modify")] + MOD_MODIFICATION, + + [LangMsg(Languages.ja, "その他のライセンス条件があれば、そのURL")] + [LangMsg(Languages.en, "The URL links of other license")] + MOD_OTHER, + + // [LangMsg(Languages.ja, "")] + // [LangMsg(Languages.en, "")] + } + + static string Msg(MessageKeys key) + { + return LanguageGetter.Msg(key); + } + + bool m_foldoutInfo = true; + bool m_foldoutPermission = true; + bool m_foldoutDistribution = true; + + static (Rect, Rect) FixedRight(Rect r, int width) + { + if (width > r.width) + { + width = (int)r.width; + } + return ( + new Rect(r.x, r.y, r.width - width, r.height), + new Rect(r.x + r.width - width, r.y, width, r.height) + ); + } + + static void RightFixedPropField(SerializedProperty prop, string label) + { + var r = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.Height(EditorGUIUtility.singleLineHeight)); + var (left, right) = FixedRight(r, 64); + // Debug.Log($"{left}, {right}"); + EditorGUI.LabelField(left, label); + EditorGUI.PropertyField(right, prop, new GUIContent(""), false); + } + + private static Texture2D TextureField(string name, Texture2D texture, int size) + { + GUILayout.BeginHorizontal(); + var style = new GUIStyle(GUI.skin.label); + style.alignment = TextAnchor.UpperCenter; + //style.fixedWidth = size; + GUILayout.Label(name, style); + var result = (Texture2D)EditorGUILayout.ObjectField(texture, typeof(Texture2D), false, GUILayout.Width(size), GUILayout.Height(size)); + GUILayout.EndVertical(); + return result; + } + + VRM10MetaProperty CreateValidation(string name, VRM10MetaPropertyValidator validator = null) + { + return new VRM10MetaProperty(m_rootProperty.FindPropertyRelative(name), validator); + } + + public VRM10MetaEditor(SerializedObject serializedObject, SerializedProperty property) : base(serializedObject, property) + { + m_name = CreateValidation(nameof(VRM10ObjectMeta.Name), prop => + { + if (string.IsNullOrEmpty(prop.stringValue)) + { + return (RequiredMessage(prop.name), MessageType.Error); + } + return ("", MessageType.None); + }); + m_version = CreateValidation(nameof(VRM10ObjectMeta.Version)); + m_authors = CreateValidation(nameof(VRM10ObjectMeta.Authors), prop => + { + if (prop.arraySize == 0) + { + return (RequiredMessage(prop.name), MessageType.Error); + } + return ("", MessageType.None); + }); + m_copyright = CreateValidation(nameof(VRM10ObjectMeta.CopyrightInformation)); + m_contact = CreateValidation(nameof(VRM10ObjectMeta.ContactInformation)); + m_references = CreateValidation(nameof(VRM10ObjectMeta.References)); + m_thirdPartyLicenses = CreateValidation(nameof(VRM10ObjectMeta.ThirdPartyLicenses)); + m_OtherLicenseUrl = CreateValidation(nameof(VRM10ObjectMeta.OtherLicenseUrl)); + m_thumbnail = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.Thumbnail)); + // AvatarPermission + m_AvatarPermission = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.AvatarPermission)); + m_ViolentUssage = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.ViolentUsage)); + m_SexualUssage = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.SexualUsage)); + m_CommercialUssage = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.CommercialUsage)); + m_PoliticalOrReligiousUsage = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.PoliticalOrReligiousUsage)); + m_AntisocialOrHateUsage = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.AntisocialOrHateUsage)); + // Mod + m_CreditNotation = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.CreditNotation)); + m_Redistribution = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.Redistribution)); + m_Modification = m_rootProperty.FindPropertyRelative(nameof(VRM10ObjectMeta.Modification)); + + } + + public static VRM10MetaEditor Create(SerializedObject serializedObject) + { + return new VRM10MetaEditor(serializedObject, serializedObject.FindProperty(nameof(VRM10Object.Meta))); + } + + protected override void RecursiveProperty(SerializedProperty root) + { + // texture + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.BeginVertical(); + EditorGUILayout.PropertyField(m_thumbnail); + EditorGUILayout.EndVertical(); + m_thumbnail.objectReferenceValue = TextureField("", (Texture2D)m_thumbnail.objectReferenceValue, 100); + } + EditorGUILayout.EndHorizontal(); + + m_foldoutInfo = EditorGUILayout.Foldout(m_foldoutInfo, "Information"); + if (m_foldoutInfo) + { + m_name.OnGUI(); + m_version.OnGUI(); + m_authors.OnGUI(); + m_copyright.OnGUI(); + m_contact.OnGUI(); + m_references.OnGUI(); + m_thirdPartyLicenses.OnGUI(); + m_OtherLicenseUrl.OnGUI(); + } + + m_foldoutPermission = EditorGUILayout.Foldout(m_foldoutPermission, Msg(MessageKeys.PERSONATION)); + if (m_foldoutPermission) + { + var backup = EditorGUIUtility.labelWidth; + RightFixedPropField(m_AvatarPermission, Msg(MessageKeys.ALLOWED_USER)); + RightFixedPropField(m_ViolentUssage, Msg(MessageKeys.VIOLENT_USAGE)); + RightFixedPropField(m_SexualUssage, Msg(MessageKeys.SEXUAL_USAGE)); + RightFixedPropField(m_CommercialUssage, Msg(MessageKeys.COMMERCIAL_USAGE)); + RightFixedPropField(m_PoliticalOrReligiousUsage, Msg(MessageKeys.POLITICAL_USAGE)); + RightFixedPropField(m_AntisocialOrHateUsage, Msg(MessageKeys.ANTI_USAGE)); + EditorGUIUtility.labelWidth = backup; + } + + m_foldoutDistribution = EditorGUILayout.Foldout(m_foldoutDistribution, Msg(MessageKeys.REDISTRIBUTION_MODIFICATIONS)); + if (m_foldoutDistribution) + { + var backup = EditorGUIUtility.labelWidth; + RightFixedPropField(m_CreditNotation, Msg(MessageKeys.MOD_CREDIT)); + RightFixedPropField(m_Redistribution, Msg(MessageKeys.MOD_REDISTRIBUTION)); + RightFixedPropField(m_Modification, Msg(MessageKeys.MOD_MODIFICATION)); + EditorGUIUtility.labelWidth = backup; + } + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/VRM10MetaEditor.cs.meta b/Assets/External/VRM10/Editor/Components/VRM10MetaEditor.cs.meta new file mode 100644 index 000000000..28bcb0260 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/VRM10MetaEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea2bc7cd57762f747bb03606c307cdcf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/VRM10MetaPropertyValidator.cs b/Assets/External/VRM10/Editor/Components/VRM10MetaPropertyValidator.cs new file mode 100644 index 000000000..d95ebaa71 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/VRM10MetaPropertyValidator.cs @@ -0,0 +1,76 @@ +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + delegate (string, MessageType) VRM10MetaPropertyValidator(SerializedProperty prop); + + class VRM10MetaProperty + { + public SerializedProperty m_prop; + + VRM10MetaPropertyValidator m_validator; + + public VRM10MetaProperty(SerializedProperty prop, + VRM10MetaPropertyValidator validator = null) + { + m_prop = prop; + if (validator == null) + { + // no validation + validator = _ => ("", MessageType.None); + } + m_validator = validator; + } + + public void OnGUI() + { + // var old = m_prop.stringValue; + if (m_prop.propertyType == SerializedPropertyType.Generic) + { + if (m_prop.arrayElementType != null) + { + EditorGUILayout.LabelField(m_prop.name); + + var depth = m_prop.depth; + var iterator = m_prop.Copy(); + var arrayName = iterator.name; + for (var enterChildren = true; iterator.NextVisible(enterChildren); enterChildren = false) + { + if (iterator.depth < depth) + break; + + depth = iterator.depth; + + // using (new EditorGUI.DisabledScope("m_Script" == iterator.propertyPath)) + var match = System.Text.RegularExpressions.Regex.Match(iterator.propertyPath, "\\[(\\d+)\\]$"); + if (match != null && iterator.type == "string") + { + // ArrayItem + // Debug.Log($"{match.Groups[1].Value}"); + iterator.stringValue = EditorGUILayout.TextField($" {arrayName}[{match.Groups[1].Value}]", iterator.stringValue); + } + else + { + EditorGUILayout.PropertyField(iterator, true); + } + } + } + else + { + throw new System.NotImplementedException(); + } + } + else + { + EditorGUILayout.PropertyField(m_prop); + } + var (msg, msgType) = m_validator(m_prop); + if (!string.IsNullOrEmpty(msg)) + { + EditorGUILayout.HelpBox(msg, msgType); + } + // return old != m_prop.stringValue; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Components/VRM10MetaPropertyValidator.cs.meta b/Assets/External/VRM10/Editor/Components/VRM10MetaPropertyValidator.cs.meta new file mode 100644 index 000000000..18e53bdbe --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/VRM10MetaPropertyValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0f1ce72ffff9a9498f2d4f73dd370f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/VRM10ObjectEditor.cs b/Assets/External/VRM10/Editor/Components/VRM10ObjectEditor.cs new file mode 100644 index 000000000..55efce643 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/VRM10ObjectEditor.cs @@ -0,0 +1,92 @@ +using System.Linq; +using UniGLTF; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + [CustomEditor(typeof(VRM10Object))] + public class VRM10ObjectEditor : Editor + { + VRM10Object m_target; + + enum Tabs + { + Meta, + Expression, + LookAt, + FirstPerson, + } + static Tabs _tab = Tabs.Meta; + + // for SerializedProperty + SerializedPropertyEditor m_expression; + SerializedPropertyEditor m_meta; + SerializedPropertyEditor m_lookAt; + SerializedPropertyEditor m_firstPerson; + SerializedProperty m_prefab; + + void OnEnable() + { + if (target == null) + { + return; + } + m_target = (VRM10Object)target; + + m_expression = SerializedPropertyEditor.Create(serializedObject, nameof(m_target.Expression)); + m_meta = VRM10MetaEditor.Create(serializedObject); + m_lookAt = SerializedPropertyEditor.Create(serializedObject, nameof(m_target.LookAt)); + m_firstPerson = SerializedPropertyEditor.Create(serializedObject, nameof(m_target.FirstPerson)); + + m_prefab = serializedObject.FindProperty("m_prefab"); + } + + public override void OnInspectorGUI() + { + // prefab + if (_tab == Tabs.FirstPerson && m_prefab.objectReferenceValue == null) + { + EditorGUILayout.HelpBox("required !", MessageType.Error); + } + serializedObject.Update(); + EditorGUILayout.ObjectField(m_prefab); + serializedObject.ApplyModifiedProperties(); + EditorGUILayout.Separator(); + + // select sub editor + using (new EnabledScope()) + { + _tab = (Tabs)EditorGUILayout.EnumPopup("Select GUI", _tab); + } + EditorGUILayout.Separator(); + + switch (_tab) + { + case Tabs.Meta: + m_meta.OnInspectorGUI(); + break; + + case Tabs.Expression: + m_expression.OnInspectorGUI(); + break; + + case Tabs.LookAt: + m_lookAt.OnInspectorGUI(); + break; + + case Tabs.FirstPerson: + using (new EditorGUI.DisabledScope(m_target.Prefab == null)) + { + if (GUILayout.Button("set default")) + { + m_target.FirstPerson.SetDefault(m_target.Prefab.transform); + } + EditorGUILayout.HelpBox("Clear Renderers and add all renderers (Auto)", MessageType.Info); + } + m_firstPerson.OnInspectorGUI(); + break; + } + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/VRM10ObjectEditor.cs.meta b/Assets/External/VRM10/Editor/Components/VRM10ObjectEditor.cs.meta new file mode 100644 index 000000000..902657937 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/VRM10ObjectEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 545fc17b99797d442a476622ba04f8dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Components/VRM10Window.cs b/Assets/External/VRM10/Editor/Components/VRM10Window.cs new file mode 100644 index 000000000..d9fd1ff62 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/VRM10Window.cs @@ -0,0 +1,155 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// VRM10操作 Window + /// + public class VRM10Window : EditorWindow + { + public const string MENU_NAME = "VRM 1.0 Window"; + + public static VRM10Window Open() + { + var window = (VRM10Window)GetWindow(typeof(VRM10Window)); + window.titleContent = new GUIContent(MENU_NAME); + window.Show(); + window.Root = UnityEditor.Selection.activeTransform?.GetComponent(); + return window; + } + + void OnEnable() + { + // Debug.Log("OnEnable"); + Undo.willFlushUndoRecord += Repaint; + UnityEditor.Selection.selectionChanged += Repaint; + + SceneView.duringSceneGui += OnSceneGUI; + } + + void OnDisable() + { + s_treeView = null; + + SceneView.duringSceneGui -= OnSceneGUI; + // Debug.Log("OnDisable"); + UnityEditor.Selection.selectionChanged -= Repaint; + Undo.willFlushUndoRecord -= Repaint; + + Tools.hidden = false; + } + + SerializedObject m_so; + int? m_root; + Vrm10Instance Root + { + get => m_root.HasValue ? (EditorUtility.InstanceIDToObject(m_root.Value) as Vrm10Instance) : null; + set + { + int? id = value != null ? value.GetInstanceID() : default; + if (m_root == id) + { + return; + } + if (value != null && !value.gameObject.scene.IsValid()) + { + // skip prefab + return; + } + m_root = id; + m_so = value != null ? new SerializedObject(value) : null; + } + } + + /// + /// Scene 上の 3D 表示 + /// + /// * Joint/Collider の Picker + /// + /// + void OnSceneGUI(SceneView sceneView) + { + Tools.hidden = true; + Draw3D(Root, m_so); + } + + /// + /// Window 上の GUI + /// + /// * 対象 VRM の保持 + /// * 選択 Joint/Collider の表示 + /// + /// + private void OnGUI() + { + if (Root == null) + { + if (UnityEditor.Selection.activeTransform != null) + { + var root = UnityEditor.Selection.activeTransform.Ancestors().Select(x => x.GetComponent()).FirstOrDefault(x => x != null); + if (root != null) + { + Root = root; + } + } + } + + // Root + Root = (Vrm10Instance)EditorGUILayout.ObjectField("Editing Model", Root, typeof(Vrm10Instance), true); + if (Root == null) + { + return; + } + + // active + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.ObjectField("Selected Object", Active, typeof(MonoBehaviour), true); + EditorGUI.EndDisabledGroup(); + + // if (m_so == null) + // { + // m_so = new SerializedObject(Root); + // } + // if (m_so == null) + // { + // return; + // } + // m_so.Update(); + // SpringBoneEditor.Draw2D(Root, m_so); + // m_so.ApplyModifiedProperties(); + } + + SpringBoneTreeView s_treeView; + SpringBoneTreeView GetTree(Vrm10Instance target, SerializedObject so) + { + if (s_treeView == null || s_treeView.Target != target) + { + var state = new UnityEditor.IMGUI.Controls.TreeViewState(); + s_treeView = new SpringBoneTreeView(state, target, so); + s_treeView.Reload(); + } + return s_treeView; + } + + public static MonoBehaviour Active; + + /// + /// 3D の Handle 描画 + /// + public void Draw3D(Vrm10Instance target, SerializedObject so) + { + var tree = GetTree(target, so); + if (tree != null && target != null) + { + if (tree.Draw3D(target.SpringBone)) + { + Repaint(); + } + Active = tree.Active; + } + } + } +} diff --git a/Assets/External/VRM10/Editor/Components/VRM10Window.cs.meta b/Assets/External/VRM10/Editor/Components/VRM10Window.cs.meta new file mode 100644 index 000000000..1f7d77ff2 --- /dev/null +++ b/Assets/External/VRM10/Editor/Components/VRM10Window.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d10db1ad6a9273e4698465a666033569 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/EditorTool.meta b/Assets/External/VRM10/Editor/EditorTool.meta new file mode 100644 index 000000000..d950d90b8 --- /dev/null +++ b/Assets/External/VRM10/Editor/EditorTool.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af5da07aebd9a47428d49b56b245b095 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/EditorTool/VRM10BoneSelectorEditorTool.cs b/Assets/External/VRM10/Editor/EditorTool/VRM10BoneSelectorEditorTool.cs new file mode 100644 index 000000000..77e582799 --- /dev/null +++ b/Assets/External/VRM10/Editor/EditorTool/VRM10BoneSelectorEditorTool.cs @@ -0,0 +1,128 @@ +using UnityEngine; +using UnityEditor; +using UnityEditor.EditorTools; +using UniGLTF; + +#if UNITY_2021_OR_NEWER +#else +using ToolManager = UnityEditor.EditorTools.EditorTools; +#endif + +namespace UniVRM10 +{ + /// + /// Bone Selector + /// + [EditorTool("vrm-1.0/Humanoid", typeof(UniVRM10.Vrm10Instance))] + public class VRM10BoneSelectorEditorTool : EditorTool + { + static GUIContent s_cachedIcon; + public override GUIContent toolbarIcon + { + get + { + if (s_cachedIcon == null) + { + s_cachedIcon = EditorGUIUtility.IconContent("AvatarSelector@2x", "|vrm-1.0 Humanoid"); + } + return s_cachedIcon; + } + } + + BoneSelector _impl; + void OnEnable() + { + ToolManager.activeToolChanged += ActiveToolDidChange; + if (SceneView.lastActiveSceneView?.camera) + { + } + } + + void OnDisable() + { + ToolManager.activeToolChanged -= ActiveToolDidChange; + if (_impl != null) + { + _impl.Dispose(); + _impl = null; + } + } + + void ActiveToolDidChange() + { + if (ToolManager.IsActiveTool(this)) + { + } + else + { + if (_impl != null) + { + _impl.Dispose(); + _impl = null; + } + } + } + + public override void OnToolGUI(EditorWindow window) + { + if (_impl == null) + { + _impl = new BoneSelector(SceneView.lastActiveSceneView.camera); + } + + var root = Selection.activeGameObject?.GetComponent(); + if (root == null) + { + return; + } + _impl.SetTarget(root.gameObject); + if (Event.current.type == EventType.Repaint) + { + _impl.Draw(); + } + + // bone manipulator + var selected = _impl.SelectedBoneInfo; + bool selector = true; + if (selected != null) + { + EditorGUI.BeginChangeCheck(); + Quaternion rot = Handles.RotationHandle(selected.HeadObject.transform.rotation, selected.HeadObject.transform.position); + // Debug.Log($"{selected}"); + if (EditorGUI.EndChangeCheck()) + { + // UNDO + Undo.RecordObject(selected.HeadObject.transform, "bone rotation"); + + // apply + selected.HeadObject.transform.rotation = rot; + selector = false; + } + } + + if (selector) + { + if (Event.current.type == EventType.MouseDown && Event.current.button == 0) + { + // 回転ギズモがなんもしなかった + // selector + Vector2 mousePosition = Event.current.mousePosition; + Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition); + Event e = Event.current; + _impl.IntersectBone(ray); + } + else if (Event.current.type == EventType.MouseMove) + { + // hover + Vector2 mousePosition = Event.current.mousePosition; + Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition); + Event e = Event.current; + _impl.IntersectBone(ray, true); + } + } + + // disable sceneView select + HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive)); + } + } +} diff --git a/Assets/External/VRM10/Editor/EditorTool/VRM10BoneSelectorEditorTool.cs.meta b/Assets/External/VRM10/Editor/EditorTool/VRM10BoneSelectorEditorTool.cs.meta new file mode 100644 index 000000000..495efd4a9 --- /dev/null +++ b/Assets/External/VRM10/Editor/EditorTool/VRM10BoneSelectorEditorTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9da1932d34ba48e45a409547a0ad30bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs b/Assets/External/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs new file mode 100644 index 000000000..296cad655 --- /dev/null +++ b/Assets/External/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.EditorTools; +using UnityEngine; + +#if UNITY_2021_OR_NEWER +#else +using ToolManager = UnityEditor.EditorTools.EditorTools; +#endif + +namespace UniVRM10 +{ + [EditorTool("vrm-1.0/Expression", typeof(UniVRM10.Vrm10Instance))] + class VRM10ExpressionEditorTool : EditorTool + { + static GUIContent s_cachedIcon; + public override GUIContent toolbarIcon + { + get + { + if (s_cachedIcon == null) + { + s_cachedIcon = EditorGUIUtility.IconContent("d_Audio Mixer@2x", "|vrm-1.0 Expression"); + } + return s_cachedIcon; + } + } + + void OnEnable() + { + ToolManager.activeToolChanged += ActiveToolDidChange; + } + + void OnDisable() + { + ToolManager.activeToolChanged -= ActiveToolDidChange; + } + + void ActiveToolDidChange() + { + if (!ToolManager.IsActiveTool(this)) + { + return; + } + } + + public override void OnToolGUI(EditorWindow window) + { + if (Selection.activeTransform == null) + { + return; + } + var root = Selection.activeTransform.GetComponent(); + if (root == null) + { + return; + } + + Handles.BeginGUI(); + if (Application.isPlaying) + { + ExpressionPreviewInPlay(root?.Vrm?.Expression, root?.Runtime.Expression); + } + else + { + EditorGUILayout.HelpBox("expression preview in play mode", MessageType.Warning); + } + Handles.EndGUI(); + } + + void ExpressionPreviewInPlay(VRM10ObjectExpression expression, Vrm10RuntimeExpression runtime) + { + if (expression == null) + { + EditorGUILayout.HelpBox("no expression settings", MessageType.Warning); + return; + } + + EditorGUILayout.BeginHorizontal(); + { + GUILayout.FlexibleSpace(); + + // 右よせ + EditorGUILayout.BeginVertical(); + { + GUILayout.FlexibleSpace(); + + m_map.Clear(); + foreach (var kv in runtime.GetWeights()) + { + var key = kv.Key; + var value = ExpressionSlider(key, kv.Value); + m_map[key] = value; + } + GUILayout.FlexibleSpace(); + + runtime.SetWeights(m_map); + } + EditorGUILayout.EndVertical(); + } + EditorGUILayout.EndHorizontal(); + } + + Dictionary m_map = new Dictionary(); + static GUIStyle s_style; + static GUIStyle Style + { + get + { + if (s_style == null) + { + s_style = GUI.skin.GetStyle("box"); + } + return s_style; + } + } + + float ExpressionSlider(ExpressionKey key, float value) + { + EditorGUILayout.BeginHorizontal(Style); + EditorGUILayout.LabelField(key.ToString()); + value = EditorGUILayout.Slider(value, 0, 1.0f); + EditorGUILayout.EndHorizontal(); + return value; + } + } +} diff --git a/Assets/External/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs.meta b/Assets/External/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs.meta new file mode 100644 index 000000000..bf85ab840 --- /dev/null +++ b/Assets/External/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eae44b522daec4846a8f06f739ad2253 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs b/Assets/External/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs new file mode 100644 index 000000000..b98e66db3 --- /dev/null +++ b/Assets/External/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs @@ -0,0 +1,175 @@ +using UnityEngine; +using UnityEditor; +using UnityEditor.EditorTools; + +#if UNITY_2021_OR_NEWER +#else +using ToolManager = UnityEditor.EditorTools.EditorTools; +#endif + + +namespace UniVRM10 +{ + [EditorTool("vrm-1.0/LookAt", typeof(UniVRM10.Vrm10Instance))] + class VRM10LookAtEditorTool : EditorTool + { + static GUIContent s_cachedIcon; + public override GUIContent toolbarIcon + { + get + { + if (s_cachedIcon == null) + { + s_cachedIcon = EditorGUIUtility.IconContent("d_BillboardRenderer Icon", "|vrm-1.0 LookAt"); + } + return s_cachedIcon; + } + } + + void OnEnable() + { + ToolManager.activeToolChanged += ActiveToolDidChange; + } + + void OnDisable() + { + ToolManager.activeToolChanged -= ActiveToolDidChange; + } + + void ActiveToolDidChange() + { + if (!ToolManager.IsActiveTool(this)) + { + return; + } + } + + public override void OnToolGUI(EditorWindow window) + { + if(Selection.activeTransform==null) + { + return; + } + var root = Selection.activeTransform.GetComponent(); + if (root == null) + { + return; + } + if (!root.DrawLookAtGizmo) + { + return; + } + var humanoid = root.GetComponent(); + var head = humanoid.Head; + if (head == null) + { + return; + } + + { + EditorGUI.BeginChangeCheck(); + + var eyeWorldPosition = head.localToWorldMatrix.MultiplyPoint(root.Vrm.LookAt.OffsetFromHead); + eyeWorldPosition = Handles.PositionHandle(eyeWorldPosition, head.rotation); + + Handles.DrawDottedLine(head.position, eyeWorldPosition, 5); + Handles.SphereHandleCap(0, head.position, Quaternion.identity, 0.02f, Event.current.type); + Handles.SphereHandleCap(0, eyeWorldPosition, Quaternion.identity, 0.02f, Event.current.type); + + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(root.Vrm, "LookAt.OffsetFromHead"); + + root.Vrm.LookAt.OffsetFromHead = head.worldToLocalMatrix.MultiplyPoint(eyeWorldPosition); + } + } + + if (Application.isPlaying) + { + OnSceneGUILookAt(root.Vrm.LookAt, root.Runtime.LookAt, root.LookAtTargetType, root.LookAtTarget); + } + else + { + // offset + var p = root.Vrm.LookAt.OffsetFromHead; + Handles.Label(head.position, $"fromHead: [{p.x:0.00}, {p.y:0.00}, {p.z:0.00}]"); + } + } + + #region Gizmo + static void DrawMatrix(Matrix4x4 m, float size) + { + Gizmos.matrix = m; + Gizmos.color = Color.red; + Gizmos.DrawLine(Vector3.zero, Vector3.right * size); + Gizmos.color = Color.green; + Gizmos.DrawLine(Vector3.zero, Vector3.up * size); + Gizmos.color = Color.blue; + Gizmos.DrawLine(Vector3.zero, Vector3.forward * size); + } + + const float LOOKAT_GIZMO_SIZE = 0.5f; + + // private void OnDrawGizmos() + // { + // if (DrawGizmo) + // { + // if (m_leftEye != null & m_rightEye != null) + // { + // DrawMatrix(m_leftEye.localToWorldMatrix, LOOKAT_GIZMO_SIZE); + // DrawMatrix(m_rightEye.localToWorldMatrix, LOOKAT_GIZMO_SIZE); + // } + // } + // } + #endregion + + const float RADIUS = 0.5f; + + static void OnSceneGUILookAt(VRM10ObjectLookAt lookAt, Vrm10RuntimeLookAt runtime, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform lookAtTarget) + { + if (lookAtTargetType == VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform && lookAtTarget != null) + { + { + EditorGUI.BeginChangeCheck(); + var newTargetPosition = Handles.PositionHandle(lookAtTarget.position, Quaternion.identity); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(lookAtTarget, "Change Look At Target Position"); + lookAtTarget.position = newTargetPosition; + } + } + + Handles.color = new Color(1, 1, 1, 0.6f); + Handles.DrawDottedLine(runtime.LookAtOriginTransform.position, lookAtTarget.position, 4.0f); + } + + var yaw = runtime.Yaw; + var pitch = runtime.Pitch; + var lookAtOriginMatrix = runtime.LookAtOriginTransform.localToWorldMatrix; + Handles.matrix = lookAtOriginMatrix; + var p = lookAt.OffsetFromHead; + Handles.Label(Vector3.zero, + $"FromHead: [{p.x:0.00}, {p.y:0.00}, {p.z:0.00}]\nYaw: {yaw:0.}degree\nPitch: {pitch:0.}degree"); + + Handles.color = new Color(0, 1, 0, 0.2f); + Handles.DrawSolidArc(Vector3.zero, + Matrix4x4.identity.GetColumn(1), + Matrix4x4.identity.GetColumn(2), + yaw, + RADIUS); + + + var yawQ = Quaternion.AngleAxis(yaw, Vector3.up); + var yawMatrix = default(Matrix4x4); + yawMatrix.SetTRS(Vector3.zero, yawQ, Vector3.one); + + Handles.matrix = lookAtOriginMatrix * yawMatrix; + Handles.color = new Color(1, 0, 0, 0.2f); + Handles.DrawSolidArc(Vector3.zero, + Matrix4x4.identity.GetColumn(0), + Matrix4x4.identity.GetColumn(2), + -pitch, + RADIUS); + } + } +} diff --git a/Assets/External/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs.meta b/Assets/External/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs.meta new file mode 100644 index 000000000..9f4ef9e90 --- /dev/null +++ b/Assets/External/VRM10/Editor/EditorTool/VRM10LookAtEditorTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a780c0aef1cdb9a4895e352e39ad40b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/EnumFlagAttributeDrawer.cs b/Assets/External/VRM10/Editor/EnumFlagAttributeDrawer.cs new file mode 100644 index 000000000..8f7ba6e5c --- /dev/null +++ b/Assets/External/VRM10/Editor/EnumFlagAttributeDrawer.cs @@ -0,0 +1,64 @@ +using System; +using UnityEngine; +using UnityEditor; + +namespace UniVRM10 +{ + /// + /// Flag設定したEnumのインスペクター表示を変えるクラス + /// + [CustomPropertyDrawer(typeof(EnumFlagsAttribute))] + public sealed class EnumFlagsAttributeDrawer : PropertyDrawer + { + public override void OnGUI( + Rect position, + SerializedProperty prop, + GUIContent label + ) + { + var buttonsIntValue = 0; + var enumLength = prop.enumNames.Length; + var labelWidth = EditorGUIUtility.labelWidth; + var buttonPressed = new bool[enumLength]; + var buttonWidth = (position.width - labelWidth) / enumLength; + + var labelPos = new Rect( + position.x, + position.y, + labelWidth, + position.height + ); + EditorGUI.LabelField(labelPos, label); + EditorGUI.BeginChangeCheck(); + + for (int i = 0; i < enumLength; i++) + { + buttonPressed[i] = (prop.intValue & (1 << i)) == 1 << i; + + var buttonPos = new Rect( + position.x + labelWidth + buttonWidth * i, + position.y, + buttonWidth, + position.height + ); + + buttonPressed[i] = GUI.Toggle( + buttonPos, + buttonPressed[i], + prop.enumNames[i], + "Button" + ); + + if (buttonPressed[i]) + { + buttonsIntValue += 1 << i; + } + } + + if (EditorGUI.EndChangeCheck()) + { + prop.intValue = buttonsIntValue; + } + } + } +} diff --git a/Assets/External/VRM10/Editor/EnumFlagAttributeDrawer.cs.meta b/Assets/External/VRM10/Editor/EnumFlagAttributeDrawer.cs.meta new file mode 100644 index 000000000..3ea85c8eb --- /dev/null +++ b/Assets/External/VRM10/Editor/EnumFlagAttributeDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62a17679a0c7f7843beaa97ae4121d63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/MeshUtility.meta b/Assets/External/VRM10/Editor/MeshUtility.meta new file mode 100644 index 000000000..a7f3f27f4 --- /dev/null +++ b/Assets/External/VRM10/Editor/MeshUtility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6fb2795d5ca5ce9449de94ea5fb94dde +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs b/Assets/External/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs new file mode 100644 index 000000000..e4c1c6ff2 --- /dev/null +++ b/Assets/External/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF.MeshUtility; +using UnityEditor; +using UnityEngine; + + +namespace UniVRM10 +{ + public class Vrm10ExpressionUpdater + { + // BlendShapeBinding.RelativePath からの逆引き + Dictionary> _rendererPathMap = new(); + GameObject _root; + + Vrm10ExpressionUpdater(GameObject root, List results) + { + _root = root; + foreach (var result in results) + { + foreach (var x in result.SourceSkinnedMeshRenderers) + { + var srcPath = x.transform.RelativePathFrom(root.transform); + if (_rendererPathMap.TryGetValue(srcPath, out var value)) + { + value.Add(result); + } + else + { + value = new List(); + value.Add(result); + _rendererPathMap.Add(srcPath, value); + } + } + } + } + + // 分割されて増える => 増えない BlendShape のある方にいく + // 統合されて減る => 名前が同じものが統合される + IEnumerable ReplaceBlendShapeBinding(IEnumerable values) + { + var used = new HashSet(); + foreach (var val in values) + { + if (_rendererPathMap.TryGetValue(val.RelativePath, out var results)) + { + foreach (var result in results) + { + if (result.Integrated == null) + { + continue; + } + var name = result.Integrated.Mesh.GetBlendShapeName(val.Index); + var newIndex = result.Integrated.Mesh.GetBlendShapeIndex(name); + if (newIndex == -1) + { + throw new KeyNotFoundException($"blendshape:{name} not found"); + } + + var dstPath = result.Integrated.IntegratedRenderer.transform.RelativePathFrom(_root.transform); + var binding = new MorphTargetBinding + { + RelativePath = dstPath, + Index = newIndex, + Weight = val.Weight, + }; + if (used.Contains(binding)) + { + Debug.LogWarning($"duplicated: {binding}"); + } + else + { + if (VRMShaders.Symbols.VRM_DEVELOP) + { + Debug.Log($"{val} >> {binding}"); + } + used.Add(binding); + yield return binding; + } + } + } + else + { + // skip + Debug.LogWarning($"SkinnedMeshRenderer not found: {val.RelativePath}"); + } + } + } + + public static Dictionary Update(string assetFolder, GameObject instance, + List results) + { + var vrm = instance.GetComponent(); + var util = new Vrm10ExpressionUpdater(instance, results); + + // write Vrm10Expressions + var copyMap = new Dictionary(); + foreach (var (preset, clip) in vrm.Vrm.Expression.Clips) + { + var copy = ScriptableObject.Instantiate(clip); + copy.MorphTargetBindings = util.ReplaceBlendShapeBinding(clip.MorphTargetBindings).ToArray(); + var assetPath = $"{assetFolder}/{copy.name}.asset"; + AssetDatabase.CreateAsset(copy, assetPath); + copyMap.Add(clip, copy); + } + + // write Vrm10Object + { + var copy = ScriptableObject.Instantiate(vrm.Vrm); + var assetPath = $"{assetFolder}/{copy.name}.asset"; + copy.Expression.Replace(copyMap); + AssetDatabase.CreateAsset(copy, assetPath); + vrm.Vrm = copy; + } + + return copyMap; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs.meta b/Assets/External/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs.meta new file mode 100644 index 000000000..4f97c265e --- /dev/null +++ b/Assets/External/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d74b29fa7bb59ae4a9f641bf16468848 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs b/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs new file mode 100644 index 000000000..4bee935da --- /dev/null +++ b/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs @@ -0,0 +1,15 @@ +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + class Vrm10MeshIntegrationTab : UniGLTF.MeshUtility.MeshIntegrationTab + { + Vrm10MeshUtility _vrmMeshUtil; + + public Vrm10MeshIntegrationTab(EditorWindow editor, Vrm10MeshUtility meshUtility) : base(editor, meshUtility) + { + _vrmMeshUtil = meshUtility; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs.meta b/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs.meta new file mode 100644 index 000000000..078ce5177 --- /dev/null +++ b/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec2a4df10a08bab4a980b7203d341bda +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs b/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs new file mode 100644 index 000000000..e96caf019 --- /dev/null +++ b/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs @@ -0,0 +1,140 @@ +using UnityEngine; +using UnityEditor; +using UniGLTF; +using UniGLTF.M17N; +using System.Collections.Generic; +using System.Linq; + + +namespace UniVRM10 +{ + public class Vrm10MeshUtilityDialog : UniGLTF.MeshUtility.MeshUtilityDialog + { + public new const string MENU_NAME = "VRM 1.0 MeshUtility"; + public new static void OpenWindow() + { + var window = + (Vrm10MeshUtilityDialog)EditorWindow.GetWindow(typeof(Vrm10MeshUtilityDialog)); + window.titleContent = new GUIContent(MENU_NAME); + window.Show(); + } + protected override void Validate() + { + base.Validate(); + if (_exportTarget.GetComponent() == null) + { + _validations.Add(Validation.Error("target is not vrm1")); + return; + } + } + + Vrm10MeshUtility _meshUtil; + Vrm10MeshUtility Vrm10MeshUtility + { + get + { + if (_meshUtil == null) + { + _meshUtil = new Vrm10MeshUtility(); + } + return _meshUtil; + } + } + protected override UniGLTF.MeshUtility.GltfMeshUtility MeshUtility => Vrm10MeshUtility; + + Vrm10MeshIntegrationTab _integrationTab; + protected override UniGLTF.MeshUtility.MeshIntegrationTab MeshIntegration + { + get + { + if (_integrationTab == null) + { + _integrationTab = new Vrm10MeshIntegrationTab(this, Vrm10MeshUtility); + } + return _integrationTab; + } + } + + protected override bool MeshIntegrateGui() + { + var firstPerson = ToggleIsModified("FirstPerson == AUTO の生成", ref MeshUtility.GenerateMeshForFirstPersonAuto); + var mod = base.MeshIntegrateGui(); + return firstPerson || mod; + } + + List _clips; + protected override void WriteAssets(string assetFolder, GameObject instance, + List results) + { + _clips = Vrm10ExpressionUpdater.Update(assetFolder, instance, results).Values.ToList(); + + // write mesh + base.WriteAssets(assetFolder, instance, results); + } + + protected override string WritePrefab(string assetFolder, + GameObject instance) + { + var prefabPath = base.WritePrefab(assetFolder, instance); + + // PostProcess + // update prefab reference of BlendShapeClip + var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); + foreach (var clip in _clips) + { + var so = new SerializedObject(clip); + so.Update(); + var prop = so.FindProperty("m_prefab"); + prop.objectReferenceValue = prefabReference; + so.ApplyModifiedProperties(); + } + + return prefabPath; + } + + protected override void DialogMessage() + { + EditorGUILayout.HelpBox(Message.MESH_UTILITY.Msg(), MessageType.Info); + } + enum Message + { + [LangMsg(Languages.ja, @"(VRM-1.0専用) 凍結 > 統合 > 分割 という一連の処理を実行します。 + +[凍結] +- ヒエラルキーの 回転・拡縮を Mesh に焼き付けます。 +- BlendShape の現状を Mesh に焼き付けます。 + +- VRM-1.0 では正規化は必須でなくなりました。任意のオプションです。 +- VRM-1.0 でも拡縮の凍結は推奨しています。 +- HumanoidAvatar の再生成。 +- Expression, SpringBone, Constraint なども影響を受けます。 + +[統合] +- ヒエラルキーに含まれる MeshRenderer と SkinnedMeshRenderer をひとつの SkinnedMeshRenderer に統合します。 + +- VRM の FirstPerson 設定に応じて3種類(BOTH, FirstPerson, ThirdPerson) にグループ化して統合します。 +- FirstPerson=AUTO を前処理できます。 + - 元の Mesh は ThirdPerson として処理されます。頭なしのモデルを追加生成して FirstPersonOnly とします。 + +[分割] +- 統合結果を BlendShape の有無を基準に分割します。 +- BOTH, FirstPerson, ThirdPerson x 2 で、最大で 6Mesh になります。空の部分ができることが多いので 3Mesh くらいが多くなります。 + +[Scene と Prefab] +Scene と Prefab で挙動が異なります。 + +(Scene/Runtime) +- 対象のヒエラルキーを変更します。UNDO可能。 +- Asset の書き出しはしません。Unityを再起動すると、書き出していない Mesh などの Asset が消滅します。 + +(Prefab/Editor) +- 対象の prefab をシーンにコピーして処理を実行し、生成する Asset を指定されたフォルダに書き出します。 +- Asset 書き出し後にコピーを削除します。 +- Undo はありません。 +")] + [LangMsg(Languages.en, @"TODO +")] + MESH_UTILITY, + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs.meta b/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs.meta new file mode 100644 index 000000000..829b51745 --- /dev/null +++ b/Assets/External/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f3af8a1b265d8a4da7ad8c1c29d2585 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/PackageResource.cs b/Assets/External/VRM10/Editor/PackageResource.cs new file mode 100644 index 000000000..5e9a187e2 --- /dev/null +++ b/Assets/External/VRM10/Editor/PackageResource.cs @@ -0,0 +1,44 @@ +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// + /// + public static class PackageResource + { + /// + /// Local時のAssetPath + /// + public const string LocalBase = "Assets/VRM10"; + + /// + /// UPM参照時のAssetPath + /// + public const string PackageBase = "Packages/com.vrmc.univrm"; + + /// + /// Try local then try package. + /// + /// + /// + /// + public static T ResourceLocalOrUPM(string relpath) where T : UnityEngine.Object + { + var path = $"{LocalBase}/{relpath}"; + var asset = AssetDatabase.LoadAssetAtPath(path); + if (asset is null) + { + // Debug.LogWarning($"fail to LoadAssetAtPath: {path}"); + path = $"{PackageResource.PackageBase}/{relpath}"; + asset = AssetDatabase.LoadAssetAtPath(path); + } + // if (asset is null) + // { + // Debug.LogWarning($"fail to LoadAssetAtPath: {path}"); + // } + return asset; + } + } +} diff --git a/Assets/External/VRM10/Editor/PackageResource.cs.meta b/Assets/External/VRM10/Editor/PackageResource.cs.meta new file mode 100644 index 000000000..f6b7d3266 --- /dev/null +++ b/Assets/External/VRM10/Editor/PackageResource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d0de6998a8026c4ca69e7a146b135f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/ScriptedImporter.meta b/Assets/External/VRM10/Editor/ScriptedImporter.meta new file mode 100644 index 000000000..c768d831b --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ac495244a4434c741850fb75768d4ef9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/ScriptedImporter/RemapEditorVrm.cs b/Assets/External/VRM10/Editor/ScriptedImporter/RemapEditorVrm.cs new file mode 100644 index 000000000..9093b11b8 --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter/RemapEditorVrm.cs @@ -0,0 +1,89 @@ +using UniGLTF; +using UnityEngine; +using System.Linq; +using UnityEditor; +using VRMShaders; +using System.Collections.Generic; +#if UNITY_2020_2_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif + + +namespace UniVRM10 +{ + public class RemapEditorVrm : RemapEditorBase + { + public RemapEditorVrm(IEnumerable keys, EditorMapGetterFunc getter, EditorMapSetterFunc setter) : base(keys, getter, setter) + { } + + public void OnGUI(ScriptedImporter importer, GltfData data, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm) + { + if (CanExtract(importer)) + { + if (GUILayout.Button("Extract Meta And Expressions ...")) + { + Extract(importer, data); + } + EditorGUILayout.HelpBox("Extract subasset to external object and overwrite remap", MessageType.Info); + } + else + { + if (GUILayout.Button("Clear extraction")) + { + ClearExternalObjects(importer, typeof(VRM10Object), typeof(VRM10Expression)); + } + EditorGUILayout.HelpBox("Clear remap. All remap use subAsset", MessageType.Info); + } + + DrawRemapGUI(importer.GetExternalObjectMap()); + DrawRemapGUI(importer.GetExternalObjectMap()); + } + + /// + /// + /// * VRM10Object + /// * VRM10Expression[] + /// + /// が Extract 対象となる + /// + /// + public static void Extract(ScriptedImporter importer, GltfData data) + { + if (string.IsNullOrEmpty(importer.assetPath)) + { + return; + } + + var path = GetAndCreateFolder(importer.assetPath, ".vrm1.Assets"); + + var assets = AssetDatabase.LoadAllAssetsAtPath(importer.assetPath); + var prefab = assets.First(x => x is GameObject) as GameObject; + + // expression を extract し置き換え map を作る + var map = new Dictionary(); + foreach (var asset in assets) + { + if (asset is VRM10Expression expression) + { + // preview用のprefab + expression.Prefab = prefab; + + var clone = ExtractSubAsset(asset, $"{path}/{asset.name}.asset", false); + map.Add(expression, clone as VRM10Expression); + } + } + + // vrmObject の expression を置き換える + var vrmObject = AssetDatabase.LoadAllAssetsAtPath(importer.assetPath).First(x => x is VRM10Object) as VRM10Object; + vrmObject.Expression.Replace(map); + vrmObject.Prefab = prefab; // for FirstPerson Editor + + // extract + ExtractSubAsset(vrmObject, $"{path}/{vrmObject.name}.asset", false); + + AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate); + } + } +} diff --git a/Assets/External/VRM10/Editor/ScriptedImporter/RemapEditorVrm.cs.meta b/Assets/External/VRM10/Editor/ScriptedImporter/RemapEditorVrm.cs.meta new file mode 100644 index 000000000..d6df07649 --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter/RemapEditorVrm.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d312fe4d8589d4d4a99768165d55f1b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs new file mode 100644 index 000000000..be82aec15 --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs @@ -0,0 +1,37 @@ +using UnityEngine; +#if UNITY_2020_2_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif + + +namespace UniVRM10 +{ + [ScriptedImporter(1, "vrm")] + public class VrmScriptedImporter : ScriptedImporter + { + [SerializeField] + public bool MigrateToVrm1 = default; + + [SerializeField] + public UniGLTF.RenderPipelineTypes RenderPipeline = default; + + public override void OnImportAsset(AssetImportContext ctx) + { + VrmScriptedImporterImpl.Import(this, ctx, MigrateToVrm1, RenderPipeline); + } + + void OnValidate() + { + if (RenderPipeline == UniGLTF.RenderPipelineTypes.UniversalRenderPipeline) + { + if (Shader.Find(UniGLTF.UrpGltfPbrMaterialImporter.ShaderName) == null) + { + Debug.LogWarning("URP is not installed. Force to BuiltinRenderPipeline"); + RenderPipeline = UniGLTF.RenderPipelineTypes.BuiltinRenderPipeline; + } + } + } + } +} diff --git a/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs.meta b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs.meta new file mode 100644 index 000000000..3d076041d --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f66ead3390398f443aa127b741826ad9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs new file mode 100644 index 000000000..cf7d530c5 --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs @@ -0,0 +1,187 @@ +using UnityEditor; +using UnityEngine; +using UniGLTF; +using System.IO; +using UniGLTF.MeshUtility; +using System.Linq; +using System.Collections.Generic; +using VRMShaders; +#if UNITY_2020_2_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif + + +namespace UniVRM10 +{ + [CustomEditor(typeof(VrmScriptedImporter))] + public class VrmScriptedImporterEditorGUI : RemapScriptedImporterEditorBase + { + VrmLib.Model m_model; + + RemapEditorMaterial m_materialEditor; + RemapEditorVrm m_vrmEditor; + + Vrm10Data m_result; + MigrationData m_migration; + + IEnumerable EnumerateExpressinKeys(UniGLTF.Extensions.VRMC_vrm.Expressions expressions) + { + if (expressions == null) + { + yield break; + } + + if (expressions.Preset?.Happy != null) yield return ExpressionKey.Happy.SubAssetKey; + if (expressions.Preset?.Angry != null) yield return ExpressionKey.Angry.SubAssetKey; + if (expressions.Preset?.Sad != null) yield return ExpressionKey.Sad.SubAssetKey; + if (expressions.Preset?.Relaxed != null) yield return ExpressionKey.Relaxed.SubAssetKey; + if (expressions.Preset?.Surprised != null) yield return ExpressionKey.Surprised.SubAssetKey; + if (expressions.Preset?.Aa != null) yield return ExpressionKey.Aa.SubAssetKey; + if (expressions.Preset?.Ih != null) yield return ExpressionKey.Ih.SubAssetKey; + if (expressions.Preset?.Ou != null) yield return ExpressionKey.Ou.SubAssetKey; + if (expressions.Preset?.Ee != null) yield return ExpressionKey.Ee.SubAssetKey; + if (expressions.Preset?.Oh != null) yield return ExpressionKey.Oh.SubAssetKey; + if (expressions.Preset?.Blink != null) yield return ExpressionKey.Blink.SubAssetKey; + if (expressions.Preset?.BlinkLeft != null) yield return ExpressionKey.BlinkLeft.SubAssetKey; + if (expressions.Preset?.BlinkRight != null) yield return ExpressionKey.BlinkRight.SubAssetKey; + if (expressions.Preset?.LookUp != null) yield return ExpressionKey.LookUp.SubAssetKey; + if (expressions.Preset?.LookDown != null) yield return ExpressionKey.LookDown.SubAssetKey; + if (expressions.Preset?.LookLeft != null) yield return ExpressionKey.LookLeft.SubAssetKey; + if (expressions.Preset?.LookRight != null) yield return ExpressionKey.LookRight.SubAssetKey; + if (expressions.Preset?.Neutral != null) yield return ExpressionKey.Neutral.SubAssetKey; + + if (expressions.Custom != null) + { + foreach (var kv in expressions.Custom) + { + yield return ExpressionKey.CreateCustom(kv.Key).SubAssetKey; + } + } + } + + void OnData() + { + if (m_result == null) + { + // error + return; + } + m_model = ModelReader.Read(m_result.Data); + + var tmp = m_importer.GetExternalObjectMap(); + + var generator = new BuiltInVrm10MaterialDescriptorGenerator(); + var materialKeys = m_result.Data.GLTF.materials.Select((x, i) => generator.Get(m_result.Data, i).SubAssetKey); + var textureKeys = new Vrm10TextureDescriptorGenerator(m_result.Data).Get().GetEnumerable().Select(x => x.SubAssetKey); + m_materialEditor = new RemapEditorMaterial(materialKeys.Concat(textureKeys), GetEditorMap, SetEditorMap); + m_vrmEditor = new RemapEditorVrm(new[] { VRM10Object.SubAssetKey }.Concat(EnumerateExpressinKeys(m_result.VrmExtension.Expressions)), GetEditorMap, SetEditorMap); + } + + public override void OnEnable() + { + base.OnEnable(); + + var importer = target as VrmScriptedImporter; + m_importer = importer; + using (var data = new GlbFileParser(m_importer.assetPath).Parse()) + { + m_result = Vrm10Data.Parse(data); + if (m_result != null) + { + OnData(); + } + else + { + using (var migrated = Vrm10Data.Migrate(data, out m_result, out m_migration)) + { + if (m_result != null) + { + OnData(); + } + } + } + } + } + + enum Tabs + { + Model, + Materials, + Vrm, + } + static Tabs s_currentTab; + + public override void OnInspectorGUI() + { + s_currentTab = TabBar.OnGUI(s_currentTab); + GUILayout.Space(10); + + switch (s_currentTab) + { + case Tabs.Model: + { + if (m_migration == null) + { + { + serializedObject.Update(); + // normalize + EditorGUILayout.Space(); + EditorGUILayout.HelpBox("Create normalized prefab", MessageType.Info); + serializedObject.ApplyModifiedProperties(); + } + + ApplyRevertGUI(); + } + else + { + EditorGUILayout.HelpBox(m_migration.Message, m_model != null ? MessageType.Info : MessageType.Warning); + + if (VRMShaders.Symbols.VRM_DEVELOP) + { + if (GUILayout.Button("debug export")) + { + File.WriteAllBytes("tmp.vrm", m_migration.MigratedBytes); + } + } + + { + serializedObject.Update(); + // migration + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(VrmScriptedImporter.MigrateToVrm1))); + serializedObject.ApplyModifiedProperties(); + } + + ApplyRevertGUI(); + } + break; + } + + case Tabs.Materials: + if (m_result.Data != null && m_result.VrmExtension != null) + { + m_materialEditor.OnGUI(m_importer, m_result.Data, new Vrm10TextureDescriptorGenerator(m_result.Data), + assetPath => $"{Path.GetFileNameWithoutExtension(assetPath)}.vrm1.Textures", + assetPath => $"{Path.GetFileNameWithoutExtension(assetPath)}.vrm1.Materials"); + + // render pipeline + EditorGUILayout.Space(); + EditorGUILayout.HelpBox("Experimental", MessageType.Warning); + EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(VrmScriptedImporter.RenderPipeline))); + + ApplyRevertGUI(); + } + break; + + case Tabs.Vrm: + if (m_result.Data != null && m_result.VrmExtension != null) + { + m_vrmEditor.OnGUI(m_importer, m_result.Data, m_result.VrmExtension); + ApplyRevertGUI(); + } + break; + } + } + } +} diff --git a/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs.meta b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs.meta new file mode 100644 index 000000000..9908c2e22 --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7cfa5b7712433dc498caffa961acb7ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs new file mode 100644 index 000000000..a7c56ffb5 --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs @@ -0,0 +1,117 @@ +using System.Linq; +using UnityEngine; +using UniGLTF; +using System; +using VRM10.Settings; +using VRMShaders; +#if UNITY_2020_2_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif + + +namespace UniVRM10 +{ + public static class VrmScriptedImporterImpl + { + static IMaterialDescriptorGenerator GetMaterialDescriptorGenerator(RenderPipelineTypes renderPipeline) + { + var settings = Vrm10ProjectEditorSettings.instance; + if (settings.MaterialDescriptorGeneratorFactory != null) + { + return settings.MaterialDescriptorGeneratorFactory.Create(); + } + + return renderPipeline switch + { + RenderPipelineTypes.BuiltinRenderPipeline => new BuiltInVrm10MaterialDescriptorGenerator(), + RenderPipelineTypes.UniversalRenderPipeline => new UrpVrm10MaterialDescriptorGenerator(), + _ => throw new NotImplementedException() + }; + } + + static void Process(Vrm10Data result, ScriptedImporter scriptedImporter, AssetImportContext context, RenderPipelineTypes renderPipeline) + { + // + // Import(create unity objects) + // + var extractedObjects = scriptedImporter.GetExternalObjectMap() + .Where(kv => kv.Value != null) + .ToDictionary(kv => new SubAssetKey(kv.Value.GetType(), kv.Key.name), kv => kv.Value); + + var materialGenerator = GetMaterialDescriptorGenerator(renderPipeline); + + using (var loader = new Vrm10Importer(result, externalObjectMap: extractedObjects, materialGenerator: materialGenerator)) + { + // settings TextureImporters + foreach (var textureInfo in loader.TextureDescriptorGenerator.Get().GetEnumerable()) + { + VRMShaders.TextureImporterConfigurator.Configure(textureInfo, loader.TextureFactory.ExternalTextures); + } + + var loaded = loader.Load(); + loaded.ShowMeshes(); + + loaded.TransferOwnership((key, o) => + { + context.AddObjectToAsset(key.Name, o); + }); + var root = loaded.Root; + GameObject.DestroyImmediate(loaded); + + context.AddObjectToAsset(root.name, root); + context.SetMainObject(root); + } + } + + /// + /// + /// + /// + /// + /// vrm0 だった場合に vrm1 化する + /// + /// normalize する + public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, bool doMigrate, RenderPipelineTypes renderPipeline) + { + if (Symbols.VRM_DEVELOP) + { + Debug.Log("OnImportAsset to " + scriptedImporter.assetPath); + } + + // 1st parse as vrm1 + using (var data = new GlbFileParser(scriptedImporter.assetPath).Parse()) + { + var vrm1Data = Vrm10Data.Parse(data); + if (vrm1Data != null) + { + // successfully parsed vrm-1.0 + Process(vrm1Data, scriptedImporter, context, renderPipeline); + } + + if (!doMigrate) + { + return; + } + + // try migration... + MigrationData migration; + using (var migrated = Vrm10Data.Migrate(data, out vrm1Data, out migration)) + { + if (vrm1Data != null) + { + Process(vrm1Data, scriptedImporter, context, renderPipeline); + } + } + + // fail to migrate... + if (migration != null) + { + Debug.LogWarning(migration.Message); + } + return; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs.meta b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs.meta new file mode 100644 index 000000000..4a1a7d4f9 --- /dev/null +++ b/Assets/External/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f08e514e6a60bd0479ed1c928e8b515e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Settings.meta b/Assets/External/VRM10/Editor/Settings.meta new file mode 100644 index 000000000..bc55b9dac --- /dev/null +++ b/Assets/External/VRM10/Editor/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 31cd964f10584104895101e2df4b5ad6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Settings/MaterialDescriptorGeneratorFactory.cs b/Assets/External/VRM10/Editor/Settings/MaterialDescriptorGeneratorFactory.cs new file mode 100644 index 000000000..59e7a235c --- /dev/null +++ b/Assets/External/VRM10/Editor/Settings/MaterialDescriptorGeneratorFactory.cs @@ -0,0 +1,10 @@ +using UniGLTF; +using UnityEngine; + +namespace VRM10.Settings +{ + public abstract class MaterialDescriptorGeneratorFactory : ScriptableObject + { + public abstract IMaterialDescriptorGenerator Create(); + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Settings/MaterialDescriptorGeneratorFactory.cs.meta b/Assets/External/VRM10/Editor/Settings/MaterialDescriptorGeneratorFactory.cs.meta new file mode 100644 index 000000000..cf28a87e0 --- /dev/null +++ b/Assets/External/VRM10/Editor/Settings/MaterialDescriptorGeneratorFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2076d23c8c5f4f359f86bbc8fce79d77 +timeCreated: 1690277470 \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Settings/Vrm10ProjectEditorSettings.cs b/Assets/External/VRM10/Editor/Settings/Vrm10ProjectEditorSettings.cs new file mode 100644 index 000000000..9ec781511 --- /dev/null +++ b/Assets/External/VRM10/Editor/Settings/Vrm10ProjectEditorSettings.cs @@ -0,0 +1,17 @@ +using UnityEditor; +using UnityEngine; + +namespace VRM10.Settings +{ + [FilePath("ProjectSettings/Vrm10ProjectEditorSettings.asset", FilePathAttribute.Location.ProjectFolder)] + internal class Vrm10ProjectEditorSettings : ScriptableSingleton + { + [SerializeField] private MaterialDescriptorGeneratorFactory materialDescriptorGeneratorFactory; + + public MaterialDescriptorGeneratorFactory MaterialDescriptorGeneratorFactory => materialDescriptorGeneratorFactory; + public void Save() + { + Save(true); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Settings/Vrm10ProjectEditorSettings.cs.meta b/Assets/External/VRM10/Editor/Settings/Vrm10ProjectEditorSettings.cs.meta new file mode 100644 index 000000000..dd0241477 --- /dev/null +++ b/Assets/External/VRM10/Editor/Settings/Vrm10ProjectEditorSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2b096596ea97420ca637d240bc264e28 +timeCreated: 1690277371 \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Settings/Vrm10ProjectSettingsProvider.cs b/Assets/External/VRM10/Editor/Settings/Vrm10ProjectSettingsProvider.cs new file mode 100644 index 000000000..9ee7200ef --- /dev/null +++ b/Assets/External/VRM10/Editor/Settings/Vrm10ProjectSettingsProvider.cs @@ -0,0 +1,51 @@ +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace VRM10.Settings +{ + internal sealed class Vrm10ProjectSettingsProvider : SettingsProvider + { + [SettingsProvider] + public static SettingsProvider CreateProvider() => new Vrm10ProjectSettingsProvider(); + + private Vrm10ProjectSettingsProvider() : base("Project/VRM10", SettingsScope.Project) + { + } + + public override void OnActivate(string searchContext, VisualElement rootElement) + { + var asset = Vrm10ProjectEditorSettings.instance; + asset.hideFlags &= ~HideFlags.NotEditable; + var assetObject = new SerializedObject(asset); + + var contentElement = new VisualElement + { + style = + { + paddingLeft = 8, + paddingRight = 2, + paddingTop = 2, + paddingBottom = 2 + } + }; + rootElement.Add(contentElement); + var title = new Label + { + text = "VRM10", + style = + { + fontSize = 19, + unityFontStyleAndWeight = FontStyle.Bold + } + }; + contentElement.Add(title); + var propertyField = new PropertyField(assetObject.FindProperty("materialDescriptorGeneratorFactory")); + propertyField.RegisterValueChangeCallback(_ => asset.Save()); + contentElement.Add(propertyField); + + contentElement.Bind(assetObject); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Editor/Settings/Vrm10ProjectSettingsProvider.cs.meta b/Assets/External/VRM10/Editor/Settings/Vrm10ProjectSettingsProvider.cs.meta new file mode 100644 index 000000000..0b37aa7b8 --- /dev/null +++ b/Assets/External/VRM10/Editor/Settings/Vrm10ProjectSettingsProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 46b3e4ddc61c31444bd942737ebb3dd9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/VRM10.Editor.asmdef b/Assets/External/VRM10/Editor/VRM10.Editor.asmdef new file mode 100644 index 000000000..ad3c9fdc3 --- /dev/null +++ b/Assets/External/VRM10/Editor/VRM10.Editor.asmdef @@ -0,0 +1,25 @@ +{ + "name": "VRM10.Editor", + "rootNamespace": "", + "references": [ + "GUID:e47c917724578cc43b5506c17a27e9a0", + "GUID:2ef84b520212e174a94668c7a0862d3b", + "GUID:5f875fdc81c40184c8333b9d63c6ddd5", + "GUID:8d76e605759c3f64a957d63ef96ada7c", + "GUID:da3e51d19d51a544fa14d43fee843098", + "GUID:7da8a75dcade2144aab699032d7d7987", + "GUID:b7aa47b240b57de44a4b2021c143c9bf", + "GUID:1cd941934d098654fa21a13f28346412" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/External/VRMShaders/VRM/IO/Editor/VRMShaders.VRM.IO.Editor.asmdef.meta b/Assets/External/VRM10/Editor/VRM10.Editor.asmdef.meta similarity index 76% rename from Assets/External/VRMShaders/VRM/IO/Editor/VRMShaders.VRM.IO.Editor.asmdef.meta rename to Assets/External/VRM10/Editor/VRM10.Editor.asmdef.meta index f5affb986..fb2020c19 100644 --- a/Assets/External/VRMShaders/VRM/IO/Editor/VRMShaders.VRM.IO.Editor.asmdef.meta +++ b/Assets/External/VRM10/Editor/VRM10.Editor.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: bc66ece0f33b52446a0830c05781d4db +guid: 6aae90b2207f6fe4fa38ba53e3ab92ef AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Assets/External/VRM10/Editor/VRM10ExportSettings.cs b/Assets/External/VRM10/Editor/VRM10ExportSettings.cs new file mode 100644 index 000000000..9b328e5a2 --- /dev/null +++ b/Assets/External/VRM10/Editor/VRM10ExportSettings.cs @@ -0,0 +1,34 @@ +using System; +using UniGLTF; +using UnityEngine; + +namespace UniVRM10 +{ + [Serializable] + public class VRM10ExportSettings : ScriptableObject + { + /// + /// エクスポート時にBlendShapeClipから参照されないBlendShapeを削除する + /// + [Tooltip("not implemented yet. Remove blendshape that is not used from BlendShapeClip")][ReadOnly] + public bool ReduceBlendshape = false; + + /// + /// skip if BlendShapeClip.Preset == Unknown + /// + [Tooltip("not implemented yet. Remove blendShapeClip that preset is Unknown")][ReadOnly] + public bool ReduceBlendshapeClip = false; + + [Tooltip("Use sparse accessor for morph target")] + public bool MorphTargetUseSparse = true; + + public GltfExportSettings MeshExportSettings => new GltfExportSettings + { + UseSparseAccessorForMorphTarget = MorphTargetUseSparse, + ExportOnlyBlendShapePosition = true, + DivideVertexBuffer = true, + }; + + public GameObject Root { get; set; } + } +} diff --git a/Assets/External/VRM10/Editor/VRM10ExportSettings.cs.meta b/Assets/External/VRM10/Editor/VRM10ExportSettings.cs.meta new file mode 100644 index 000000000..c132dc444 --- /dev/null +++ b/Assets/External/VRM10/Editor/VRM10ExportSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fbbce5097a7261648b99437896210af8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/VRM10MaterialValidator.cs b/Assets/External/VRM10/Editor/VRM10MaterialValidator.cs new file mode 100644 index 000000000..083557e46 --- /dev/null +++ b/Assets/External/VRM10/Editor/VRM10MaterialValidator.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// VRM0 + /// + class VRM10MaterialValidator : UniGLTF.DefaultMaterialValidator + { + const string MTOON_SHADER_NAME = "VRM10/MToon10"; + + public override string GetGltfMaterialTypeFromUnityShaderName(string shaderName) + { + switch (shaderName) + { + case MTOON_SHADER_NAME: + return "VRMC_materials_mtoon"; + } + + // TODO: VRM-0.X + + return base.GetGltfMaterialTypeFromUnityShaderName(shaderName); + } + + public override IEnumerable<(string propertyName, Texture texture)> EnumerateTextureProperties(Material m) + { + if (m.shader.name == MTOON_SHADER_NAME) + { + // TODO + } + else + { + foreach (var x in base.EnumerateTextureProperties(m)) + { + yield return x; + } + } + } + } +} diff --git a/Assets/External/VRM10/Editor/VRM10MaterialValidator.cs.meta b/Assets/External/VRM10/Editor/VRM10MaterialValidator.cs.meta new file mode 100644 index 000000000..8d92b1cf7 --- /dev/null +++ b/Assets/External/VRM10/Editor/VRM10MaterialValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77bcf6c00ae8990488aaea60f0ec9173 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Vrm10ExportDialog.cs b/Assets/External/VRM10/Editor/Vrm10ExportDialog.cs new file mode 100644 index 000000000..51b2e4d3f --- /dev/null +++ b/Assets/External/VRM10/Editor/Vrm10ExportDialog.cs @@ -0,0 +1,311 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UniGLTF; +using UniGLTF.M17N; +using UniGLTF.MeshUtility; +using UnityEditor; +using UnityEngine; +using VrmLib; +using VRMShaders; + +namespace UniVRM10 +{ + public class VRM10ExportDialog : ExportDialogBase + { + public const string MENU_NAME = "Export VRM 1.0..."; + + public static void Open() + { + var window = GetWindow(MENU_NAME); + window.Show(); + } + + + enum Tabs + { + Meta, + Mesh, + ExportSettings, + } + Tabs _tab; + + + VRM10ExportSettings m_settings; + Editor m_settingsInspector; + + + MeshExportValidator m_meshes; + Editor m_meshesInspector; + + VRM10Object m_meta; + VRM10Object Vrm + { + get { return m_meta; } + set + { + if (value != null && AssetDatabase.IsSubAsset(value)) + { + // SubAsset is readonly. copy + Debug.Log("copy VRM10ObjectMeta"); + value.Meta.CopyTo(m_tmpObject.Meta); + return; + } + + if (m_meta == value) + { + return; + } + m_metaEditor = default; + m_meta = value; + } + } + VRM10Object m_tmpObject; + VRM10MetaEditor m_metaEditor; + + protected override void Initialize() + { + m_tmpObject = ScriptableObject.CreateInstance(); + m_tmpObject.name = "_vrm1_"; + m_tmpObject.Meta.Authors = new List { "" }; + + m_settings = ScriptableObject.CreateInstance(); + m_settingsInspector = Editor.CreateEditor(m_settings); + + m_meshes = ScriptableObject.CreateInstance(); + m_meshesInspector = Editor.CreateEditor(m_meshes); + + State.ExportRootChanged += (root) => + { + // update meta + if (root == null) + { + Vrm = null; + } + else + { + var controller = root.GetComponent(); + if (controller != null) + { + Vrm = controller.Vrm; + } + else + { + Vrm = null; + } + + // default setting + // m_settings.PoseFreeze = + // MeshUtility.Validators.HumanoidValidator.HasRotationOrScale(root) + // || m_meshes.Meshes.Any(x => x.ExportBlendShapeCount > 0 && !x.HasSkinning) + // ; + } + }; + } + + protected override void Clear() + { + // m_settingsInspector + UnityEditor.Editor.DestroyImmediate(m_settingsInspector); + m_settingsInspector = null; + // m_meshesInspector + UnityEditor.Editor.DestroyImmediate(m_meshesInspector); + m_meshesInspector = null; + // Meta + Vrm = null; + ScriptableObject.DestroyImmediate(m_tmpObject); + m_tmpObject = null; + // m_settings + ScriptableObject.DestroyImmediate(m_settings); + m_settings = null; + // m_meshes + ScriptableObject.DestroyImmediate(m_meshes); + m_meshes = null; + } + + protected override IEnumerable ValidatorFactory() + { + HumanoidValidator.MeshInformations = m_meshes.Meshes; + // HumanoidValidator.EnableFreeze = m_settings.PoseFreeze; + + yield return HierarchyValidator.Validate; + if (!State.ExportRoot) + { + yield break; + } + + // Mesh/Renderer のチェック + m_meshes.MaterialValidator = new VRM10MaterialValidator(); + yield return m_meshes.Validate; + + yield return HumanoidValidator.Validate_TPose; + + // MeshUtility.Validators.HumanoidValidator.EnableFreeze = false; + // yield return MeshUtility.Validators.HumanoidValidator.Validate; + + // yield return VRMExporterValidator.Validate; + // yield return VRMSpringBoneValidator.Validate; + + // var firstPerson = State.ExportRoot.GetComponent(); + // if (firstPerson != null) + // { + // yield return firstPerson.Validate; + // } + + // var proxy = State.ExportRoot.GetComponent(); + // if (proxy != null) + // { + // yield return proxy.Validate; + // } + + var vrm = Vrm ? Vrm : m_tmpObject; + yield return vrm.Meta.Validate; + } + + protected override void OnLayout() + { + // m_settings, m_meshes.Meshes + m_meshes.SetRoot(State.ExportRoot, m_settings.MeshExportSettings, new DefualtBlendShapeExportFilter()); + } + + protected override bool DoGUI(bool isValid) + { + if (State.ExportRoot == null) + { + return false; + } + + if (State.ExportRoot.GetComponent() != null) + { + var backup = GUI.enabled; + GUI.enabled = State.ExportRoot.scene.IsValid(); + if (GUI.enabled) + { + EditorGUILayout.HelpBox(EnableTPose.ENALBE_TPOSE_BUTTON.Msg(), MessageType.Info); + } + else + { + EditorGUILayout.HelpBox(EnableTPose.DISABLE_TPOSE_BUTTON.Msg(), MessageType.Warning); + } + + if (GUILayout.Button("T-Pose" + "(unity internal)")) + { + if (State.ExportRoot != null) + { + Undo.RecordObjects(State.ExportRoot.GetComponentsInChildren(), "tpose.internal"); + if (InternalTPose.TryMakePoseValid(State.ExportRoot)) + { + // done + Repaint(); + } + else + { + Debug.LogWarning("not found"); + } + } + } + EditorGUILayout.Separator(); + GUI.enabled = backup; + } + + if (!isValid) + { + return false; + } + + if (m_tmpObject == null) + { + // disabled + return false; + } + + // tabbar + _tab = TabBar.OnGUI(_tab); + switch (_tab) + { + case Tabs.Meta: + if (m_metaEditor == null) + { + SerializedObject so; + if (m_meta != null) + { + so = new SerializedObject(Vrm); + } + else + { + so = new SerializedObject(m_tmpObject); + } + m_metaEditor = VRM10MetaEditor.Create(so); + } + m_metaEditor.OnInspectorGUI(); + break; + + case Tabs.Mesh: + m_meshesInspector.OnInspectorGUI(); + break; + + case Tabs.ExportSettings: + m_settingsInspector.OnInspectorGUI(); + break; + } + + return true; + } + + protected override string SaveTitle => "Vrm1"; + protected override string SaveName => $"{State.ExportRoot.name}.vrm"; + protected override string[] SaveExtensions => new string[] { "vrm" }; + + string m_logLabel; + + protected override void ExportPath(string path) + { + m_logLabel = ""; + + m_logLabel += $"export...\n"; + + var root = State.ExportRoot; + + try + { + using (var arrayManager = new NativeArrayManager()) + { + var converter = new UniVRM10.ModelExporter(); + var model = converter.Export(arrayManager, root); + + // 右手系に変換 + m_logLabel += $"convert to right handed coordinate...\n"; + model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false); + + // export vrm-1.0 + var exporter = new UniVRM10.Vrm10Exporter(new EditorTextureSerializer(), m_settings.MeshExportSettings); + var option = new VrmLib.ExportArgs + { + sparse = m_settings.MorphTargetUseSparse, + }; + exporter.Export(root, model, converter, option, Vrm ? Vrm.Meta : m_tmpObject.Meta); + + var exportedBytes = exporter.Storage.ToGlbBytes(); + + m_logLabel += $"write to {path}...\n"; + File.WriteAllBytes(path, exportedBytes); + Debug.Log("exportedBytes: " + exportedBytes.Length); + + var assetPath = UniGLTF.UnityPath.FromFullpath(path); + if (assetPath.IsUnderWritableFolder) + { + // asset folder 内。import を発動 + assetPath.ImportAsset(); + } + } + } + catch (Exception ex) + { + m_logLabel += ex.ToString(); + // rethrow + //throw; + Debug.LogException(ex); + } + } + } +} diff --git a/Assets/External/VRM10/Editor/Vrm10ExportDialog.cs.meta b/Assets/External/VRM10/Editor/Vrm10ExportDialog.cs.meta new file mode 100644 index 000000000..ebfa9e1fd --- /dev/null +++ b/Assets/External/VRM10/Editor/Vrm10ExportDialog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e9ade01036e113c46a73f05c06ce57ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Vrm10InstanceEditor.cs b/Assets/External/VRM10/Editor/Vrm10InstanceEditor.cs new file mode 100644 index 000000000..accf5b4e6 --- /dev/null +++ b/Assets/External/VRM10/Editor/Vrm10InstanceEditor.cs @@ -0,0 +1,295 @@ +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UniGLTF.Utils; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + [CustomEditor(typeof(Vrm10Instance))] + public class Vrm10InstanceEditor : Editor + { + const string SaveTitle = "New folder for vrm-1.0 assets..."; + static string[] SaveExtensions = new string[] { "asset" }; + + static VRM10Object CreateAsset(string path, Dictionary expressions, Vrm10Instance instance) + { + if (string.IsNullOrEmpty(path)) + { + return null; + } + var unityPath = UnityPath.FromFullpath(path); + if (!unityPath.IsUnderWritableFolder) + { + EditorUtility.DisplayDialog("error", "The specified path is not inside of Assets or writable Packages", "OK"); + return null; + } + + var asset = ScriptableObject.CreateInstance(); + + asset.Prefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(instance?.gameObject); + foreach (var kv in expressions) + { + switch (kv.Key) + { + case ExpressionPreset.aa: asset.Expression.Aa = kv.Value; break; + case ExpressionPreset.ih: asset.Expression.Ih = kv.Value; break; + case ExpressionPreset.ou: asset.Expression.Ou = kv.Value; break; + case ExpressionPreset.ee: asset.Expression.Ee = kv.Value; break; + case ExpressionPreset.oh: asset.Expression.Oh = kv.Value; break; + case ExpressionPreset.happy: asset.Expression.Happy = kv.Value; break; + case ExpressionPreset.angry: asset.Expression.Angry = kv.Value; break; + case ExpressionPreset.sad: asset.Expression.Sad = kv.Value; break; + case ExpressionPreset.relaxed: asset.Expression.Relaxed = kv.Value; break; + case ExpressionPreset.surprised: asset.Expression.Surprised = kv.Value; break; + case ExpressionPreset.blink: asset.Expression.Blink = kv.Value; break; + case ExpressionPreset.blinkLeft: asset.Expression.BlinkLeft = kv.Value; break; + case ExpressionPreset.blinkRight: asset.Expression.BlinkRight = kv.Value; break; + case ExpressionPreset.lookUp: asset.Expression.LookUp = kv.Value; break; + case ExpressionPreset.lookDown: asset.Expression.LookDown = kv.Value; break; + case ExpressionPreset.lookLeft: asset.Expression.LookLeft = kv.Value; break; + case ExpressionPreset.lookRight: asset.Expression.LookRight = kv.Value; break; + case ExpressionPreset.neutral: asset.Expression.Neutral = kv.Value; break; + default: break; + } + } + + unityPath.CreateAsset(asset); + AssetDatabase.Refresh(); + var loaded = unityPath.LoadAsset(); + + return loaded; + } + + static bool CheckHumanoid(GameObject go) + { + var animator = go.GetComponent(); + if (animator != null) + { + if (animator.avatar == null) + { + EditorGUILayout.HelpBox("animator.avatar is null", MessageType.Error); + return false; + } + if (!animator.avatar.isValid) + { + EditorGUILayout.HelpBox("animator.avatar is not valid", MessageType.Error); + return false; + + } + if (!animator.avatar.isHuman) + { + EditorGUILayout.HelpBox("animator.avatar is not human", MessageType.Error); + return false; + } + + return true; + } + + var humanoid = go.GetComponent(); + if (humanoid == null) + { + EditorGUILayout.HelpBox("vrm-1.0 require Animator or UniHumanoid.Humanoid", MessageType.Error); + return false; + } + + if (humanoid != null) + { + if (humanoid.Validate().Any()) + { + // 不正 + EditorGUILayout.HelpBox("Please create humanoid avatar", MessageType.Error); + return false; + } + } + + return true; + } + + static VRM10Expression CreateAndSaveExpression(ExpressionPreset preset, string dir, Vrm10Instance instance) + { + var prefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(instance.gameObject); + var clip = ScriptableObject.CreateInstance(); + clip.name = preset.ToString(); + clip.Prefab = prefab; + var path = System.IO.Path.Combine(dir, $"{preset}.asset"); + var unityPath = UnityPath.FromFullpath(path); + unityPath.CreateAsset(clip); + var loaded = unityPath.LoadAsset(); + return loaded; + } + + static string GetSaveName(Vrm10Instance instance) + { + if (instance == null) + { + return "Assets/vrm-1.0.assets"; + } + + if (VRMShaders.PathObject.TryGetFromAsset(instance, out var asset)) + { + return (asset.Parent.Child(instance.name + ".asset")).UnityAssetPath; + } + + return $"Assets/{instance.name}.assets"; + } + + void SetupVRM10Object(Vrm10Instance instance) + { + if (!CheckHumanoid(instance.gameObject)) + { + // can not + return; + } + + EditorGUILayout.HelpBox("Humanoid OK.", MessageType.Info); + + // VRM10Object + var prop = serializedObject.FindProperty(nameof(Vrm10Instance.Vrm)); + if (prop.objectReferenceValue == null) + { + EditorGUILayout.HelpBox("No VRM10Object.", MessageType.Error); + } + if (GUILayout.Button("Create new VRM10Object and default Expressions. select target folder")) + { + var saveName = GetSaveName(instance); + var dir = SaveFileDialog.GetDir(SaveTitle, System.IO.Path.GetDirectoryName(saveName)); + if (!string.IsNullOrEmpty(dir)) + { + var expressions = new Dictionary(); + foreach (ExpressionPreset expression in CachedEnum.GetValues()) + { + if (expression == ExpressionPreset.custom) + { + continue; + } + expressions[expression] = CreateAndSaveExpression(expression, dir, instance); + } + + var path = System.IO.Path.Combine(dir, (instance.name ?? "VRMObject") + ".asset"); + var asset = CreateAsset(path, expressions, instance); + if (asset != null) + { + // update editor + serializedObject.Update(); + prop.objectReferenceValue = asset; + serializedObject.ApplyModifiedProperties(); + } + } + } + } + + public override void OnInspectorGUI() + { + + if (target is Vrm10Instance instance) + { + if (instance.Vrm == null) + { + SetupVRM10Object(instance); + } + + if (instance.Vrm != null) + { + EditorGUILayout.HelpBox("SpringBone gizmo etc...", MessageType.Info); + if (GUILayout.Button("Open " + VRM10Window.MENU_NAME)) + { + VRM10Window.Open(); + } + } + } + + base.OnInspectorGUI(); + } + + public void OnSceneGUI() + { + // 親指のガイド + DrawThumbGuide(target as Vrm10Instance); + } + + static void DrawThumbGuide(Vrm10Instance instance) + { + if (instance == null) + { + return; + } + if (instance.TryGetBoneTransform(HumanBodyBones.LeftThumbProximal, out var l0)) + { + if (instance.TryGetBoneTransform(HumanBodyBones.LeftThumbIntermediate, out var l1)) + { + if (instance.TryGetBoneTransform(HumanBodyBones.LeftThumbDistal, out var l2)) + { + var color = new Color(0.5f, 1.0f, 0.0f, 1.0f); + var thumbDir = (Vector3.forward + Vector3.left).normalized; + var nailNormal = (Vector3.forward + Vector3.right).normalized; + DrawThumbGuide(l0.position, l2.position, thumbDir, nailNormal, color); + } + } + } + if (instance.TryGetBoneTransform(HumanBodyBones.RightThumbProximal, out var r0)) + { + if (instance.TryGetBoneTransform(HumanBodyBones.RightThumbIntermediate, out var r1)) + { + if (instance.TryGetBoneTransform(HumanBodyBones.RightThumbDistal, out var r2)) + { + var color = new Color(0.5f, 1.0f, 0.0f, 1.0f); + var thumbDir = (Vector3.forward + Vector3.right).normalized; + var nailNormal = (Vector3.forward + Vector3.left).normalized; + DrawThumbGuide(r0.position, r2.position, thumbDir, nailNormal, color); + } + } + } + } + static void DrawThumbGuide(Vector3 metacarpalPos, Vector3 distalPos, Vector3 thumbDir, Vector3 nailNormal, Color color) + { + Handles.color = color; + Handles.matrix = Matrix4x4.identity; + + var thumbVector = distalPos - metacarpalPos; + var thumbLength = thumbVector.magnitude * 1.5f; + var thickness = thumbLength * 0.1f; + var tipCenter = metacarpalPos + thumbDir * (thumbLength - thickness); + var crossVector = Vector3.Cross(thumbDir, nailNormal); + + // 指の形を描く + Handles.DrawLine(metacarpalPos + crossVector * thickness, tipCenter + crossVector * thickness); + Handles.DrawLine(metacarpalPos - crossVector * thickness, tipCenter - crossVector * thickness); + Handles.DrawWireArc(tipCenter, nailNormal, crossVector, 180f, thickness); + + Handles.DrawLine(metacarpalPos + nailNormal * thickness, tipCenter + nailNormal * thickness); + Handles.DrawLine(metacarpalPos - nailNormal * thickness, tipCenter - nailNormal * thickness); + Handles.DrawWireArc(tipCenter, crossVector, -nailNormal, 180f, thickness); + + Handles.DrawWireDisc(metacarpalPos, thumbDir, thickness); + Handles.DrawWireDisc(tipCenter, thumbDir, thickness); + + // 爪の方向に伸びる線を描く + Handles.DrawDottedLine(tipCenter, tipCenter + nailNormal * thickness * 8.0f, 1.0f); + + // 爪を描く + Vector2[] points2 = { + new Vector2(-0.2f, -0.5f), + new Vector2(0.2f, -0.5f), + new Vector2(0.5f, -0.3f), + new Vector2(0.5f, 0.3f), + new Vector2(0.2f, 0.5f), + new Vector2(-0.2f, 0.5f), + new Vector2(-0.5f, 0.3f), + new Vector2(-0.5f, -0.3f), + new Vector2(-0.2f, -0.5f), + }; + Vector3[] points = points2 + .Select(v => tipCenter + (nailNormal + crossVector * v.x + thumbDir * v.y) * thickness) + .ToArray(); + + Handles.DrawAAPolyLine(points); + Handles.color = color * new Color(1.0f, 1.0f, 1.0f, 0.1f); + Handles.DrawAAConvexPolygon(points); + + // 文字ラベルを描く + Handles.Label(tipCenter + nailNormal * thickness * 6.0f, "Thumb nail direction"); + } + } +} diff --git a/Assets/External/VRM10/Editor/Vrm10InstanceEditor.cs.meta b/Assets/External/VRM10/Editor/Vrm10InstanceEditor.cs.meta new file mode 100644 index 000000000..7f6324abc --- /dev/null +++ b/Assets/External/VRM10/Editor/Vrm10InstanceEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 789ac0011e43ce9428e4de09668c2595 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Vrm10SerializerGenerator.cs b/Assets/External/VRM10/Editor/Vrm10SerializerGenerator.cs new file mode 100644 index 000000000..f22a16105 --- /dev/null +++ b/Assets/External/VRM10/Editor/Vrm10SerializerGenerator.cs @@ -0,0 +1,107 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// JsonSchema から vrm10 のシリアライザーを生成する。 + /// + /// * glTF + /// * vrm-specification + /// + /// は SubModuleになった。 `$ git submodule update --init` しておくこと。 + /// + /// + public static class Vrm10SerializerGenerator + { + struct GenerateInfo + { + public string JsonSchema; + public string FormatDir; + public string SerializerDir; + + public GenerateInfo(string jsonSchema, string formatDir, string serializerDir) + { + JsonSchema = jsonSchema; + FormatDir = formatDir; + SerializerDir = serializerDir; + } + + public GenerateInfo(string jsonSchema, string formatDir) : this(jsonSchema, formatDir, formatDir) + { + } + } + + const string SPEC_DIR = "vrm-specification/specification"; + + public static void Run(bool debug) + { + var projectRoot = new DirectoryInfo(Path.GetFullPath(Path.Combine(Application.dataPath, "../"))); + + var gltf = new FileInfo(Path.Combine(projectRoot.FullName, "glTF/specification/2.0/schema/glTF.schema.json")); + + var args = new GenerateInfo[] + { + // VRMC_hdr_emissiveMultiplier + new GenerateInfo( + $"{SPEC_DIR}/VRMC_materials_hdr_emissiveMultiplier-1.0/schema/VRMC_materials_hdr_emissiveMultiplier.json", + "Assets/UniGLTF/Runtime/UniGLTF/Format/ExtensionsAndExtras/EmissiveMultiplier" + ), + + // VRMC_vrm + new GenerateInfo( + $"{SPEC_DIR}/VRMC_vrm-1.0/schema/VRMC_vrm.schema.json", + "Assets/VRM10/Runtime/Format/Vrm" + ), + + // VRMC_materials_mtoon + new GenerateInfo( + $"{SPEC_DIR}/VRMC_materials_mtoon-1.0/schema/VRMC_materials_mtoon.schema.json", + "Assets/VRMShaders/VRM10/Format/Runtime/MaterialsMToon", + "Assets/VRM10/Runtime/Format/MaterialsMToon" + ), + + // VRMC_springBone + new GenerateInfo( + $"{SPEC_DIR}/VRMC_springBone-1.0/schema/VRMC_springBone.schema.json", + "Assets/VRM10/Runtime/Format/SpringBone" + ), + + // VRMC_node_constraint + new GenerateInfo( + $"{SPEC_DIR}/VRMC_node_constraint-1.0/schema/VRMC_node_constraint.schema.json", + "Assets/VRM10/Runtime/Format/Constraints" + ), + + // VRMC_animation + new GenerateInfo( + $"{SPEC_DIR}/VRMC_vrm_animation-1.0/schema/VRMC_vrm_animation.schema.json", + "Assets/VRM10/Runtime/Format/Animation" + ), + }; + + foreach (var arg in args) + { + var extensionSchemaPath = new FileInfo(Path.Combine(projectRoot.FullName, arg.JsonSchema)); + var parser = new UniGLTF.JsonSchema.JsonSchemaParser(gltf.Directory, extensionSchemaPath.Directory); + var extensionSchema = parser.Load(extensionSchemaPath, ""); + + var formatDst = new DirectoryInfo(Path.Combine(projectRoot.FullName, arg.FormatDir)); + Debug.Log($"Format.g Dir: {formatDst}"); + + var serializerDst = new DirectoryInfo(Path.Combine(projectRoot.FullName, arg.SerializerDir)); + Debug.Log($"Serializer/Deserializer.g Dir: {serializerDst}"); + + if (debug) + { + Debug.Log(extensionSchema.Dump()); + } + else + { + GenerateUniGLTFSerialization.Generator.GenerateTo(extensionSchema, formatDst, serializerDst); + } + } + } + } +} diff --git a/Assets/External/VRM10/Editor/Vrm10SerializerGenerator.cs.meta b/Assets/External/VRM10/Editor/Vrm10SerializerGenerator.cs.meta new file mode 100644 index 000000000..1b098ddea --- /dev/null +++ b/Assets/External/VRM10/Editor/Vrm10SerializerGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e5497454373c2a458526799422de3ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/Vrm10TopMenu.cs b/Assets/External/VRM10/Editor/Vrm10TopMenu.cs new file mode 100644 index 000000000..3749c5e63 --- /dev/null +++ b/Assets/External/VRM10/Editor/Vrm10TopMenu.cs @@ -0,0 +1,34 @@ +using UniGLTF.MeshUtility; +using UnityEditor; + +namespace UniVRM10 +{ + public static class Vrm10TopMenu + { + private const string UserMenuPrefix = VRM10SpecVersion.MENU; + private const string DevelopmentMenuPrefix = VRM10SpecVersion.MENU + "/Development"; + private const string ExperimentalMenuPrefix = VRM10SpecVersion.MENU + "/Experimental"; + + + [MenuItem(UserMenuPrefix + "/" + VRM10ExportDialog.MENU_NAME, priority = 1)] + private static void OpenExportDialog() => VRM10ExportDialog.Open(); + + [MenuItem(UserMenuPrefix + "/" + Vrm10MeshUtilityDialog.MENU_NAME, priority = 21)] + private static void OpenMeshUtility() => Vrm10MeshUtilityDialog.OpenWindow(); + + + [MenuItem(ExperimentalMenuPrefix + "/" + VrmAnimationMenu.MENU_NAME, priority = 22)] + private static void ConvertVrmAnimation() => VrmAnimationMenu.BvhToVrmAnimationMenu(); + +#if VRM_DEVELOP + [MenuItem(ExperimentalMenuPrefix + "/" + VRM10Window.MENU_NAME, false, 23)] + private static void OpenWindow() => VRM10Window.Open(); + + [MenuItem(DevelopmentMenuPrefix + "/Generate from JsonSchema", false, 100)] + private static void Generate() => Vrm10SerializerGenerator.Run(false); + + [MenuItem(DevelopmentMenuPrefix + "/Generate from JsonSchema(debug)", false, 101)] + private static void Parse() => Vrm10SerializerGenerator.Run(true); +#endif + } +} diff --git a/Assets/External/VRM10/Editor/Vrm10TopMenu.cs.meta b/Assets/External/VRM10/Editor/Vrm10TopMenu.cs.meta new file mode 100644 index 000000000..9750afd3e --- /dev/null +++ b/Assets/External/VRM10/Editor/Vrm10TopMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 935fd2eb9940f5d48933733f69a96113 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Editor/VrmAnimationMenu.cs b/Assets/External/VRM10/Editor/VrmAnimationMenu.cs new file mode 100644 index 000000000..40ef1013f --- /dev/null +++ b/Assets/External/VRM10/Editor/VrmAnimationMenu.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UniGLTF; +using UniHumanoid; +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + internal static class VrmAnimationMenu + { + public const string MENU_NAME = "Convert BVH to VRM-Animation..."; + + public static void BvhToVrmAnimationMenu() + { + var path = EditorUtility.OpenFilePanel("select bvh", null, "bvh"); + if (!string.IsNullOrEmpty(path)) + { + var bytes = BvhToVrmAnimation(path); + var dst = EditorUtility.SaveFilePanel("write vrma", + Path.GetDirectoryName(path), + Path.GetFileNameWithoutExtension(path), + "vrma"); + if (!string.IsNullOrEmpty(dst)) + { + File.WriteAllBytes(dst, bytes); + } + } + } + + static Transform GetParentBone(Dictionary map, Vrm10HumanoidBones bone) + { + while (true) + { + if (bone == Vrm10HumanoidBones.Hips) + { + break; + } + var parentBone = Vrm10HumanoidBoneSpecification.GetDefine(bone).ParentBone.Value; + var unityParentBone = Vrm10HumanoidBoneSpecification.ConvertToUnityBone(parentBone); + if (map.TryGetValue(unityParentBone, out var found)) + { + return found; + } + bone = parentBone; + } + + // hips has no parent + return null; + } + + /// 使用する BVH は次の条件を満たす必要があります。 + /// + /// * レストポーズが TPose であること + /// + /// また、BVH には HumanBone の割り当てが記述されておらず、 + /// 大きさに関しても単位の規定がありません。 + /// + /// bvh.Load 関数の中で HumanBone の名前ベースの割り当て処理と、 + /// メートルサイズへのスケーリング(cm to meter など)をしています。 + /// + /// bvh のボーン割り当てを追加する場合は、 + /// bvh.Parse 内の Skeleton.Estimate 関数を参照してください。 + /// + static byte[] BvhToVrmAnimation(string path) + { + var bvh = new BvhImporterContext(); + bvh.Parse(path, File.ReadAllText(path)); + bvh.Load(); + + var data = new ExportingGltfData(); + using var exporter = new VrmAnimationExporter( + data, new GltfExportSettings()); + exporter.Prepare(bvh.Root.gameObject); + + exporter.Export((VrmAnimationExporter vrma) => + { + // + // setup + // + var map = new Dictionary(); + var animator = bvh.Root.GetComponent(); + foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) + { + if (bone == HumanBodyBones.LastBone) + { + continue; + } + var t = animator.GetBoneTransform(bone); + if (t == null) + { + continue; + } + map.Add(bone, t); + } + + vrma.SetPositionBoneAndParent(map[HumanBodyBones.Hips], bvh.Root.transform); + + foreach (var kv in map) + { + var vrmBone = Vrm10HumanoidBoneSpecification.ConvertFromUnityBone(kv.Key); + var parent = GetParentBone(map, vrmBone) ?? bvh.Root.transform; + vrma.AddRotationBoneAndParent(kv.Key, kv.Value, parent); + } + + // + // get data + // + var animation = bvh.Root.gameObject.GetComponent(); + var clip = animation.clip; + var state = animation[clip.name]; + + var time = default(TimeSpan); + for (int i = 0; i < bvh.Bvh.FrameCount; ++i, time += bvh.Bvh.FrameTime) + { + state.time = (float)time.TotalSeconds; + animation.Sample(); + vrma.AddFrame(time); + } + + }); + + return data.ToGlbBytes(); + } + } +} diff --git a/Assets/External/VRM10/Editor/VrmAnimationMenu.cs.meta b/Assets/External/VRM10/Editor/VrmAnimationMenu.cs.meta new file mode 100644 index 000000000..efae9abb9 --- /dev/null +++ b/Assets/External/VRM10/Editor/VrmAnimationMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7cd670e43db7e7f42a210eb10f5da2c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime.meta b/Assets/External/VRM10/Runtime.meta new file mode 100644 index 000000000..5314201dc --- /dev/null +++ b/Assets/External/VRM10/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0809da138c9f1564b8e5151372b2161f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/AssemblyInfo.cs b/Assets/External/VRM10/Runtime/AssemblyInfo.cs new file mode 100644 index 000000000..cdd50e031 --- /dev/null +++ b/Assets/External/VRM10/Runtime/AssemblyInfo.cs @@ -0,0 +1,5 @@ +#if UNITY_EDITOR +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("VRM10.Tests")] +#endif \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/AssemblyInfo.cs.meta b/Assets/External/VRM10/Runtime/AssemblyInfo.cs.meta new file mode 100644 index 000000000..e78efb4ef --- /dev/null +++ b/Assets/External/VRM10/Runtime/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c0bb9ff90c68a3f4bb86b5fed930f30e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components.meta b/Assets/External/VRM10/Runtime/Components.meta new file mode 100644 index 000000000..30b970a99 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7074fe77da26e9d4891ee5c940395c71 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint.meta b/Assets/External/VRM10/Runtime/Components/Constraint.meta new file mode 100644 index 000000000..05748a79e --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61b940c05955d5342aef635236298ce5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/ConstRaintException.cs b/Assets/External/VRM10/Runtime/Components/Constraint/ConstRaintException.cs new file mode 100644 index 000000000..5ec92109a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/ConstRaintException.cs @@ -0,0 +1,20 @@ +using System; + +namespace UniVRM10 +{ + public class ConstraintException : Exception + { + public enum ExceptionTypes + { + NoSource, + NoModelWithModelSpace + } + + public readonly ExceptionTypes Type; + + public ConstraintException(ExceptionTypes type) + { + Type = type; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/ConstRaintException.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/ConstRaintException.cs.meta new file mode 100644 index 000000000..afc5fb285 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/ConstRaintException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13be84b73aeb40641978e083c750590d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintAxes.cs b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintAxes.cs new file mode 100644 index 000000000..6fe4e9397 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintAxes.cs @@ -0,0 +1,43 @@ +using System; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Axesで使う。bitマスク + /// + [Flags] + public enum AxisMask + { + X = 1, + Y = 2, + Z = 4, + } + + [Flags] + public enum YawPitchMask + { + Yaw = 1, + Pitch = 2, + } + + public static class AxesMaskExtensions + { + public static Vector3 Mask(this AxisMask mask, Vector3 src) + { + if (!mask.HasFlag(AxisMask.X)) + { + src.x = 0; + } + if (!mask.HasFlag(AxisMask.Y)) + { + src.y = 0; + } + if (!mask.HasFlag(AxisMask.Z)) + { + src.z = 0; + } + return src; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintAxes.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintAxes.cs.meta new file mode 100644 index 000000000..c1c49bc0e --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintAxes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 913d6607f40ece14d827c2f95b76ea55 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs new file mode 100644 index 000000000..10af3f818 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs @@ -0,0 +1,36 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public class ConstraintDestination + { + public readonly Transform Destination; + public readonly TR ModelInitial; + public readonly TR LocalInitial; + public readonly Transform ModelRoot; + + public ConstraintDestination(Transform t, Transform modelRoot = null) + { + Destination = t; + LocalInitial = TR.FromLocal(t); + + if (modelRoot != null) + { + ModelRoot = modelRoot; + ModelInitial = TR.FromRelative(t, modelRoot); + } + } + + public void ApplyLocal(TR tr) + { + Destination.localPosition = tr.Translation; + Destination.localRotation = tr.Rotation; + } + + public void ApplyModel(TR tr) + { + Destination.position = tr.Translation; + Destination.rotation = tr.Rotation; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs.meta new file mode 100644 index 000000000..f88469da2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9468d76832ea7224b97e0260f53a87dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintSource.cs b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintSource.cs new file mode 100644 index 000000000..f4d249b14 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintSource.cs @@ -0,0 +1,35 @@ +using UnityEngine; +using System; +using UniGLTF.Extensions.VRMC_node_constraint; + +namespace UniVRM10 +{ + public class ConstraintSource + { + public readonly Transform ModelRoot; + readonly Transform Source; + + public readonly TR ModelInitial; + + public readonly TR LocalInitial; + + public TR Delta(Quaternion sourceRotationOffset) + { + return TR.FromLocal(Source) * (LocalInitial * new TR(sourceRotationOffset)).Inverse(); + } + + public ConstraintSource(Transform t, Transform modelRoot = null) + { + { + Source = t; + LocalInitial = TR.FromLocal(t); + } + + if (modelRoot != null) + { + ModelRoot = modelRoot; + ModelInitial = TR.FromLocal(t); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintSource.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintSource.cs.meta new file mode 100644 index 000000000..c155762ed --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/ConstraintSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0730ba085e3395f4aa76c477cdc6548b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs b/Assets/External/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs new file mode 100644 index 000000000..774e0597f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public interface IVrm10Constraint + { + internal void Process(); + + GameObject ConstraintTarget { get; } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs.meta new file mode 100644 index 000000000..e14d79e8d --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c859e278c34a69b438db39275ce25556 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/TR.cs b/Assets/External/VRM10/Runtime/Components/Constraint/TR.cs new file mode 100644 index 000000000..de7bfa81a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/TR.cs @@ -0,0 +1,62 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public struct TR + { + public Quaternion Rotation; + public Vector3 Translation; + + public static TR Identity => new TR(Quaternion.identity, Vector3.zero); + + public static TR FromWorld(Transform t) => new TR(t.rotation, t.position); + + public static TR FromParent(Transform t) => t.parent != null ? FromWorld(t.parent) : TR.Identity; + + public static TR FromLocal(Transform t) => new TR(t.localRotation, t.localPosition); + + public static TR FromRelative(Transform t, Transform from) + { + var toRelative = from.worldToLocalMatrix; + return new TR(toRelative.rotation * t.rotation, toRelative.MultiplyPoint(t.position)); + } + + public TR(Quaternion r, Vector3 t) + { + Rotation = r; + Translation = t; + } + + public TR(Quaternion r) : this(r, Vector3.zero) + { + } + + public TR(Vector3 t) : this(Quaternion.identity, t) + { + } + + public Matrix4x4 TRS(float s) => Matrix4x4.TRS(Translation, Rotation, new Vector3(s, s, s)); + + + /// + /// R1|T1 R2|T2 x R1R2|R1T2+T1 x + /// --+-- --+-- y => ----+------- y + /// 0| 1 0| 1 z 0| 1 z + /// + /// + /// + /// + public static TR operator *(TR a, TR b) => new TR(a.Rotation * b.Rotation, a.Rotation * b.Translation + a.Translation); + + /// + /// R|0 1|T R|RT + /// -+- -+- => -+-- + /// 0|1 0|1 0| 1 + /// + public TR Inverse() + { + var inv = Quaternion.Inverse(Rotation); + return new TR(inv, inv * -Translation); + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/TR.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/TR.cs.meta new file mode 100644 index 000000000..b5f7a2033 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/TR.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ddd45ffb38279b488938471919fc089 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/TransformExtensions.cs b/Assets/External/VRM10/Runtime/Components/Constraint/TransformExtensions.cs new file mode 100644 index 000000000..6b07bd795 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/TransformExtensions.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public static class TransformExtensions + { + public static Quaternion ParentRotation(this Transform transform) + { + return transform.parent == null ? Quaternion.identity : transform.parent.rotation; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/TransformExtensions.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/TransformExtensions.cs.meta new file mode 100644 index 000000000..1d848428a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/TransformExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec9ca9ddc040c304793c322223f11b6a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs new file mode 100644 index 000000000..9f500a774 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs @@ -0,0 +1,106 @@ +using System; +using UniGLTF.Extensions.VRMC_node_constraint; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_beta/schema/VRMC_node_constraint.aimConstraint.schema.json + /// + [DisallowMultipleComponent] + public class Vrm10AimConstraint : MonoBehaviour, IVrm10Constraint + { + public GameObject ConstraintTarget => gameObject; + + [SerializeField] + public Transform Source = default; + + [SerializeField] + [Range(0, 1.0f)] + public float Weight = 1.0f; + + [SerializeField] + public AimAxis AimAxis; + + Vector3 GetAxisVector() + { + switch (AimAxis) + { + case AimAxis.PositiveX: return Vector3.right; + case AimAxis.NegativeX: return Vector3.left; + case AimAxis.PositiveY: return Vector3.up; + case AimAxis.NegativeY: return Vector3.down; + case AimAxis.PositiveZ: return Vector3.forward; + case AimAxis.NegativeZ: return Vector3.back; + default: throw new NotImplementedException(); + } + } + + Quaternion _dstRestLocalQuat; + + void Start() + { + if (Source == null) + { + this.enabled = false; + return; + } + + _dstRestLocalQuat = transform.localRotation; + } + /// + /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_beta/README.ja.md#example-of-implementation-1 + /// + /// fromVec = aimAxis.applyQuaternion( dstParentWorldQuat * dstRestQuat ) + /// toVec = ( srcWorldPos - dstWorldPos ).normalized + /// fromToQuat = Quaternion.fromToRotation( fromVec, toVec ) + /// targetQuat = Quaternion.slerp( + /// dstRestQuat, + /// dstParentWorldQuat.inverse * fromToQuat * dstParentWorldQuat * dstRestQuat, + /// weight + /// ) + /// + void IVrm10Constraint.Process() + { + if (Source == null) return; + + // world coords + var dstParentWorldQuat = transform.parent != null ? transform.parent.rotation : Quaternion.identity; + var fromVec = (dstParentWorldQuat * _dstRestLocalQuat) * GetAxisVector(); + var toVec = (Source.position - transform.position).normalized; + var fromToQuat = Quaternion.FromToRotation(fromVec, toVec); + + transform.localRotation = Quaternion.SlerpUnclamped( + _dstRestLocalQuat, + Quaternion.Inverse(dstParentWorldQuat) * fromToQuat * dstParentWorldQuat * _dstRestLocalQuat, + Weight + ); + } + + public void OnDrawGizmosSelected() + { + if (Source == null) + { + return; + } + + Gizmos.color = Color.magenta; + Gizmos.DrawLine(transform.position, Source.position); + Gizmos.DrawSphere(Source.position, 0.01f); + + Gizmos.matrix = transform.localToWorldMatrix; + var len = 0.1f; + switch (AimAxis) + { + case AimAxis.PositiveX: + Gizmos.color = Color.red; + Gizmos.DrawLine(Vector3.zero, Vector3.right * len); + break; + case AimAxis.NegativeX: + Gizmos.color = Color.red; + Gizmos.DrawLine(Vector3.zero, Vector3.left * len); + break; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs.meta new file mode 100644 index 000000000..205e03dc4 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37b0507e4ae49724898ca17cc3db6f1a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs new file mode 100644 index 000000000..702f17d02 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs @@ -0,0 +1,18 @@ +namespace UniVRM10 +{ + public static class Vrm10ConstraintUtil + { + /// + /// 右手系と左手系を相互に変換する + /// + public static UniGLTF.Extensions.VRMC_node_constraint.AimAxis ReverseX(UniGLTF.Extensions.VRMC_node_constraint.AimAxis src) + { + switch (src) + { + case UniGLTF.Extensions.VRMC_node_constraint.AimAxis.PositiveX: return UniGLTF.Extensions.VRMC_node_constraint.AimAxis.NegativeX; + case UniGLTF.Extensions.VRMC_node_constraint.AimAxis.NegativeX: return UniGLTF.Extensions.VRMC_node_constraint.AimAxis.PositiveX; + default: return src; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs.meta new file mode 100644 index 000000000..461a75070 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2c7b76ebe42e9543ac52153ea9f2728 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs new file mode 100644 index 000000000..ce0f0f27f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs @@ -0,0 +1,84 @@ +using System; +using UniGLTF.Extensions.VRMC_node_constraint; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_beta/schema/VRMC_node_constraint.rollConstraint.schema.json + /// + [DisallowMultipleComponent] + public class Vrm10RollConstraint : MonoBehaviour, IVrm10Constraint + { + public GameObject ConstraintTarget => gameObject; + + [SerializeField] + public Transform Source = default; + + [SerializeField] + [Range(0, 1.0f)] + public float Weight = 1.0f; + + [SerializeField] + public RollAxis RollAxis; + Vector3 GetRollVector() + { + switch (RollAxis) + { + case RollAxis.X: return Vector3.right; + case RollAxis.Y: return Vector3.up; + case RollAxis.Z: return Vector3.forward; + default: throw new NotImplementedException(); + } + } + + Quaternion _srcRestLocalQuat; + Quaternion _dstRestLocalQuat; + + void Start() + { + if (Source == null) + { + this.enabled = false; + return; + } + + _srcRestLocalQuat = Source.localRotation; + _dstRestLocalQuat = transform.localRotation; + } + /// + /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_beta/README.ja.md#example-of-implementation + /// + /// deltaSrcQuat = srcRestQuat.inverse * srcQuat + /// deltaSrcQuatInParent = srcRestQuat * deltaSrcQuat * srcRestQuat.inverse // source to parent + /// deltaSrcQuatInDst = dstRestQuat.inverse * deltaSrcQuatInWorld * dstRestQuat // parent to destination + /// + /// toVec = rollAxis.applyQuaternion( deltaSrcQuatInDst ) + /// fromToQuat = Quaternion.fromToRotation( rollAxis, toVec ) + /// + /// targetQuat = Quaternion.slerp( + /// dstRestQuat, + /// dstRestQuat * fromToQuat.inverse * deltaSrcQuatInDst, + /// weight + /// ) + /// + void IVrm10Constraint.Process() + { + if (Source == null) return; + + var deltaSrcQuat = Quaternion.Inverse(_srcRestLocalQuat) * Source.localRotation; + var deltaSrcQuatInParent = _srcRestLocalQuat * deltaSrcQuat * Quaternion.Inverse(_srcRestLocalQuat); // source to parent + var deltaSrcQuatInDst = Quaternion.Inverse(_dstRestLocalQuat) * deltaSrcQuatInParent * _dstRestLocalQuat; // parent to destination + + var rollAxis = GetRollVector(); + var toVec = deltaSrcQuatInDst * rollAxis; + var fromToQuat = Quaternion.FromToRotation(rollAxis, toVec); + + transform.localRotation = Quaternion.SlerpUnclamped( + _dstRestLocalQuat, + _dstRestLocalQuat * Quaternion.Inverse(fromToQuat) * deltaSrcQuatInDst, + Weight + ); + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs.meta new file mode 100644 index 000000000..4c6dc5979 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e864293edac89b40b9f79c23e7aa547 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs new file mode 100644 index 000000000..a98a608e5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_beta/schema/VRMC_node_constraint.rotationConstraint.schema.json + /// + [DisallowMultipleComponent] + public class Vrm10RotationConstraint : MonoBehaviour, IVrm10Constraint + { + public GameObject ConstraintTarget => gameObject; + + [SerializeField] + public Transform Source = default; + + [SerializeField] + [Range(0, 1.0f)] + public float Weight = 1.0f; + + Quaternion _srcRestLocalQuatInverse; + Quaternion _dstRestLocalQuat; + + void Start() + { + if (Source == null) + { + this.enabled = false; + return; + } + + _srcRestLocalQuatInverse = Quaternion.Inverse(Source.localRotation); + _dstRestLocalQuat = transform.localRotation; + } + + /// + /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_beta/README.ja.md#example-of-implementation-2 + /// + /// srcDeltaQuat = srcRestQuat.inverse * srcQuat + /// targetQuat = Quaternion.slerp( + /// dstRestQuat, + /// dstRestQuat * srcDeltaQuat, + /// weight + /// ) + /// + void IVrm10Constraint.Process() + { + if (Source == null) return; + + // local coords + var srcDeltaLocalQuat = _srcRestLocalQuatInverse * Source.localRotation; + transform.localRotation = Quaternion.SlerpUnclamped(_dstRestLocalQuat, _dstRestLocalQuat * srcDeltaLocalQuat, Weight); + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs.meta b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs.meta new file mode 100644 index 000000000..4eaea4e14 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7a07fbecedce41b4396f286fd7634e1d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression.meta b/Assets/External/VRM10/Runtime/Components/Expression.meta new file mode 100644 index 000000000..a9013ae99 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86b623ba37ecc8344a984fad4ceff2d4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs b/Assets/External/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs new file mode 100644 index 000000000..b671a1608 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF.Extensions.VRMC_vrm; +using UnityEngine; +using VrmLib; + +namespace UniVRM10 +{ + public sealed class DefaultExpressionValidator : IExpressionValidator + { + private readonly ExpressionKey[] _keys; + private readonly Dictionary _expressions; + + private DefaultExpressionValidator(VRM10ObjectExpression expressionAvatar) + { + _keys = expressionAvatar.Clips + .Select(x => expressionAvatar.CreateKey(x.Clip)) + .ToArray(); + _expressions = expressionAvatar.Clips.ToDictionary( + x => expressionAvatar.CreateKey(x.Clip), + x => x.Clip, + ExpressionKey.Comparer + ); + } + + public void Validate(IReadOnlyDictionary inputWeights, IDictionary actualWeights, + LookAtEyeDirection inputEyeDirection, out LookAtEyeDirection actualEyeDirection, + out float blinkOverrideRate, out float lookAtOverrideRate, out float mouthOverrideRate) + { + // override rate + blinkOverrideRate = 0f; + lookAtOverrideRate = 0f; + mouthOverrideRate = 0f; + + // 1. Set weights and Accumulate override rates. + foreach (var key in _keys) + { + // Get expression. + if (!_expressions.ContainsKey(key)) continue; + var expression = _expressions[key]; + + // Get weight with evaluation binary flag. + var weight = expression.IsBinary ? Mathf.Round(inputWeights[key]) : inputWeights[key]; + + // Set weight. + actualWeights[key] = weight; + + // Override rate without targeting myself. + if (!key.IsBlink) + { + blinkOverrideRate += GetOverrideRate(expression.OverrideBlink, weight); + } + if (!key.IsLookAt) + { + lookAtOverrideRate += GetOverrideRate(expression.OverrideLookAt, weight); + } + if (!key.IsMouth) + { + mouthOverrideRate += GetOverrideRate(expression.OverrideMouth, weight); + } + } + + // 2. Saturate rate. + blinkOverrideRate = Mathf.Clamp01(blinkOverrideRate); + lookAtOverrideRate = Mathf.Clamp01(lookAtOverrideRate); + mouthOverrideRate = Mathf.Clamp01(mouthOverrideRate); + + var blinkMultiplier = 1f - blinkOverrideRate; + var lookAtMultiplier = 1f - lookAtOverrideRate; + var mouthMultiplier = 1f - mouthOverrideRate; + + // 3. Set procedural key's weights. + foreach (var key in _keys) + { + if (key.IsBlink) + { + actualWeights[key] = actualWeights[key] * blinkMultiplier; + } + else if (key.IsLookAt) + { + actualWeights[key] = actualWeights[key] * lookAtMultiplier; + } + else if (key.IsMouth) + { + actualWeights[key] = actualWeights[key] * mouthMultiplier; + } + } + + // 4. eye direction + actualEyeDirection = LookAtEyeDirection.Multiply(inputEyeDirection, 1f - lookAtOverrideRate); + } + + private float GetOverrideRate(ExpressionOverrideType type, float weight) + { + switch (type) + { + case ExpressionOverrideType.none: + return 0f; + case ExpressionOverrideType.block: + return weight > 0f ? 1f : 0f; + case ExpressionOverrideType.blend: + return weight; + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } + } + + public sealed class Factory : IExpressionValidatorFactory + { + public IExpressionValidator Create(VRM10ObjectExpression expressionAvatar) + { + return new DefaultExpressionValidator(expressionAvatar); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs.meta new file mode 100644 index 000000000..6b904c3a4 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/DefaultExpressionValidator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 50fc6f6edac946548edb751de64c1cb1 +timeCreated: 1611916405 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/ExpressionKey.cs b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionKey.cs new file mode 100644 index 000000000..a31f0e8ff --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionKey.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using VRMShaders; + +namespace UniVRM10 +{ + [Serializable] + public readonly struct ExpressionKey : IEquatable, IComparable + { + /// + /// Enum.ToString() のGC回避用キャッシュ + /// + private static readonly Dictionary PresetNameDictionary = + new Dictionary(); + + /// + /// ExpressionPreset と同名の名前を持つ独自に追加した Expression を区別するための prefix + /// + private static readonly string UnknownPresetPrefix = "Unknown_"; + + /// + /// Preset of this ExpressionKey. + /// + public readonly ExpressionPreset Preset; + + /// + /// Custom Name of this ExpressionKey. + /// This works if Preset was Custom. + /// + public readonly string Name; + + /// + /// Key's hashcode for comparison. + /// + private readonly int _hashCode; + + public bool IsBlink + { + get + { + switch (Preset) + { + case ExpressionPreset.blink: + case ExpressionPreset.blinkLeft: + case ExpressionPreset.blinkRight: + return true; + } + return false; + } + } + + public bool IsLookAt + { + get + { + switch (Preset) + { + case ExpressionPreset.lookUp: + case ExpressionPreset.lookDown: + case ExpressionPreset.lookLeft: + case ExpressionPreset.lookRight: + return true; + } + return false; + } + } + + public bool IsMouth + { + get + { + switch (Preset) + { + case ExpressionPreset.aa: + case ExpressionPreset.ih: + case ExpressionPreset.ou: + case ExpressionPreset.ee: + case ExpressionPreset.oh: + return true; + } + return false; + } + } + + public bool IsProcedual => IsBlink || IsLookAt || IsMouth; + + public ExpressionKey(ExpressionPreset preset, string customName = null) + { + Preset = preset; + + if (Preset != ExpressionPreset.custom) + { + if (PresetNameDictionary.ContainsKey((Preset))) + { + Name = PresetNameDictionary[Preset]; + _hashCode = Name.GetHashCode(); + } + else + { + PresetNameDictionary.Add(Preset, Preset.ToString()); + Name = PresetNameDictionary[Preset]; + _hashCode = Name.GetHashCode(); + } + } + else + { + if (string.IsNullOrEmpty(customName)) + { + throw new ArgumentException("name is required for ExpressionPreset.Custom"); + } + + Name = customName; + _hashCode = $"{UnknownPresetPrefix}{customName}".GetHashCode(); + } + } + + public static ExpressionKey CreateCustom(String key) + { + return new ExpressionKey(ExpressionPreset.custom, key); + } + + public static ExpressionKey CreateFromPreset(ExpressionPreset preset) + { + return new ExpressionKey(preset); + } + + public static ExpressionKey Happy => CreateFromPreset(ExpressionPreset.happy); + public static ExpressionKey Angry => CreateFromPreset(ExpressionPreset.angry); + public static ExpressionKey Sad => CreateFromPreset(ExpressionPreset.sad); + public static ExpressionKey Relaxed => CreateFromPreset(ExpressionPreset.relaxed); + public static ExpressionKey Surprised => CreateFromPreset(ExpressionPreset.surprised); + public static ExpressionKey Aa => CreateFromPreset(ExpressionPreset.aa); + public static ExpressionKey Ih => CreateFromPreset(ExpressionPreset.ih); + public static ExpressionKey Ou => CreateFromPreset(ExpressionPreset.ou); + public static ExpressionKey Ee => CreateFromPreset(ExpressionPreset.ee); + public static ExpressionKey Oh => CreateFromPreset(ExpressionPreset.oh); + public static ExpressionKey Blink => CreateFromPreset(ExpressionPreset.blink); + public static ExpressionKey BlinkLeft => CreateFromPreset(ExpressionPreset.blinkLeft); + public static ExpressionKey BlinkRight => CreateFromPreset(ExpressionPreset.blinkRight); + public static ExpressionKey LookUp => CreateFromPreset(ExpressionPreset.lookUp); + public static ExpressionKey LookDown => CreateFromPreset(ExpressionPreset.lookDown); + public static ExpressionKey LookLeft => CreateFromPreset(ExpressionPreset.lookLeft); + public static ExpressionKey LookRight => CreateFromPreset(ExpressionPreset.lookRight); + public static ExpressionKey Neutral => CreateFromPreset(ExpressionPreset.neutral); + + + public override string ToString() + { + return Name; + } + + public bool Equals(ExpressionKey other) + { + // Early pruning + if (_hashCode != other._hashCode) return false; + + if (Preset != other.Preset) return false; + if (Preset != ExpressionPreset.custom) return true; + return Name.Equals(other.Name, StringComparison.Ordinal); + } + + public override bool Equals(object obj) + { + if (obj is ExpressionKey key) + { + return Equals(key); + } + else + { + return false; + } + } + + public override int GetHashCode() + { + return _hashCode; + } + + public int CompareTo(ExpressionKey other) + { + if (Preset != other.Preset) + { + return Preset - other.Preset; + } + + return 0; + } + + public SubAssetKey SubAssetKey + { + get + { + return new SubAssetKey(typeof(VRM10Expression), this.ToString()); + } + } + + public static IEqualityComparer Comparer { get; } = new EqualityComparer(); + + internal sealed class EqualityComparer : IEqualityComparer + { + public bool Equals(ExpressionKey x, ExpressionKey y) + { + return x.Equals(y); + } + + public int GetHashCode(ExpressionKey obj) + { + return obj.GetHashCode(); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/ExpressionKey.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionKey.cs.meta new file mode 100644 index 000000000..5029b99fd --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionKey.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: adb1d8985f9fee54db1b8584da77ee08 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionMerger.cs new file mode 100644 index 000000000..c67515913 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionMerger.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniVRM10 +{ + + /// + /// ブレンドシェイプを蓄えてまとめて適用するクラス + /// + internal sealed class ExpressionMerger + { + /// + /// Key から Expression を得る + /// + Dictionary m_clipMap; + + /// + /// Expression のWeightを記録する + /// + Dictionary m_valueMap; + + MorphTargetBindingMerger m_morphTargetBindingMerger; + MaterialValueBindingMerger m_materialValueBindingMerger; + + + public ExpressionMerger(VRM10ObjectExpression expressions, Transform root) + { + m_clipMap = expressions.Clips.ToDictionary( + x => expressions.CreateKey(x.Clip), + x => x.Clip, + ExpressionKey.Comparer + ); + m_valueMap = new Dictionary(ExpressionKey.Comparer); + m_morphTargetBindingMerger = new MorphTargetBindingMerger(m_clipMap, root); + m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root); + } + + /// + /// まとめて反映する。1フレームに1回呼び出されることを想定 + /// + /// + public void SetValues(Dictionary expressionWeights) + { + foreach (var (key, weight) in expressionWeights) + { + AccumulateValue(key, weight); + } + + m_morphTargetBindingMerger.Apply(); + m_materialValueBindingMerger.Apply(); + } + + private void AccumulateValue(ExpressionKey key, float value) + { + m_valueMap[key] = value; + + VRM10Expression clip; + if (!m_clipMap.TryGetValue(key, out clip)) + { + return; + } + + m_morphTargetBindingMerger.AccumulateValue(key, value); + m_materialValueBindingMerger.AccumulateValue(clip, value); + } + + public void RestoreMaterialInitialValues() + { + m_materialValueBindingMerger.RestoreMaterialInitialValues(); + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/ExpressionMerger.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionMerger.cs.meta new file mode 100644 index 000000000..42f0dcbeb --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionMerger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b21afa8373708b04b9f656f894daf392 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/ExpressionPreset.cs b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionPreset.cs new file mode 100644 index 000000000..7ed98db06 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionPreset.cs @@ -0,0 +1,25 @@ +namespace UniVRM10 +{ + public enum ExpressionPreset + { + custom, + happy, + angry, + sad, + relaxed, + surprised, + aa, + ih, + ou, + ee, + oh, + blink, + blinkLeft, + blinkRight, + lookUp, + lookDown, + lookLeft, + lookRight, + neutral, + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/ExpressionPreset.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionPreset.cs.meta new file mode 100644 index 000000000..d38aa6b4d --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/ExpressionPreset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 959cd7efa29185648bb7996d11eb2a14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidator.cs b/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidator.cs new file mode 100644 index 000000000..f417ce01d --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidator.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace UniVRM10 +{ + /// + /// Validate Expression constraints (ex. overrideBlink) + /// + public interface IExpressionValidator + { + /// + /// Validate input weights with Expression constraints. + /// + void Validate(IReadOnlyDictionary inputWeights, IDictionary actualWeights, + LookAtEyeDirection inputEyeDirection, out LookAtEyeDirection actualEyeDirection, + out float blinkOverrideRate, out float lookAtOverrideRate, out float mouthOverrideRate); + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidator.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidator.cs.meta new file mode 100644 index 000000000..2526efa13 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1de32ec5101c48298bb78d6835b5d4e2 +timeCreated: 1611916321 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs b/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs new file mode 100644 index 000000000..c4d402206 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs @@ -0,0 +1,7 @@ +namespace UniVRM10 +{ + public interface IExpressionValidatorFactory + { + IExpressionValidator Create(VRM10ObjectExpression expressionAvatar); + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs.meta new file mode 100644 index 000000000..ddb108f5e --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/IExpressionValidatorFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a46e9573ca04d098b71780a849cd30e +timeCreated: 1611916369 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs b/Assets/External/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs new file mode 100644 index 000000000..77bfcf6f7 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace UniVRM10 +{ + /// + /// Receive LooAtEyeDirection, and Apply to bone transforms. + /// + internal interface ILookAtEyeDirectionApplicable + { + void Apply(LookAtEyeDirection eyeDirection, Dictionary actualWeights); + void Restore(); + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs.meta new file mode 100644 index 000000000..891a58e73 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/ILookAtEyeDirectionApplicable.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 099d76e017bc4b229ed2f852990b18ea +timeCreated: 1612166872 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MaterialColorBinding.cs b/Assets/External/VRM10/Runtime/Components/Expression/MaterialColorBinding.cs new file mode 100644 index 000000000..2fc12cc01 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MaterialColorBinding.cs @@ -0,0 +1,35 @@ +using System; +using UnityEngine; + +namespace UniVRM10 +{ + [Serializable] + public struct MaterialColorBinding : IEquatable + { + public String MaterialName; + public UniGLTF.Extensions.VRMC_vrm.MaterialColorType BindType; + public Vector4 TargetValue; + + public bool Equals(MaterialColorBinding other) + { + return string.Equals(MaterialName, other.MaterialName) && BindType.Equals(other.BindType) && TargetValue.Equals(other.TargetValue); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MaterialColorBinding && Equals((MaterialColorBinding)obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = (MaterialName != null ? MaterialName.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ BindType.GetHashCode(); + hashCode = (hashCode * 397) ^ TargetValue.GetHashCode(); + return hashCode; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MaterialColorBinding.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/MaterialColorBinding.cs.meta new file mode 100644 index 000000000..907161af3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MaterialColorBinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 985d3a33d6e0e144e99deed88e048b59 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MaterialUVBinding.cs b/Assets/External/VRM10/Runtime/Components/Expression/MaterialUVBinding.cs new file mode 100644 index 000000000..2fe88d0dd --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MaterialUVBinding.cs @@ -0,0 +1,46 @@ +using System; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// 対象のマテリアルのすべての テクスチャの Scale/Offset をまとめて変更する。 + /// 主に _MainTex_ST 値 + /// + [Serializable] + public struct MaterialUVBinding : IEquatable + { + /// + /// モデルのヒエラルキーから得たマテリアルの中から名前で検索する。 + /// 同名マテリアルはやめてください。 + /// + public String MaterialName; + + public Vector2 Scaling; // default: Vector2.one + public Vector2 Offset; // default: Vector2.zero + + public Vector4 ScalingOffset => new Vector4(Scaling.x, Scaling.y, Offset.x, Offset.y); + + public bool Equals(MaterialUVBinding other) + { + return string.Equals(MaterialName, other.MaterialName) && Scaling.Equals(other.Scaling) && Offset.Equals(other.Offset); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MaterialUVBinding && Equals((MaterialUVBinding)obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = (MaterialName != null ? MaterialName.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ Scaling.GetHashCode(); + hashCode = (hashCode * 397) ^ Offset.GetHashCode(); + return hashCode; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MaterialUVBinding.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/MaterialUVBinding.cs.meta new file mode 100644 index 000000000..012631962 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MaterialUVBinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5a80fb172c64ddc4e865ae0e0130f827 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs b/Assets/External/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs new file mode 100644 index 000000000..d0bd550cf --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections.Generic; +using UniGLTF.Extensions.VRMC_vrm; +using UnityEngine; +using VRMShaders.VRM10.MToon10.Runtime; + +namespace UniVRM10 +{ + /// + /// Base + (A.Target - Base) * A.Weight + (B.Target - Base) * B.Weight ... + /// + internal sealed class MaterialValueBindingMerger + { + private static readonly string COLOR_PROPERTY = MToon10Prop.BaseColorFactor.ToUnityShaderLabName(); + private static readonly string EMISSION_COLOR_PROPERTY = MToon10Prop.EmissiveFactor.ToUnityShaderLabName(); + private static readonly string RIM_COLOR_PROPERTY = MToon10Prop.ParametricRimColorFactor.ToUnityShaderLabName(); + private static readonly string OUTLINE_COLOR_PROPERTY = MToon10Prop.OutlineColorFactor.ToUnityShaderLabName(); + private static readonly string SHADE_COLOR_PROPERTY = MToon10Prop.ShadeColorFactor.ToUnityShaderLabName(); + private static readonly string MATCAP_COLOR_PROPERTY = MToon10Prop.MatcapColorFactor.ToUnityShaderLabName(); + + public static string GetProperty(MaterialColorType bindType) + { + switch (bindType) + { + // case MaterialBindType.UvOffset: + // case MaterialBindType.UvScale: + // return UV_PROPERTY; + + case MaterialColorType.color: + return COLOR_PROPERTY; + + case MaterialColorType.emissionColor: + return EMISSION_COLOR_PROPERTY; + + case MaterialColorType.shadeColor: + return SHADE_COLOR_PROPERTY; + + case MaterialColorType.rimColor: + return RIM_COLOR_PROPERTY; + + case MaterialColorType.outlineColor: + return OUTLINE_COLOR_PROPERTY; + + case MaterialColorType.matcapColor: + return MATCAP_COLOR_PROPERTY; + } + + throw new NotImplementedException(); + } + + #region MaterialMap + /// + /// MaterialValueBinding の対象になるマテリアルの情報を記録する + /// + Dictionary m_materialMap = new Dictionary(); + + void InitializeMaterialMap(Dictionary clipMap, Transform root) + { + Dictionary materialNameMap = new Dictionary(); + foreach (var renderer in root.GetComponentsInChildren()) + { + foreach (var material in renderer.sharedMaterials) + { + if (material != null && !materialNameMap.ContainsKey(material.name)) + { + materialNameMap.Add(material.name, material); + } + } + } + + foreach (var kv in clipMap) + { + foreach (var binding in kv.Value.MaterialColorBindings) + { + PreviewMaterialItem item; + if (!m_materialMap.TryGetValue(binding.MaterialName, out item)) + { + if (!materialNameMap.TryGetValue(binding.MaterialName, out Material material)) + { + // not found skip + continue; + } + item = new PreviewMaterialItem(material); + m_materialMap.Add(binding.MaterialName, item); + } + // color default value + var propName = GetProperty(binding.BindType); + if (!item.PropMap.ContainsKey(binding.BindType)) + { + item.PropMap.Add(binding.BindType, new PropItem + { + Name = propName, + DefaultValues = item.Material.GetVector(propName), + }); + } + } + + foreach (var binding in kv.Value.MaterialUVBindings) + { + PreviewMaterialItem item; + if (!m_materialMap.TryGetValue(binding.MaterialName, out item)) + { + if (!materialNameMap.TryGetValue(binding.MaterialName, out Material material)) + { + // not found skip + continue; + } + item = new PreviewMaterialItem(material); + m_materialMap.Add(binding.MaterialName, item); + } + } + } + } + + /// + /// m_materialMap に記録した値に Material を復旧する + /// + public void RestoreMaterialInitialValues() + { + foreach (var kv in m_materialMap) + { + kv.Value.RestoreInitialValues(); + } + } + #endregion + + #region Accumulate + struct DictionaryKeyMaterialValueBindingComparer : IEqualityComparer + { + public bool Equals(MaterialColorBinding x, MaterialColorBinding y) + { + return x.TargetValue == y.TargetValue && x.MaterialName == y.MaterialName && x.BindType == y.BindType; + } + + public int GetHashCode(MaterialColorBinding obj) + { + return obj.GetHashCode(); + } + } + + static DictionaryKeyMaterialValueBindingComparer comparer = new DictionaryKeyMaterialValueBindingComparer(); + + /// + /// MaterialValueの適用値を蓄積する + /// + /// + /// + /// + Dictionary m_materialColorMap = new Dictionary(comparer); + + /// + /// UV Scale/Offset + /// + Dictionary m_materialUVMap = new Dictionary(); + + public void AccumulateValue(VRM10Expression clip, float value) + { + // material color + foreach (var binding in clip.MaterialColorBindings) + { + float acc; + if (m_materialColorMap.TryGetValue(binding, out acc)) + { + m_materialColorMap[binding] = acc + value; + } + else + { + m_materialColorMap[binding] = value; + } + } + + // maetrial uv + foreach (var binding in clip.MaterialUVBindings) + { + if (m_materialMap.TryGetValue(binding.MaterialName, out PreviewMaterialItem item)) + { + var delta = binding.ScalingOffset - item.DefaultUVScaleOffset; + + Vector4 acc; + if (m_materialUVMap.TryGetValue(binding.MaterialName, out acc)) + { + m_materialUVMap[binding.MaterialName] = acc + delta * value; + } + else + { + m_materialUVMap[binding.MaterialName] = item.DefaultUVScaleOffset + delta * value; + } + } + } + } + + struct MaterialTarget : IEquatable + { + public string MaterialName; + public string ValueName; + + public bool Equals(MaterialTarget other) + { + return MaterialName == other.MaterialName + && ValueName == other.ValueName; + } + + public override bool Equals(object obj) + { + if (obj is MaterialTarget) + { + return Equals((MaterialTarget)obj); + } + else + { + return false; + } + } + + public override int GetHashCode() + { + if (MaterialName == null || ValueName == null) + { + return 0; + } + return MaterialName.GetHashCode() + ValueName.GetHashCode(); + } + + public static MaterialTarget Create(MaterialColorBinding binding) + { + return new MaterialTarget + { + MaterialName = binding.MaterialName, + ValueName = GetProperty(binding.BindType), + }; + } + } + + // UVアクセスするテクスチャーのScaleOffsetプロパティの一覧 + static Dictionary UVPropMap = new Dictionary + { + {"Standard", new string[]{ + "_MainTex_ST", + }}, + {"VRM10/MToon10", new string[]{ + "_MainTex_ST", + }}, + }; + static string[] DefaultProps = { "_MainTex_ST" }; + public static String[] GetUVProps(string shaderName) + { + if (UVPropMap.TryGetValue(shaderName, out string[] props)) + { + return props; + } + else + { + return DefaultProps; + } + } + + HashSet m_used = new HashSet(); + public void Apply() + { + { + m_used.Clear(); + foreach (var kv in m_materialColorMap) + { + var key = MaterialTarget.Create(kv.Key); + PreviewMaterialItem item; + if (m_materialMap.TryGetValue(key.MaterialName, out item)) + { + // 初期値(コンストラクタで記録) + var initial = item.PropMap[kv.Key.BindType].DefaultValues; + if (!m_used.Contains(key)) + { + // + // m_used に入っていない場合は、このフレームで初回の呼び出しになる。 + // (Apply はフレームに一回呼ばれる想定) + // 初回は、値を初期値に戻す。 + // + item.Material.SetColor(key.ValueName, initial); + m_used.Add(key); + } + + // 現在値 + var current = item.Material.GetVector(key.ValueName); + // 変化量 + var value = (kv.Key.TargetValue - initial) * kv.Value; + // 適用 + item.Material.SetColor(key.ValueName, current + value); + } + else + { + // エラー? + } + } + m_materialColorMap.Clear(); + } + + { + foreach (var kv in m_materialUVMap) + { + PreviewMaterialItem item; + if (m_materialMap.TryGetValue(kv.Key, out item)) + { + // + // Standard and MToon use _MainTex_ST as uv0 scale/offset + // + foreach (var prop in GetUVProps(item.Material.shader.name)) + { + item.Material.SetVector(prop, kv.Value); + } + } + } + m_materialUVMap.Clear(); + } + } + #endregion + + public MaterialValueBindingMerger(Dictionary clipMap, Transform root) + { + InitializeMaterialMap(clipMap, root); + } + } +} diff --git a/Assets/External/UniGLTF/Tests/UniJSON/Json/JsonDiffTests.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs.meta similarity index 76% rename from Assets/External/UniGLTF/Tests/UniJSON/Json/JsonDiffTests.cs.meta rename to Assets/External/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs.meta index 43396090a..1caec40de 100644 --- a/Assets/External/UniGLTF/Tests/UniJSON/Json/JsonDiffTests.cs.meta +++ b/Assets/External/VRM10/Runtime/Components/Expression/MaterialValueBindingMerger.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: bafda51ddeeb2b84b920b119176499b8 -timeCreated: 1532154188 +guid: b6aebf9f38de41c4a9cfd03e85756e9e +timeCreated: 1541229189 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs new file mode 100644 index 000000000..9a4ca77c3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs @@ -0,0 +1,82 @@ +using System; +using UnityEngine; + +namespace UniVRM10 +{ + [Serializable] + public struct MorphTargetBinding : IEquatable + { + /// + /// Unity の BlendShape の値域は 0-100 + /// + public const float VRM_TO_UNITY = 100.0f; + + /// + /// VRM-1.0 の MorphTargetBinding.Weight の値域は 0-1.0 + /// + public const float UNITY_TO_VRM = 0.01f; + + public const float MAX_WEIGHT = 1.0f; + + /// + /// SkinnedMeshRenderer.BlendShape[Index].Weight を 指し示す。 + /// + /// [トレードオフ] + /// + /// * SkinnedMeshRenderer そのものの方がわかりやすい + /// * Prefab 生成時の順番問題 + /// * Prefabの中で、Prefab自体を参照するので String の方が扱いが楽(Prefab生成時にトラブルになりがち。Runtimeロードでは問題ない) + /// * モデル変更時の改変への強さ + /// + /// + + // シリアライズしてEditorから変更するので readonly 不可 + public /*readonly*/ String RelativePath; + public /*readonly*/ int Index; + public /*readonly*/ float Weight; + + /// + /// + /// + /// + /// + /// 0 to 1.0 + public MorphTargetBinding(string path, int index, float weight) + { + RelativePath = path; + Index = index; + if (weight > MAX_WEIGHT) + { + Debug.LogWarning($"MorphTargetBinding: {weight} > {MAX_WEIGHT}"); + } + Weight = weight; + } + + public override string ToString() + { + return string.Format("{0}[{1}]=>{2}", RelativePath, Index, Weight); + } + + public bool Equals(MorphTargetBinding other) + { + return string.Equals(RelativePath, other.RelativePath) && Index == other.Index && Weight.Equals(other.Weight); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MorphTargetBinding && Equals((MorphTargetBinding)obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = (RelativePath != null ? RelativePath.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ Index; + hashCode = (hashCode * 397) ^ Weight.GetHashCode(); + return hashCode; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs.meta new file mode 100644 index 000000000..52e569872 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d69431f58097b7d4dbafd4cd5695881d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger.meta b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger.meta new file mode 100644 index 000000000..e8493187f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6ced9964a99042e383f60c2f065fa807 +timeCreated: 1692091240 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetBindingMerger.cs b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetBindingMerger.cs new file mode 100644 index 000000000..3c99a1a72 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetBindingMerger.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Optimized implementation of MorphTarget binding merger. + /// + /// Dictionary を使用すると、その GetEnumerator()(foreach) や get/set を 100,1000 オーダーで呼び出すことになる。 + /// するとモバイル環境ではかなりの定常負荷になってしまうため、その使用を避けて実装する。 + /// + internal sealed class MorphTargetBindingMerger + { + private readonly ExpressionKey[] _keyOrder; + private readonly Dictionary _keyIndexReverseMap = new(ExpressionKey.Comparer); + + /// + /// index access with [_keyOrder][*] + /// + private readonly RuntimeMorphTargetBinding[][] _bindings; + private readonly MorphTargetIdentifier[] _morphTargetOrder; + + /// + /// index access with [_morphTargetOrder] + /// + private readonly float?[] _accumulatedWeights; + + public MorphTargetBindingMerger(Dictionary expressions, Transform modelRoot) + { + _keyOrder = expressions.Keys.ToArray(); + for (var keyIdx = 0; keyIdx < _keyOrder.Length; ++keyIdx) + { + _keyIndexReverseMap.Add(_keyOrder[keyIdx], keyIdx); + } + + var morphTargetList = new List(); + _bindings = new RuntimeMorphTargetBinding[_keyOrder.Length][]; + for (var keyIdx = 0; keyIdx < _keyOrder.Length; ++keyIdx) + { + var key = _keyOrder[keyIdx]; + var expression = expressions[key]; + + var bindingsPerKey = new List(); + foreach (var rawBinding in expression.MorphTargetBindings) + { + var morphTarget = MorphTargetIdentifier.Create(rawBinding, modelRoot); + if (!morphTarget.HasValue) + { + Debug.LogWarning($"Invalid {nameof(MorphTargetBinding)} found: {rawBinding}"); + continue; + } + if (bindingsPerKey.FindIndex(x => morphTarget.Value.Equals(x.TargetIdentifier)) >= 0) + { + Debug.LogWarning($"Duplicate MorphTargetBinding found: {rawBinding}"); + continue; + } + + var morphTargetIdx = morphTargetList.FindIndex(x => morphTarget.Value.Equals(x)); + if (morphTargetIdx < 0) + { + morphTargetIdx = morphTargetList.Count; + morphTargetList.Add(morphTarget.Value); + } + + var bindingWeight = rawBinding.Weight * MorphTargetBinding.VRM_TO_UNITY; + bindingsPerKey.Add(new RuntimeMorphTargetBinding(morphTarget.Value, inputWeight => + { + _accumulatedWeights[morphTargetIdx] = (_accumulatedWeights[morphTargetIdx] ?? 0f) + bindingWeight * inputWeight; + })); + } + _bindings[keyIdx] = bindingsPerKey.ToArray(); + } + _morphTargetOrder = morphTargetList.ToArray(); + _accumulatedWeights = new float?[_morphTargetOrder.Length]; + } + + public void AccumulateValue(ExpressionKey key, float value) + { + if (!_keyIndexReverseMap.TryGetValue(key, out var idx)) return; + + foreach (var binding in _bindings[idx]) + { + binding.WeightApplier(value); + } + } + + public void Apply() + { + for (var idx = 0; idx < _morphTargetOrder.Length; ++idx) + { + var morphTarget = _morphTargetOrder[idx]; + var weight = _accumulatedWeights[idx]; + if (!weight.HasValue) continue; + if (morphTarget.TargetRenderer) + { + morphTarget.TargetRenderer.SetBlendShapeWeight(morphTarget.TargetBlendShapeIndex, weight.Value); + } + _accumulatedWeights[idx] = null; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetBindingMerger.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetBindingMerger.cs.meta new file mode 100644 index 000000000..881314e68 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetBindingMerger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 166681d1a9384d8ba5ed2ee1f8c127a5 +timeCreated: 1692089928 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetIdentifier.cs b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetIdentifier.cs new file mode 100644 index 000000000..c230a708b --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetIdentifier.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + internal readonly struct MorphTargetIdentifier : IEquatable + { + public static MorphTargetIdentifier? Create(MorphTargetBinding binding, Transform modelRoot) + { + if (modelRoot == null) return null; + + var targetGameObject = modelRoot.Find(binding.RelativePath); + if (targetGameObject == null) return null; + + var targetRenderer = targetGameObject.GetComponent(); + if (targetRenderer == null) return null; + if (targetRenderer.sharedMesh == null) return null; + if (targetRenderer.sharedMesh.blendShapeCount <= binding.Index) return null; + + return new MorphTargetIdentifier(targetRenderer, binding.Index); + } + + public SkinnedMeshRenderer TargetRenderer { get; } + public int TargetRendererInstanceId { get; } + public int TargetBlendShapeIndex { get; } + + public MorphTargetIdentifier(SkinnedMeshRenderer targetRenderer, int targetBlendShapeIndex) + { + TargetRenderer = targetRenderer; + TargetRendererInstanceId = targetRenderer.GetInstanceID(); + TargetBlendShapeIndex = targetBlendShapeIndex; + } + + public bool Equals(MorphTargetIdentifier other) + { + return TargetRendererInstanceId == other.TargetRendererInstanceId && TargetBlendShapeIndex == other.TargetBlendShapeIndex; + } + + public override bool Equals(object obj) + { + return obj is MorphTargetIdentifier other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(TargetRendererInstanceId, TargetBlendShapeIndex); + } + + #region IEqualityComparer + public static IEqualityComparer Comparer { get; } = new EqualityComparer(); + + private sealed class EqualityComparer : IEqualityComparer + { + public bool Equals(MorphTargetIdentifier x, MorphTargetIdentifier y) + { + return x.TargetRendererInstanceId == y.TargetRendererInstanceId && x.TargetBlendShapeIndex == y.TargetBlendShapeIndex; + } + + public int GetHashCode(MorphTargetIdentifier obj) + { + return HashCode.Combine(obj.TargetRendererInstanceId, obj.TargetBlendShapeIndex); + } + } + #endregion + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetIdentifier.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetIdentifier.cs.meta new file mode 100644 index 000000000..7a6652743 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/MorphTargetIdentifier.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2d943de827f04f72aa4ea46868826987 +timeCreated: 1692191013 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/RuntimeMorphTargetBinding.cs b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/RuntimeMorphTargetBinding.cs new file mode 100644 index 000000000..0657cc055 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/RuntimeMorphTargetBinding.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + internal readonly struct RuntimeMorphTargetBinding + { + public MorphTargetIdentifier TargetIdentifier { get; } + public Action WeightApplier { get; } + + public RuntimeMorphTargetBinding(MorphTargetIdentifier targetIdentifier, Action weightApplier) + { + TargetIdentifier = targetIdentifier; + WeightApplier = weightApplier; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/RuntimeMorphTargetBinding.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/RuntimeMorphTargetBinding.cs.meta new file mode 100644 index 000000000..c98efb4ac --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger/RuntimeMorphTargetBinding.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 80f2db6641bf44f192a67c98006db559 +timeCreated: 1692091250 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/Preview.meta b/Assets/External/VRM10/Runtime/Components/Expression/Preview.meta new file mode 100644 index 000000000..d5bcc3675 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/Preview.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f7b7c8fb7bd5f244a45e72845748d31 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMaterialUtil.cs b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMaterialUtil.cs new file mode 100644 index 000000000..aa9ab6b44 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMaterialUtil.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +#if UNITY_EDITOR +using UnityEditor; + +namespace UniVRM10 +{ + public static class PreviewMaterialUtil + { + public static bool TryCreateForPreview(Material material, out PreviewMaterialItem item) + { + item = new PreviewMaterialItem(material); + + var propNames = new List(); + var hasError = false; + for (int i = 0; i < ShaderUtil.GetPropertyCount(material.shader); ++i) + { + var propType = ShaderUtil.GetPropertyType(material.shader, i); + var name = ShaderUtil.GetPropertyName(material.shader, i); + + switch (propType) + { + case ShaderUtil.ShaderPropertyType.Color: + // 色 + { + if (!PreviewMaterialItem.TryGetBindType(name, out var bindType)) + { + Debug.LogError($"{material.shader.name}.{name} is unsupported property name"); + hasError = true; + continue; + } + + if (!Enum.TryParse(propType.ToString(), true, out ShaderPropertyType propertyType)) + { + Debug.LogError($"{material.shader.name}.{propertyType.ToString()} is unsupported property type"); + hasError = true; + continue; + } + + item.PropMap.Add(bindType, new PropItem + { + Name = name, + PropertyType = propertyType, + DefaultValues = material.GetColor(name), + }); + propNames.Add(name); + } + break; + + case ShaderUtil.ShaderPropertyType.TexEnv: + break; + } + } + item.PropNames = propNames.ToArray(); + + return !hasError; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMaterialUtil.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMaterialUtil.cs.meta new file mode 100644 index 000000000..612774902 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMaterialUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 45f9865ffd894b04bad0c39f53154f55 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs new file mode 100644 index 000000000..913f9cf53 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs @@ -0,0 +1,143 @@ +using System.Linq; +using UnityEngine; +using System; +using System.Collections.Generic; + +namespace UniVRM10 +{ + [Serializable] + public sealed class PreviewMeshItem + { + public string Path + { + get; + private set; + } + + public SkinnedMeshRenderer SkinnedMeshRenderer + { + get; + private set; + } + + public Mesh Mesh + { + get; + private set; + } + + public string[] BlendShapeNames + { + get; + private set; + } + + public int BlendShapeCount + { + get { return BlendShapeNames.Length; } + } + + public Material[] Materials + { + get; + private set; + } + + Transform m_transform; + public Vector3 Position + { + get { return m_transform.position; } + } + public Quaternion Rotation + { + get { return m_transform.rotation; } + } + + PreviewMeshItem(string path, Transform transform, Material[] materials) + { + Path = path; + m_transform = transform; + Materials = materials; + } + + public void Bake(IEnumerable values, float weight) + { + if (SkinnedMeshRenderer == null) return; + + // Update baked mesh + if (values != null) + { + // clear + for (int i = 0; i < BlendShapeCount; ++i) + { + SkinnedMeshRenderer.SetBlendShapeWeight(i, 0); + } + + foreach (var x in values) + { + if (x.RelativePath == Path) + { + if (x.Index >= 0 && x.Index < SkinnedMeshRenderer.sharedMesh.blendShapeCount) + { + SkinnedMeshRenderer.SetBlendShapeWeight(x.Index, x.Weight * weight * MorphTargetBinding.VRM_TO_UNITY); + } + else + { + Debug.LogWarningFormat("Out of range {0}: 0 <= {1} < {2}", + SkinnedMeshRenderer.name, + x.Index, + SkinnedMeshRenderer.sharedMesh.blendShapeCount); + } + } + } + } + SkinnedMeshRenderer.BakeMesh(Mesh); + } + + public static PreviewMeshItem Create(Transform t, Transform root, + Func getOrCreateMaterial) + { + //Debug.Log("create"); + + var meshFilter = t.GetComponent(); + var meshRenderer = t.GetComponent(); + var skinnedMeshRenderer = t.GetComponent(); + if (meshFilter != null && meshRenderer != null) + { + // copy + meshRenderer.sharedMaterials = meshRenderer.sharedMaterials.Select(x => getOrCreateMaterial(x)).ToArray(); + return new PreviewMeshItem(t.RelativePathFrom(root), t, meshRenderer.sharedMaterials) + { + Mesh = meshFilter.sharedMesh + }; + } + else if (skinnedMeshRenderer != null) + { + // copy + skinnedMeshRenderer.sharedMaterials = skinnedMeshRenderer.sharedMaterials.Select(x => getOrCreateMaterial(x)).ToArray(); + if (skinnedMeshRenderer.sharedMesh.blendShapeCount > 0) + { + // bake required + var sharedMesh = skinnedMeshRenderer.sharedMesh; + return new PreviewMeshItem(t.RelativePathFrom(root), t, skinnedMeshRenderer.sharedMaterials) + { + SkinnedMeshRenderer = skinnedMeshRenderer, + Mesh = new Mesh(), // for bake + BlendShapeNames = Enumerable.Range(0, sharedMesh.blendShapeCount).Select(x => sharedMesh.GetBlendShapeName(x)).ToArray() + }; + } + else + { + return new PreviewMeshItem(t.RelativePathFrom(root), t, skinnedMeshRenderer.sharedMaterials) + { + Mesh = skinnedMeshRenderer.sharedMesh, + }; + } + } + else + { + return null; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs.meta new file mode 100644 index 000000000..fe62f21a5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b634c6524bdf71744a1d448ccbec7eaa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs new file mode 100644 index 000000000..51d83ba51 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs @@ -0,0 +1,333 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using System; +using VRMShaders; + + +namespace UniVRM10 +{ + /// + /// プレビュー向けのシーンを管理する + /// + public sealed class PreviewSceneManager : MonoBehaviour + { + public GameObject Prefab; + + public bool hasError; + +#if UNITY_EDITOR + public static PreviewSceneManager GetOrCreate(GameObject prefab) + { + if (prefab == null) + { + return null; + } + + PreviewSceneManager manager = null; + + // if we already instantiated a PreviewInstance previously but just lost the reference, then use that same instance instead of making a new one + var managers = GameObject.FindObjectsOfType(); + foreach (var x in managers) + { + if (x.Prefab == prefab) + { + Debug.LogFormat("find {0}", manager); + return manager; + } + Debug.LogFormat("destroy {0}", x); + GameObject.DestroyImmediate(x.gameObject); + } + + //Debug.Log("new prefab. instanciate"); + // no previous instance detected, so now let's make a fresh one + // very important: this loads the PreviewInstance prefab and temporarily instantiates it into PreviewInstance + var go = GameObject.Instantiate(prefab, + prefab.transform.position, + prefab.transform.rotation + ); + go.name = "__PREVIEW_SCENE_MANGER__"; + manager = go.AddComponent(); + manager.Initialize(prefab); + + // HideFlags are special editor-only settings that let you have *secret* GameObjects in a scene, or to tell Unity not to save that temporary GameObject as part of the scene + foreach (var x in go.transform.Traverse()) + { + if (Symbols.VRM_DEVELOP) + { + x.gameObject.hideFlags = HideFlags.None | + HideFlags.DontSave; + } + else + { + x.gameObject.hideFlags = HideFlags.None | + HideFlags.DontSave | + HideFlags.HideAndDontSave; + } + } + + return manager; + } +#endif + + public void Clean() + { + foreach (var kv in m_materialMap) + { + UnityEngine.Object.DestroyImmediate(kv.Value.Material); + } + } + +#if UNITY_EDITOR + private void Initialize(GameObject prefab) + { + hasError = false; + + //Debug.LogFormat("[PreviewSceneManager.Initialize] {0}", prefab); + Prefab = prefab; + + var materialNames = new List(); + + // preview シーン用に Material を複製する。 + // Expression のカスタムエディタのマテリアル変更は、 + // 複製したものに適用される。 + var map = new Dictionary(); + Func getOrCreateMaterial = src => + { + if (src == null) return null; + if (string.IsNullOrEmpty(src.name)) return null; // ! + + Material dst; + if (!map.TryGetValue(src, out dst)) + { + dst = new Material(src); + map.Add(src, dst); + + if (!PreviewMaterialUtil.TryCreateForPreview(dst, out var previewMaterialItem)) + { + hasError = true; + // Return cloned material for preview + return dst; + } + + m_materialMap.Add(src.name, previewMaterialItem); + + //Debug.LogFormat("add material {0}", src.name); + materialNames.Add(src.name); + } + return dst; + }; + + m_meshes = transform.Traverse() + .Select(x => PreviewMeshItem.Create(x, transform, getOrCreateMaterial)) + .Where(x => x != null) + .ToArray() + ; + MaterialNames = materialNames.ToArray(); + + m_blendShapeMeshes = m_meshes + .Where(x => x.SkinnedMeshRenderer != null + && x.SkinnedMeshRenderer.sharedMesh.blendShapeCount > 0) + .ToArray(); + + m_rendererPathList = m_meshes.Select(x => x.Path).ToArray(); + m_skinnedMeshRendererPathList = m_meshes + .Where(x => x.SkinnedMeshRenderer != null) + .Select(x => x.Path) + .ToArray(); + + var animator = GetComponent(); + if (animator != null) + { + var head = animator.GetBoneTransform(HumanBodyBones.Head); + if (head != null) + { + m_target = head; + } + } + } +#endif + + PreviewMeshItem[] m_meshes; + PreviewMeshItem[] m_blendShapeMeshes; + public IEnumerable EnumRenderItems + { + get + { + if (m_meshes != null) + { + foreach (var x in m_meshes) + { + yield return x; + } + } + } + } + + public string[] MaterialNames + { + get; + private set; + } + + Dictionary m_materialMap = new Dictionary(); + + string[] m_rendererPathList; + public string[] RendererPathList + { + get { return m_rendererPathList; } + } + + string[] m_skinnedMeshRendererPathList; + public string[] SkinnedMeshRendererPathList + { + get { return m_skinnedMeshRendererPathList; } + } + + public string[] GetBlendShapeNames(int blendShapeMeshIndex) + { + if (blendShapeMeshIndex >= 0 && blendShapeMeshIndex < m_blendShapeMeshes.Length) + { + var item = m_blendShapeMeshes[blendShapeMeshIndex]; + return item.BlendShapeNames; + } + + return null; + } + + public PreviewMaterialItem GetMaterialItem(string materialName) + { + PreviewMaterialItem item; + if (!m_materialMap.TryGetValue(materialName, out item)) + { + return null; + } + + return item; + } + + public Transform m_target; + public Vector3 TargetPosition + { + get + { + if (m_target == null) + { + return new Vector3(0, 1.4f, 0); + } + return m_target.position + new Vector3(0, 0.1f, 0); + } + } + +#if UNITY_EDITOR + Bounds m_bounds; + public void Bake(VRM10Expression bake, float weight) + { + if (bake == null) + { + return; + } + + // + // Bake Expression + // + m_bounds = default(Bounds); + if (m_meshes != null) + { + if (bake != null) + { + foreach (var x in m_meshes) + { + x.Bake(bake.MorphTargetBindings, weight); + m_bounds.Expand(x.Mesh.bounds.size); + } + } + } + + // + // Update Material + // + if (m_materialMap != null) + { + // clear + foreach (var kv in m_materialMap) + { + kv.Value.Clear(); + } + + // color + if (bake.MaterialColorBindings != null) + { + foreach (var x in bake.MaterialColorBindings) + { + PreviewMaterialItem item; + if (m_materialMap.TryGetValue(x.MaterialName, out item)) + { + //Debug.Log("set material"); + PropItem prop; + if (item.PropMap.TryGetValue(x.BindType, out prop)) + { + // var valueName = x.ValueName; + // if (valueName.EndsWith("_ST_S") + // || valueName.EndsWith("_ST_T")) + // { + // valueName = valueName.Substring(0, valueName.Length - 2); + // } + + var value = item.Material.GetVector(prop.Name); + //Debug.LogFormat("{0} => {1}", valueName, x.TargetValue); + value += ((x.TargetValue - prop.DefaultValues) * weight); + item.Material.SetColor(prop.Name, value); + } + } + } + } + + // uv + if (bake.MaterialUVBindings != null) + { + foreach (var x in bake.MaterialUVBindings) + { + PreviewMaterialItem item; + if (m_materialMap.TryGetValue(x.MaterialName, out item)) + { + item.AddScaleOffset(x.ScalingOffset, weight); + } + } + } + } + } +#endif + + /// + /// カメラパラメーターを決める + /// + /// + public void SetupCamera(Camera camera, Vector3 target, float yaw, float pitch, Vector3 position) + { + camera.backgroundColor = Color.gray; + camera.clearFlags = CameraClearFlags.Color; + + // projection + //float magnitude = m_bounds.extents.magnitude * 0.5f; + //float distance = magnitude; + //var distance = target.magnitude; + + camera.fieldOfView = 27f; + camera.nearClipPlane = 0.3f; + camera.farClipPlane = -position.z /*+ magnitude*/ * 2.1f; + + var t = Matrix4x4.Translate(position); + var r = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(pitch, yaw, 0), Vector3.one); + // 回転してから移動 + var m = r * t; + + camera.transform.position = target + m.ExtractPosition(); + camera.transform.rotation = m.ExtractRotation(); + //camera.transform.LookAt(target); + + //previewLayer のみ表示する + //camera.cullingMask = 1 << PreviewLayer; + } + } +} diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Standard.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs.meta similarity index 76% rename from Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Standard.cs.meta rename to Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs.meta index abf6b6c83..c662e7df7 100644 --- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Standard.cs.meta +++ b/Assets/External/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 54043e349b047bf4b8f127cd919a757d -timeCreated: 1533542890 +guid: 8753271443aa4cc4d93334c992ea6a27 +timeCreated: 1523096653 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Assets/External/VRM10/Runtime/Components/Expression/PreviewMaterialItem.cs b/Assets/External/VRM10/Runtime/Components/Expression/PreviewMaterialItem.cs new file mode 100644 index 000000000..460f14809 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/PreviewMaterialItem.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UniGLTF.Extensions.VRMC_vrm; +using VRMShaders.VRM10.MToon10.Runtime; + + +namespace UniVRM10 +{ + public enum ShaderPropertyType + { + // + // 概要: + // Color Property. + Color = 0, + // + // 概要: + // Vector Property. + Vector = 1, + // + // 概要: + // Float Property. + Float = 2, + // + // 概要: + // Range Property. + Range = 3, + // + // 概要: + // Texture Property. + TexEnv = 4 + } + + [Serializable] + public struct PropItem + { + public string Name; + public ShaderPropertyType PropertyType; + public Vector4 DefaultValues; + } + + /// + /// Material 一つ分のプロパティを蓄えている + /// + /// * PreviewSceneManager で使う + /// * MaterialValueBindingMerger で使う + /// + /// + [Serializable] + public sealed class PreviewMaterialItem + { + public readonly Material Material; + + public PreviewMaterialItem(Material material) + { + Material = material; + + // uv default value + DefaultUVScaleOffset = material.GetVector(UV_PROPERTY); + } + + public Dictionary PropMap = new Dictionary(); + + public Vector4 DefaultUVScaleOffset = new Vector4(1, 1, 0, 0); + + public string[] PropNames + { + get; + set; + } + + public void RestoreInitialValues() + { + foreach (var prop in PropMap) + { + Material.SetColor(prop.Value.Name, prop.Value.DefaultValues); + } + } + + public static readonly string UV_PROPERTY = $"{MToon10Prop.BaseColorTexture.ToUnityShaderLabName()}_ST"; + public static readonly string COLOR_PROPERTY = MToon10Prop.BaseColorFactor.ToUnityShaderLabName(); + public static readonly string EMISSION_COLOR_PROPERTY = MToon10Prop.EmissiveFactor.ToUnityShaderLabName(); + public static readonly string RIM_COLOR_PROPERTY = MToon10Prop.ParametricRimColorFactor.ToUnityShaderLabName(); + public static readonly string OUTLINE_COLOR_PROPERTY = MToon10Prop.OutlineColorFactor.ToUnityShaderLabName(); + public static readonly string SHADE_COLOR_PROPERTY = MToon10Prop.ShadeColorFactor.ToUnityShaderLabName(); + public static readonly string MATCAP_COLOR_PROPERTY = MToon10Prop.MatcapColorFactor.ToUnityShaderLabName(); + + public static bool TryGetBindType(string property, out MaterialColorType type) + { + if (property == COLOR_PROPERTY) + { + type = MaterialColorType.color; + } + else if (property == EMISSION_COLOR_PROPERTY) + { + type = MaterialColorType.emissionColor; + } + else if (property == RIM_COLOR_PROPERTY) + { + type = MaterialColorType.rimColor; + } + else if (property == OUTLINE_COLOR_PROPERTY) + { + type = MaterialColorType.outlineColor; + } + else if (property == SHADE_COLOR_PROPERTY) + { + type = MaterialColorType.shadeColor; + } + else if (property == MATCAP_COLOR_PROPERTY) + { + type = MaterialColorType.matcapColor; + } + else + { + type = default; + return false; + } + + return true; + } + + /// + /// [Preview] 積算する前の初期値にクリアする + /// + public void Clear() + { + // clear Color + foreach (var _kv in PropMap) + { + Material.SetColor(_kv.Value.Name, _kv.Value.DefaultValues); + } + + // clear UV + Material.SetVector(UV_PROPERTY, DefaultUVScaleOffset); + } + + /// + /// [Preview] scaleOffset を weight で重みを付けて加える + /// + /// + /// + public void AddScaleOffset(Vector4 scaleOffset, float weight) + { + var value = Material.GetVector(UV_PROPERTY); + //Debug.LogFormat("{0} => {1}", valueName, x.TargetValue); + value += (scaleOffset - DefaultUVScaleOffset) * weight; + Material.SetColor(UV_PROPERTY, value); + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/PreviewMaterialItem.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/PreviewMaterialItem.cs.meta new file mode 100644 index 000000000..58b4efbde --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/PreviewMaterialItem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 713446847d9e57341828430ee0f79ad2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Expression/VRM10Expression.cs b/Assets/External/VRM10/Runtime/Components/Expression/VRM10Expression.cs new file mode 100644 index 000000000..b75473e24 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/VRM10Expression.cs @@ -0,0 +1,50 @@ +using UnityEngine; + +namespace UniVRM10 +{ + [CreateAssetMenu(menuName = "VRM10/Expression")] + public sealed class VRM10Expression : PrefabRelatedScriptableObject + { + /// + /// 対象メッシュの Expression を操作する + /// + [SerializeField] + public MorphTargetBinding[] MorphTargetBindings = new MorphTargetBinding[] { }; + + /// + /// 対象マテリアルの Color を操作する + /// + [SerializeField] + public MaterialColorBinding[] MaterialColorBindings = new MaterialColorBinding[] { }; + + /// + /// 対象マテリアルの UVScale+Offset を操作する + /// + [SerializeField] + public MaterialUVBinding[] MaterialUVBindings = new MaterialUVBinding[] { }; + + /// + /// UniVRM-0.45: trueの場合、この Expression は0と1の間の中間値を取らない。四捨五入する + /// + [SerializeField] + public bool IsBinary; + + /// + /// この Expression と Blink(Blink, BlinkLeft, BlinkRight) が同時に有効な場合、Blink の Weight を 0 にする + /// + [SerializeField] + public UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType OverrideBlink; + + /// + /// この Expression と LookAt(LookUp, LookDown, LookLeft, LookRight) が同時に有効な場合、LookAt の Weight を 0 にする + /// + [SerializeField] + public UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType OverrideLookAt; + + /// + /// この Expression と Mouth(Aa, Ih, Ou, Ee, Oh) が同時に有効な場合、Mouth の Weight を 0 にする + /// + [SerializeField] + public UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType OverrideMouth; + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Expression/VRM10Expression.cs.meta b/Assets/External/VRM10/Runtime/Components/Expression/VRM10Expression.cs.meta new file mode 100644 index 000000000..4c6762ab3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Expression/VRM10Expression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c8b2024ae0d0944eb878d90212bf21b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/FirstPerson.meta b/Assets/External/VRM10/Runtime/Components/FirstPerson.meta new file mode 100644 index 000000000..ce5e8bffe --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/FirstPerson.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a31f8c37cbcc4141b963817a2f02aed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/FirstPerson/RendererFirstPersonFlags.cs b/Assets/External/VRM10/Runtime/Components/FirstPerson/RendererFirstPersonFlags.cs new file mode 100644 index 000000000..c7c097d79 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/FirstPerson/RendererFirstPersonFlags.cs @@ -0,0 +1,54 @@ +using System; +using UnityEngine; + +namespace UniVRM10 +{ + [Serializable] + public struct RendererFirstPersonFlags + { + /// + /// RendererへのModelRootからの相対パス + /// + [SerializeField] + public String Renderer; + + [SerializeField] + public UniGLTF.Extensions.VRMC_vrm.FirstPersonType FirstPersonFlag; + + public static RendererFirstPersonFlags Create(Transform root, Renderer r, UniGLTF.Extensions.VRMC_vrm.FirstPersonType flag) + { + return new RendererFirstPersonFlags + { + Renderer = r.transform.RelativePathFrom(root), + FirstPersonFlag = flag, + }; + } + + public Renderer GetRenderer(Transform root) + { + var node = root.Find(Renderer); + return node?.GetComponent(); + } + + public Mesh GetSharedMesh(Transform root) + { + var renderer = GetRenderer(root); + switch (renderer) + { + case SkinnedMeshRenderer smr: + return smr.sharedMesh; + + case MeshRenderer meshRenderer: + var filter = renderer.GetComponent(); + if (filter != null) + { + return filter.sharedMesh; + } + return null; + + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/FirstPerson/RendererFirstPersonFlags.cs.meta b/Assets/External/VRM10/Runtime/Components/FirstPerson/RendererFirstPersonFlags.cs.meta new file mode 100644 index 000000000..2fe0976bf --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/FirstPerson/RendererFirstPersonFlags.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e57d4492156c0a14189a0aa26d3022fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/FirstPerson/Vrm10FirstPersonLayerSettings.cs b/Assets/External/VRM10/Runtime/Components/FirstPerson/Vrm10FirstPersonLayerSettings.cs new file mode 100644 index 000000000..93379de2f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/FirstPerson/Vrm10FirstPersonLayerSettings.cs @@ -0,0 +1,37 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public static class Vrm10FirstPersonLayerSettings + { + public const int DEFAULT_FIRSTPERSON_ONLY_LAYER = 9; + public const string FIRSTPERSON_ONLY_LAYER_NAME = "VRMFirstPersonOnly"; + + public const int DEFAULT_THIRDPERSON_ONLY_LAYER = 10; + public const string THIRDPERSON_ONLY_LAYER_NAME = "VRMThirdPersonOnly"; + + public static int GetLayer(int? arg, string name, int fallback) + { + if (arg.HasValue) + { + return arg.Value; + } + var layer = LayerMask.NameToLayer(name); + if (layer != -1) + { + return layer; + } + return fallback; + } + + public static int GetFirstPersonOnlyLayer(int? arg) + { + return GetLayer(arg, FIRSTPERSON_ONLY_LAYER_NAME, DEFAULT_FIRSTPERSON_ONLY_LAYER); + } + + public static int GetThirdPersonOnlyLayer(int? arg) + { + return GetLayer(arg, THIRDPERSON_ONLY_LAYER_NAME, DEFAULT_THIRDPERSON_ONLY_LAYER); + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/FirstPerson/Vrm10FirstPersonLayerSettings.cs.meta b/Assets/External/VRM10/Runtime/Components/FirstPerson/Vrm10FirstPersonLayerSettings.cs.meta new file mode 100644 index 000000000..ddc5a467a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/FirstPerson/Vrm10FirstPersonLayerSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ca895b6d3e950a47a3166f832146d8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/LookAt.meta b/Assets/External/VRM10/Runtime/Components/LookAt.meta new file mode 100644 index 000000000..92f89855a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fad5429c9ac21574db43656309c3b5e5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/CurveMapper.cs b/Assets/External/VRM10/Runtime/Components/LookAt/CurveMapper.cs new file mode 100644 index 000000000..55dcba9ff --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/CurveMapper.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + + +namespace UniVRM10 +{ + [Serializable] + public class CurveMapper + { + private AnimationCurve _curve = AnimationCurve.Linear(0, 0, 1.0f, 1.0f); + + [Range(20.0f, 90.0f)] + public float CurveXRangeDegree; + + [Range(0, 90.0f)] + public float CurveYRangeDegree; + + public CurveMapper(float xRange, float yRange) + { + CurveXRangeDegree = xRange; + CurveYRangeDegree = yRange; + } + + public void OnValidate() + { + if (CurveXRangeDegree == 0) + { + CurveXRangeDegree = 90.0f; + } + } + + public float Map(float src) + { + if (src < 0) + { + src = 0; + } + else if (src > CurveXRangeDegree) + { + src = CurveXRangeDegree; + } + return _curve.Evaluate(src / CurveXRangeDegree) * CurveYRangeDegree; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/CurveMapper.cs.meta b/Assets/External/VRM10/Runtime/Components/LookAt/CurveMapper.cs.meta new file mode 100644 index 000000000..6a8ef19bb --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/CurveMapper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 16e5128b491d62b4bbed7fed19658d22 +timeCreated: 1521805484 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/ILookAtEyeDirectionProvider.cs b/Assets/External/VRM10/Runtime/Components/LookAt/ILookAtEyeDirectionProvider.cs new file mode 100644 index 000000000..9bd701a85 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/ILookAtEyeDirectionProvider.cs @@ -0,0 +1,7 @@ +namespace UniVRM10 +{ + internal interface ILookAtEyeDirectionProvider + { + LookAtEyeDirection EyeDirection { get; } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/ILookAtEyeDirectionProvider.cs.meta b/Assets/External/VRM10/Runtime/Components/LookAt/ILookAtEyeDirectionProvider.cs.meta new file mode 100644 index 000000000..1a0210914 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/ILookAtEyeDirectionProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f4729047efb44254af696cb9eb01be01 +timeCreated: 1612173634 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs new file mode 100644 index 000000000..5aa6c250a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs @@ -0,0 +1,35 @@ +namespace UniVRM10 +{ + public readonly struct LookAtEyeDirection + { + /// + /// Positive is right. + /// Negative is left. + /// + /// + public float Yaw { get; } + + /// + /// Positive is upper. + /// Negative is lower. + /// + /// Usually in z-forward y-up left coordinates, positive is lower. + /// This is inverted because of following the vrm-1.0 specification. + /// + public float Pitch { get; } + + public LookAtEyeDirection(float yaw, float pitch) + { + Yaw = yaw; + Pitch = pitch; + } + + public static LookAtEyeDirection Multiply(LookAtEyeDirection a, float b) + { + return new LookAtEyeDirection( + a.Yaw * b, + a.Pitch * b + ); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs.meta b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs.meta new file mode 100644 index 000000000..ab1f28828 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirection.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a10e9a01fd446dc98513b556999ba67 +timeCreated: 1612163300 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs new file mode 100644 index 000000000..dee0ac4ea --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs @@ -0,0 +1,91 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Apply eye direction to bone transforms. + /// + internal sealed class LookAtEyeDirectionApplicableToBone : ILookAtEyeDirectionApplicable + { + private readonly Transform _leftEye; + private readonly Quaternion _leftEyePreMultiplyRotation; + private readonly Quaternion _leftEyePostMultiplyRotation; + + private readonly Transform _rightEye; + private readonly Quaternion _rightEyePreMultiplyRotation; + private readonly Quaternion _rightEyePostMultiplyRotation; + + private readonly CurveMapper _horizontalOuter; + private readonly CurveMapper _horizontalInner; + private readonly CurveMapper _verticalDown; + private readonly CurveMapper _verticalUp; + + public LookAtEyeDirectionApplicableToBone(Transform leftEye, Transform rightEye, + CurveMapper horizontalOuter, CurveMapper horizontalInner, CurveMapper verticalDown, CurveMapper verticalUp) + { + _leftEye = leftEye; + var leftEyeRotation = _leftEye.rotation; + _leftEyePreMultiplyRotation = _leftEye.localRotation * Quaternion.Inverse(leftEyeRotation); + _leftEyePostMultiplyRotation = leftEyeRotation; + + _rightEye = rightEye; + var rightEyeRotation = _rightEye.rotation; + _rightEyePreMultiplyRotation = _rightEye.localRotation * Quaternion.Inverse(rightEyeRotation); + _rightEyePostMultiplyRotation = rightEyeRotation; + + _horizontalOuter = horizontalOuter; + _horizontalInner = horizontalInner; + _verticalDown = verticalDown; + _verticalUp = verticalUp; + } + + public void Apply(LookAtEyeDirection eyeDirection, Dictionary actualWeights) + { + SetYawPitchToBones(eyeDirection); + } + + public void Restore() + { + SetYawPitchToBones(new LookAtEyeDirection(0, 0)); + } + + private void SetYawPitchToBones(LookAtEyeDirection eyeDirection) + { + float leftYaw, rightYaw; + if (eyeDirection.Yaw < 0) + { + leftYaw = -_horizontalOuter.Map(-eyeDirection.Yaw); + rightYaw = -_horizontalInner.Map(-eyeDirection.Yaw); + } + else + { + leftYaw = _horizontalInner.Map(eyeDirection.Yaw); + rightYaw = _horizontalOuter.Map(eyeDirection.Yaw); + } + + float pitch; + if (eyeDirection.Pitch < 0) + { + pitch = _verticalDown.Map(-eyeDirection.Pitch); + } + else + { + pitch = -_verticalUp.Map(eyeDirection.Pitch); + } + + if (_leftEye != null) + { + _leftEye.localRotation = _leftEyePreMultiplyRotation * + Quaternion.Euler(pitch, leftYaw, 0) * + _leftEyePostMultiplyRotation; + } + if (_rightEye != null) + { + _rightEye.localRotation = _rightEyePreMultiplyRotation * + Quaternion.Euler(pitch, rightYaw, 0) * + _rightEyePostMultiplyRotation; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs.meta b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs.meta new file mode 100644 index 000000000..6c1e04332 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToBone.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c973408bdfe4936ac9847d0a55855a2 +timeCreated: 1612167497 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs new file mode 100644 index 000000000..60f859b32 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using UniGLTF.Extensions.VRMC_vrm; +using UnityEngine; + +namespace UniVRM10 +{ + internal sealed class LookAtEyeDirectionApplicableToExpression : ILookAtEyeDirectionApplicable + { + private readonly CurveMapper _horizontalOuter; + private readonly CurveMapper _horizontalInner; + private readonly CurveMapper _verticalDown; + private readonly CurveMapper _verticalUp; + + private readonly ExpressionKey _lookRightKey = ExpressionKey.CreateFromPreset(ExpressionPreset.lookRight); + private readonly ExpressionKey _lookLeftKey = ExpressionKey.CreateFromPreset(ExpressionPreset.lookLeft); + private readonly ExpressionKey _lookUpKey = ExpressionKey.CreateFromPreset(ExpressionPreset.lookUp); + private readonly ExpressionKey _lookDownKey = ExpressionKey.CreateFromPreset(ExpressionPreset.lookDown); + + public LookAtEyeDirectionApplicableToExpression( + CurveMapper horizontalOuter, CurveMapper horizontalInner, CurveMapper verticalDown, CurveMapper verticalUp) + { + _horizontalOuter = horizontalOuter; + _horizontalInner = horizontalInner; + _verticalDown = verticalDown; + _verticalUp = verticalUp; + } + + public void Apply(LookAtEyeDirection eyeDirection, Dictionary actualWeights) + { + var yaw = eyeDirection.Yaw; + var pitch = eyeDirection.Pitch; + + if (yaw < 0) + { + // Left + actualWeights[_lookRightKey] = 0; + actualWeights[_lookLeftKey] = Mathf.Clamp(_horizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f); + } + else + { + // Right + actualWeights[_lookRightKey] = Mathf.Clamp(_horizontalOuter.Map(Mathf.Abs(yaw)), 0, 1.0f); + actualWeights[_lookLeftKey] = 0; + } + + if (pitch < 0) + { + // Down + actualWeights[_lookUpKey] = 0; + actualWeights[_lookDownKey] = Mathf.Clamp(_verticalDown.Map(Mathf.Abs(pitch)), 0, 1.0f); + } + else + { + // Up + actualWeights[_lookUpKey] = Mathf.Clamp(_verticalUp.Map(Mathf.Abs(pitch)), 0, 1.0f); + actualWeights[_lookDownKey] = 0; + } + } + + public void Restore() + { + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs.meta b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs.meta new file mode 100644 index 000000000..bf1af3ff9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtEyeDirectionApplicableToExpression.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1d8a407ebe89449e9b03e1ed8a759f60 +timeCreated: 1612171380 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/LookAtInput.cs b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtInput.cs new file mode 100644 index 000000000..10a26e95b --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtInput.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// LookAt を具体的な値に解決する前の入力値 + /// この値を元に LookAtEyeDirection を生成し、 + /// LookAtEyeDirection を Bone もしくは MorphTarget に対して適用する。 + /// + public struct LookAtInput + { + public LookAtEyeDirection? YawPitch; + public Vector3? WorldPosition; + } +} diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/LookAtInput.cs.meta b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtInput.cs.meta new file mode 100644 index 000000000..71262e061 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/LookAtInput.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f7a52869fd45b2439bce28499c3f8dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs b/Assets/External/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs new file mode 100644 index 000000000..f88b4905c --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs @@ -0,0 +1,102 @@ +using System; +using UnityEngine; + + +namespace UniVRM10 +{ + public static class Matrix4x4Extensions + { + /// + /// from AimConstraint + /// + /// + /// + /// + /// + public static (float Yaw, float Pitch) CalcYawPitch(this Matrix4x4 m, Vector3 target) + { + var localPosition = m.inverse.MultiplyPoint(target); + + var zaxis = Vector3.Project(localPosition, Vector3.forward); + var yaxis = Vector3.Project(localPosition, Vector3.up); + var xaxis = Vector3.Project(localPosition, Vector3.right); + + var xDot = Vector3.Dot(xaxis, Vector3.right) > 0; + var yDot = Vector3.Dot(yaxis, Vector3.up) > 0; + var zDot = Vector3.Dot(zaxis, Vector3.forward) > 0; + + // x z plane + var yaw = (float)Math.Atan2(xaxis.magnitude, zaxis.magnitude) * Mathf.Rad2Deg; + if (xDot && zDot) + { + // 1st(0-90) + + } + else if (xDot && !zDot) + { + // 2nd(90-180) + yaw = 180 - yaw; + } + else if (!xDot && !zDot) + { + // 3rd + yaw = -180 + yaw; + } + else if (!xDot && zDot) + { + // 4th + yaw = -yaw; + } + else + { + throw new NotImplementedException(); + } + + // x+y z plane + var pitch = (float)Math.Atan2(yaxis.magnitude, (xaxis + zaxis).magnitude) * Mathf.Rad2Deg; + if (yDot) + { + pitch = -pitch; + } + + return (yaw, pitch); + } + + /// + /// yaw: 右が+ + /// pitch: 上が+ + /// という仕様。vrm-0.x から据え置き + /// + public static void CalcYawPitch(this Matrix4x4 m, Vector3 target, out float yaw, out float pitch) + { + var z = Vector3.Dot(target, m.GetColumn(2)); + var x = Vector3.Dot(target, m.GetColumn(0)); + yaw = Mathf.Atan2(x, z) * Mathf.Rad2Deg; + + // x+y z plane + var xz = Mathf.Sqrt(x * x + z * z); + var y = Vector3.Dot(target, m.GetColumn(1)); + pitch = Mathf.Atan2(y, xz) * Mathf.Rad2Deg; + } + + /// + /// yaw: 右が+ + /// pitch: 上が+ + /// という仕様。vrm-0.x から据え置き + /// + public static Quaternion YawPitchRotation(this Matrix4x4 m, float yaw, float pitch) + { + return Quaternion.AngleAxis(yaw, m.GetColumn(1)) * Quaternion.AngleAxis(-pitch, m.GetColumn(0)); + } + + public static Matrix4x4 RotationToWorldAxis(this Matrix4x4 m) + { + return UnityExtensions.Matrix4x4FromColumns( + m.MultiplyVector(Vector3.right), + m.MultiplyVector(Vector3.up), + m.MultiplyVector(Vector3.forward), + new Vector4(0, 0, 0, 1) + ); + } + } +} diff --git a/Assets/External/VRM/Runtime/Format/VRMVersion.cs.meta b/Assets/External/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs.meta similarity index 77% rename from Assets/External/VRM/Runtime/Format/VRMVersion.cs.meta rename to Assets/External/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs.meta index b953c85a9..4c1ec1686 100644 --- a/Assets/External/VRM/Runtime/Format/VRMVersion.cs.meta +++ b/Assets/External/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 93c46c8b64555f14bada9f5bb0b7761a -timeCreated: 1522130257 +guid: 467dbe8b852af2a479d542138339d1b0 +timeCreated: 1518347175 licenseType: Free MonoImporter: externalObjects: {} diff --git a/Assets/External/VRM10/Runtime/Components/PrefabRelatedScriptableObject.cs b/Assets/External/VRM10/Runtime/Components/PrefabRelatedScriptableObject.cs new file mode 100644 index 000000000..bc24cf26b --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/PrefabRelatedScriptableObject.cs @@ -0,0 +1,52 @@ +using UniGLTF; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// ScriptableObject なのだけど Editor では、ヒエラルキーを参照したい。 + /// 参照して、ヒエラルキー内の Renderer を選択したりしたい。 + /// + /// そういうオブジェクト。 + /// + public class PrefabRelatedScriptableObject : ScriptableObject + { +#if UNITY_EDITOR + /// + /// Preview 用のObject参照 + /// + [SerializeField] + GameObject m_prefab; + public GameObject Prefab + { + set { m_prefab = value; } + get + { + if (m_prefab == null) + { + var assetPath = UnityEditor.AssetDatabase.GetAssetPath(this); + if (!string.IsNullOrEmpty(assetPath)) + { + // if asset is subasset of prefab + m_prefab = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath); + if (m_prefab != null) return m_prefab; + + // 同じフォルダに prefab が居る + var parent = UnityPath.FromUnityPath(assetPath).Parent; + var prefabPath = parent.Parent.Child(parent.FileNameWithoutExtension + ".prefab"); + m_prefab = UnityEditor.AssetDatabase.LoadAssetAtPath(prefabPath.Value); + if (m_prefab != null) return m_prefab; + + // 同じフォルダに vrm(ScriptedImporter) が居る + var parentParent = UnityPath.FromUnityPath(assetPath).Parent.Parent; + var vrmPath = parent.Parent.Child(parent.FileNameWithoutExtension + ".vrm"); + m_prefab = UnityEditor.AssetDatabase.LoadAssetAtPath(vrmPath.Value); + if (m_prefab != null) return m_prefab; + } + } + return m_prefab; + } + } +#endif + } +} diff --git a/Assets/External/VRM10/Runtime/Components/PrefabRelatedScriptableObject.cs.meta b/Assets/External/VRM10/Runtime/Components/PrefabRelatedScriptableObject.cs.meta new file mode 100644 index 000000000..1f7427741 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/PrefabRelatedScriptableObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa46394d71fe3814ca9b60f0b3409c6d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone.meta b/Assets/External/VRM10/Runtime/Components/SpringBone.meta new file mode 100644 index 000000000..30530a6d9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 14e1fad136e82e64c8ac16f4c4502b72 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs new file mode 100644 index 000000000..e0d257405 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs @@ -0,0 +1,49 @@ +using System; +using UnityEngine; + +namespace UniVRM10 +{ + public enum VRM10SpringBoneColliderTypes + { + Sphere, + Capsule, + } + + [Serializable] + public class VRM10SpringBoneCollider : MonoBehaviour + { + public VRM10SpringBoneColliderTypes ColliderType; + + /// bone local position + public Vector3 Offset; + + [Range(0, 1.0f)] + public float Radius; + + /// bone local position + public Vector3 Tail; + + public static int SelectedGuid; + + public bool IsSelected => GetInstanceID() == SelectedGuid; + + public void OnDrawGizmosSelected() + { + Gizmos.matrix = transform.localToWorldMatrix; + switch (ColliderType) + { + case VRM10SpringBoneColliderTypes.Sphere: + Gizmos.color = Color.magenta; + Gizmos.DrawWireSphere(Offset, Radius); + break; + + case VRM10SpringBoneColliderTypes.Capsule: + Gizmos.color = new Color(1.0f, 0.1f, 0.1f); + Gizmos.DrawWireSphere(Offset, Radius); + Gizmos.DrawWireSphere(Tail, Radius); + Gizmos.DrawLine(Offset, Tail); + break; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs.meta b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs.meta new file mode 100644 index 000000000..5d1c1d17d --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35bfb658269b2af478e501de243deda6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneColliderGroup.cs b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneColliderGroup.cs new file mode 100644 index 000000000..e1c782085 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneColliderGroup.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + [Serializable] + public class VRM10SpringBoneColliderGroup : MonoBehaviour + { + [SerializeField] + public string Name; + + public string GUIName(int i) => $"{i:00}:{Name}"; + + [SerializeField] + public List Colliders = new List(); + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneColliderGroup.cs.meta b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneColliderGroup.cs.meta new file mode 100644 index 000000000..dd1463115 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneColliderGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 177ea458e237fee41b0902e3006c744b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs new file mode 100644 index 000000000..867d3fcbd --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UniVRM10 +{ + [Serializable] + [DisallowMultipleComponent] + public class VRM10SpringBoneJoint : MonoBehaviour + { + [SerializeField] + public float m_stiffnessForce = 1.0f; + + [SerializeField] + public float m_gravityPower = 0; + + [SerializeField] + public Vector3 m_gravityDir = new Vector3(0, -1.0f, 0); + + [SerializeField, Range(0, 1)] + public float m_dragForce = 0.4f; + + [SerializeField] + public float m_jointRadius = 0.02f; + + void AddJointRecursive(Transform t, VRM10SpringBoneJoint src) + { + var joint = t.gameObject.GetComponent(); + if (joint == null) + { + joint = t.gameObject.AddComponent(); + Debug.Log($"{joint} added"); + } + + // copy settings + joint.m_stiffnessForce = src.m_stiffnessForce; + joint.m_gravityPower = src.m_gravityPower; + joint.m_gravityDir = src.m_gravityDir; + joint.m_dragForce = src.m_dragForce; + joint.m_jointRadius = src.m_jointRadius; + + if (t.childCount > 0) + { + // only first child + AddJointRecursive(t.GetChild(0), src); + } + } + + void GetJoints(Transform t, List joints) + { + var joint = t.GetComponent(); + if (joint != null) + { + joints.Add(joint); + } + + if (t.childCount > 0) + { + GetJoints(t.GetChild(0), joints); + } + } + + [ContextMenu("Add joints")] + private void AddJointsToChild0() + { + var root = GetComponentInParent(); + if (root == null) + { + Debug.LogWarning("not Vrm10Instance"); + return; + } + + if (transform.childCount == 0) + { + Debug.LogWarning("no children"); + return; + } + + AddJointRecursive(transform.GetChild(0), this); + + // updater root + foreach (var spring in root.SpringBone.Springs) + { + for (int i = 0; i < spring.Joints.Count; ++i) + { + if (spring.Joints[i] == this) + { + // found + while (spring.Joints.Count - 1 > i) + { + // remove after this joint + spring.Joints.RemoveAt(spring.Joints.Count - 1); + } + // get descendants joints + var joints = new List(); + GetJoints(transform.GetChild(0), joints); + // add jonits to after this + spring.Joints.AddRange(joints); + return; + } + } + } + + Debug.LogWarning($"{this} is found in {root}"); + } + + + (Vrm10InstanceSpringBone.Spring, int) FindTail(Vrm10Instance vrm, VRM10SpringBoneJoint head) + { + foreach (var spring in vrm.SpringBone.Springs) + { + var index = spring.Joints.IndexOf(head); + if (index != -1) + { + if (index + 1 < spring.Joints.Count) + { + return (spring, index); + } + else + { + break; + } + } + } + return default; + } + + private void OnDrawGizmosSelected() + { + var vrm = GetComponentInParent(); + if (vrm == null) + { + return; + } + + var (spring, joint_index) = FindTail(vrm, this); + if (spring == null) + { + return; + } + + if (spring.Joints != null && joint_index + 1 < spring.Joints.Count) + { + var tail = spring.Joints[joint_index + 1]; + if (tail != null) + { + // draw tail + Gizmos.color = Color.yellow; + // tail の radius は head の m_jointRadius で決まる + Gizmos.DrawWireSphere(tail.transform.position, m_jointRadius); + Gizmos.DrawLine(transform.position, tail.transform.position); + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs.meta b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs.meta new file mode 100644 index 000000000..1f0db6050 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a942e03b39600e41a1b161e958048f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringUtility.cs b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringUtility.cs new file mode 100644 index 000000000..920e02d55 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringUtility.cs @@ -0,0 +1,221 @@ +namespace UniVRM10 +{ + + public static class VRM10SpringUtility + { +#if false + +#if UNITY_EDITOR +#region save + [MenuItem(VRMVersion.MENU + "/SaveSpringBoneToJSON", validate = true)] + static bool SaveSpringBoneToJSONIsEnable() + { + var root = Selection.activeObject as GameObject; + if (root == null) + { + return false; + } + + var animator = root.GetComponent(); + if (animator == null) + { + return false; + } + + return true; + } + + [MenuItem(VRMVersion.MENU + "/SaveSpringBoneToJSON")] + static void SaveSpringBoneToJSON() + { + var path = EditorUtility.SaveFilePanel( + "Save spring to json", + null, + "VRMSpring.json", + "json"); + if (string.IsNullOrEmpty(path)) + { + return; + } + + var go = Selection.activeObject as GameObject; + var root = go.transform; + var nodes = root.Traverse().Skip(1).ToList(); + var spring = new glTF_VRM_SecondaryAnimation(); + ExportSecondary(root, nodes, + spring.colliderGroups.Add, + spring.boneGroups.Add + ); + + File.WriteAllText(path, spring.ToJson()); + } + +#endregion + +#region load + [MenuItem(VRMVersion.MENU + "/LoadSpringBoneFromJSON", true)] + static bool LoadSpringBoneFromJSONIsEnable() + { + var root = Selection.activeObject as GameObject; + if (root == null) + { + return false; + } + + var animator = root.GetComponent(); + if (animator == null) + { + return false; + } + + return true; + } + + [MenuItem(VRMVersion.MENU + "/LoadSpringBoneFromJSON")] + static void LoadSpringBoneFromJSON() + { + var path = EditorUtility.OpenFilePanel( + "Load spring from json", + null, + "json"); + if (string.IsNullOrEmpty(path)) + { + return; + } + + var json = File.ReadAllText(path, Encoding.UTF8); + var spring = JsonUtility.FromJson(json); + + var go = Selection.activeObject as GameObject; + var root = go.transform; + var nodes = root.Traverse().Skip(1).ToList(); + + LoadSecondary(root, nodes, spring); + } +#endregion +#endif + + public static void ExportSecondary(Transform root, List nodes, + Action addSecondaryColliderGroup, + Action addSecondaryGroup) + { + var colliders = new List(); + foreach (var vrmColliderGroup in root.Traverse() + .Select(x => x.GetComponent()) + .Where(x => x != null)) + { + colliders.Add(vrmColliderGroup); + + var colliderGroup = new glTF_VRM_SecondaryAnimationColliderGroup + { + node = nodes.IndexOf(vrmColliderGroup.transform) + }; + + colliderGroup.colliders = vrmColliderGroup.Colliders.Select(x => + { + return new glTF_VRM_SecondaryAnimationCollider + { + offset = x.Offset, + radius = x.Radius, + }; + + }).ToList(); + + addSecondaryColliderGroup(colliderGroup); + } + + foreach (var spring in root.Traverse() + .SelectMany(x => x.GetComponents()) + .Where(x => x != null)) + { + addSecondaryGroup(new glTF_VRM_SecondaryAnimationGroup + { + comment = spring.m_comment, + center = nodes.IndexOf(spring.m_center), + dragForce = spring.m_dragForce, + gravityDir = spring.m_gravityDir, + gravityPower = spring.m_gravityPower, + stiffiness = spring.m_stiffnessForce, + hitRadius = spring.m_hitRadius, + colliderGroups = spring.ColliderGroups + .Select(x => colliders.IndexOf(x)) + .Where(x => x != -1) + .ToArray(), + bones = spring.RootBones.Select(x => nodes.IndexOf(x)).ToArray(), + }); + } + } + + public static void LoadSecondary(Transform root, List nodes, + glTF_VRM_SecondaryAnimation secondaryAnimation) + { + var secondary = root.Find("secondary"); + if (secondary == null) + { + secondary = new GameObject("secondary").transform; + secondary.SetParent(root, false); + } + + // clear components + var remove = root.Traverse() + .SelectMany(x => x.GetComponents()) + .Where(x => x is VRMSpringBone || x is VRMSpringBoneColliderGroup) + .ToArray(); + foreach (var x in remove) + { + if (Application.isPlaying) + { + GameObject.Destroy(x); + } + else + { + GameObject.DestroyImmediate(x); + } + } + + //var secondaryAnimation = context.VRM.extensions.VRM.secondaryAnimation; + var colliders = new List(); + foreach (var colliderGroup in secondaryAnimation.colliderGroups) + { + var vrmGroup = nodes[colliderGroup.node].gameObject.AddComponent(); + vrmGroup.Colliders = colliderGroup.colliders.Select(x => + { + return new VRMSpringBoneColliderGroup.SphereCollider + { + Offset = x.offset, + Radius = x.radius + }; + }).ToArray(); + colliders.Add(vrmGroup); + } + + if (secondaryAnimation.boneGroups.Count > 0) + { + foreach (var boneGroup in secondaryAnimation.boneGroups) + { + var vrmBoneGroup = secondary.gameObject.AddComponent(); + if (boneGroup.center != -1) + { + vrmBoneGroup.m_center = nodes[boneGroup.center]; + } + vrmBoneGroup.m_comment = boneGroup.comment; + vrmBoneGroup.m_dragForce = boneGroup.dragForce; + vrmBoneGroup.m_gravityDir = boneGroup.gravityDir; + vrmBoneGroup.m_gravityPower = boneGroup.gravityPower; + vrmBoneGroup.m_hitRadius = boneGroup.hitRadius; + vrmBoneGroup.m_stiffnessForce = boneGroup.stiffiness; + if (boneGroup.colliderGroups != null && boneGroup.colliderGroups.Any()) + { + vrmBoneGroup.ColliderGroups = boneGroup.colliderGroups.Select(x => colliders[x]).ToArray(); + } + vrmBoneGroup.RootBones = boneGroup.bones.Select(x => nodes[x]).ToList(); + } + } + else + { + secondary.gameObject.AddComponent(); + } + } +#endif + } +} diff --git a/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringUtility.cs.meta b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringUtility.cs.meta new file mode 100644 index 000000000..844f7c71f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/SpringBone/VRM10SpringUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61a4226bc18ddab4daf79fc681690fab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object.meta b/Assets/External/VRM10/Runtime/Components/VRM10Object.meta new file mode 100644 index 000000000..625e01bd9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8c3df50f202d51e43a56b80a698a3870 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10Object.cs b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10Object.cs new file mode 100644 index 000000000..ec25ff42c --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10Object.cs @@ -0,0 +1,47 @@ +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + /// + /// VRM関連の情報を保持するオブジェクト + /// ScriptedImporter から Extract して + /// Editor経由で Edit可能にするのが目的。 + /// ヒエラルキーに対する参照を保持できないので Humanoid, Spring, Constraint は含まず + /// 下記の項目を保持することとした。 + /// シーンに出さずにアセットとして編集できる。 + /// + /// * Meta + /// * Expressions(enum + custom list) + /// * LookAt + /// * FirstPerson + /// + /// + public class VRM10Object : PrefabRelatedScriptableObject + { + public static SubAssetKey SubAssetKey => new SubAssetKey(typeof(VRM10Object), "_vrm1_"); + + [SerializeField] + public VRM10ObjectMeta Meta = new VRM10ObjectMeta(); + + [SerializeField] + public VRM10ObjectExpression Expression = new VRM10ObjectExpression(); + + [SerializeField] + public VRM10ObjectLookAt LookAt = new VRM10ObjectLookAt(); + + [SerializeField] + public VRM10ObjectFirstPerson FirstPerson = new VRM10ObjectFirstPerson(); + + void OnValidate() + { + if (LookAt != null) + { + LookAt.HorizontalInner.OnValidate(); + LookAt.HorizontalOuter.OnValidate(); + LookAt.VerticalUp.OnValidate(); + LookAt.VerticalDown.OnValidate(); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10Object.cs.meta b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10Object.cs.meta new file mode 100644 index 000000000..135924fd1 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10Object.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88684271e27adb843b6570957c9e7637 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs new file mode 100644 index 000000000..1ce7e24dc --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using VrmLib; + +namespace UniVRM10 +{ + [Serializable] + public sealed class VRM10ObjectExpression + { + #region Preset + [SerializeField, Header("Emotion")] + public VRM10Expression Happy; + + [SerializeField] + public VRM10Expression Angry; + + [SerializeField] + public VRM10Expression Sad; + + [SerializeField] + public VRM10Expression Relaxed; + + [SerializeField] + public VRM10Expression Surprised; + + [SerializeField, Header("LipSync")] + public VRM10Expression Aa; + + [SerializeField] + public VRM10Expression Ih; + + [SerializeField] + public VRM10Expression Ou; + + [SerializeField] + public VRM10Expression Ee; + + [SerializeField] + public VRM10Expression Oh; + + [SerializeField, Header("Blink")] + public VRM10Expression Blink; + + [SerializeField] + public VRM10Expression BlinkLeft; + + [SerializeField] + public VRM10Expression BlinkRight; + + [SerializeField, Header("LookAt")] + public VRM10Expression LookUp; + + [SerializeField] + public VRM10Expression LookDown; + + [SerializeField] + public VRM10Expression LookLeft; + + [SerializeField] + public VRM10Expression LookRight; + + [SerializeField, Header("Other")] + public VRM10Expression Neutral; + #endregion + + [SerializeField] + public List CustomClips = new List(); + + public IEnumerable<(ExpressionPreset Preset, VRM10Expression Clip)> Clips + { + get + { + if (Happy != null) yield return (ExpressionPreset.happy, Happy); + if (Angry != null) yield return (ExpressionPreset.angry, Angry); + if (Sad != null) yield return (ExpressionPreset.sad, Sad); + if (Relaxed != null) yield return (ExpressionPreset.relaxed, Relaxed); + if (Surprised != null) yield return (ExpressionPreset.surprised, Surprised); + if (Aa != null) yield return (ExpressionPreset.aa, Aa); + if (Ih != null) yield return (ExpressionPreset.ih, Ih); + if (Ou != null) yield return (ExpressionPreset.ou, Ou); + if (Ee != null) yield return (ExpressionPreset.ee, Ee); + if (Oh != null) yield return (ExpressionPreset.oh, Oh); + if (Blink != null) yield return (ExpressionPreset.blink, Blink); + if (BlinkLeft != null) yield return (ExpressionPreset.blinkLeft, BlinkLeft); + if (BlinkRight != null) yield return (ExpressionPreset.blinkRight, BlinkRight); + if (LookUp != null) yield return (ExpressionPreset.lookUp, LookUp); + if (LookDown != null) yield return (ExpressionPreset.lookDown, LookDown); + if (LookLeft != null) yield return (ExpressionPreset.lookLeft, LookLeft); + if (LookRight != null) yield return (ExpressionPreset.lookRight, LookRight); + if (Neutral != null) yield return (ExpressionPreset.neutral, Neutral); + foreach (var clip in CustomClips) + { + if (clip != null) + { + yield return (ExpressionPreset.custom, clip); + } + } + } + } + + public ExpressionKey CreateKey(VRM10Expression clip) + { + foreach (var (preset, c) in Clips) + { + if (c == clip) + { + return new ExpressionKey(preset, clip.name); + } + } + + // not found + // return default(ExpressionKey); + throw new KeyNotFoundException(); + } + + public void AddClip(ExpressionPreset preset, VRM10Expression clip) + { + switch (preset) + { + case ExpressionPreset.happy: Happy = clip; break; + case ExpressionPreset.angry: Angry = clip; break; + case ExpressionPreset.sad: Sad = clip; break; + case ExpressionPreset.relaxed: Relaxed = clip; break; + case ExpressionPreset.surprised: Surprised = clip; break; + case ExpressionPreset.aa: Aa = clip; break; + case ExpressionPreset.ih: Ih = clip; break; + case ExpressionPreset.ou: Ou = clip; break; + case ExpressionPreset.ee: Ee = clip; break; + case ExpressionPreset.oh: Oh = clip; break; + case ExpressionPreset.blink: Blink = clip; break; + case ExpressionPreset.blinkLeft: BlinkLeft = clip; break; + case ExpressionPreset.blinkRight: BlinkRight = clip; break; + case ExpressionPreset.lookUp: LookUp = clip; break; + case ExpressionPreset.lookDown: LookDown = clip; break; + case ExpressionPreset.lookLeft: LookLeft = clip; break; + case ExpressionPreset.lookRight: LookRight = clip; break; + case ExpressionPreset.neutral: Neutral = clip; break; + default: CustomClips.Add(clip); break; + } + } + + public void Replace(IDictionary map) + { + foreach (var (k, v) in map) + { + Replace(k, v); + } + } + + void Replace(VRM10Expression src, VRM10Expression dst) + { + if (Happy == src) + { + Happy = dst; return; + } + if (Angry == src) + { + Angry = dst; return; + } + if (Sad == src) + { + Sad = dst; return; + } + if (Relaxed == src) + { + Relaxed = dst; return; + } + if (Surprised == src) + { + Surprised = dst; return; + } + if (Aa == src) + { + Aa = dst; return; + } + if (Ih == src) + { + Ih = dst; return; + } + if (Ou == src) + { + Ou = dst; return; + } + if (Ee == src) + { + Ee = dst; return; + } + if (Oh == src) + { + Oh = dst; return; + } + if (Blink == src) + { + Blink = dst; return; + } + if (BlinkLeft == src) + { + BlinkLeft = dst; return; + } + if (BlinkRight == src) + { + BlinkRight = dst; return; + } + if (LookUp == src) + { + LookUp = dst; return; + } + if (LookDown == src) + { + LookDown = dst; return; + } + if (LookLeft == src) + { + LookLeft = dst; return; + } + if (LookRight == src) + { + LookRight = dst; return; + } + if (Neutral == src) + { + Neutral = dst; return; + } + + for (int i = 0; i < CustomClips.Count; ++i) + { + if (CustomClips[i] == src) + { + CustomClips[i] = dst; + return; + } + } + } + + /// + /// NullのClipを削除して詰める + /// + public void RemoveNullClip() + { + if (CustomClips == null) + { + return; + } + for (int i = CustomClips.Count - 1; i >= 0; --i) + { + if (CustomClips[i] == null) + { + CustomClips.RemoveAt(i); + } + } + } + + // /// + // /// Unknown以外で存在しないものを全て作る + // /// + // public void CreateDefaultPreset() + // { + // foreach (var preset in ((ExpressionPreset[])Enum.GetValues(typeof(ExpressionPreset))) + // .Where(x => x != ExpressionPreset.custom) + // ) + // { + // CreateDefaultPreset(preset); + // } + // } + + + + } +} diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs.meta b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs.meta new file mode 100644 index 000000000..2b7fe5401 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectExpression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcf99f5cc866e6b42b05c6f6a7ea630c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs new file mode 100644 index 000000000..812264422 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs @@ -0,0 +1,222 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using UniGLTF.MeshUtility; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + [Serializable] + public class VRM10ObjectFirstPerson + { + [SerializeField] + public List Renderers = new List(); + public void SetDefault(Transform root) + { + Renderers.Clear(); + + var renderers = root.GetComponentsInChildren(); + var paths = renderers.Select(x => x.transform.RelativePathFrom(root)).ToArray(); + foreach (var path in paths) + { + Renderers.Add(new RendererFirstPersonFlags + { + FirstPersonFlag = UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto, + Renderer = path, + }); + } + } + + static int[] GetBonesThatHasAncestor(SkinnedMeshRenderer smr, Transform ancestor) + { + var eraseBones = smr.bones + .Where(x => x.Ancestor().Any(y => y == ancestor)) + .Select(x => Array.IndexOf(smr.bones, x)) + .Distinct() + .ToArray(); + return eraseBones; + } + + public static async Task CreateErasedMeshAsync(SkinnedMeshRenderer smr, + Transform firstPersonBone, + IAwaitCaller awaitCaller) + { + var eraseBones = GetBonesThatHasAncestor(smr, firstPersonBone); + if (eraseBones.Any()) + { + return await BoneMeshEraser.CreateErasedMeshAsync(smr.sharedMesh, eraseBones, awaitCaller); + } + else + { + return null; + } + } + + // + // 頭部を取り除いたモデルを複製する + // + // renderer: 元になるSkinnedMeshRenderer + // eraseBones: 削除対象になるボーンのindex + public async static Task CreateHeadlessMeshAsync(SkinnedMeshRenderer renderer, + Transform firstPersonBone, IAwaitCaller awaitCaller) + { + var mesh = await CreateErasedMeshAsync(renderer, firstPersonBone, awaitCaller); + if (mesh != null) + { + var go = new GameObject("_headless_" + renderer.name); + var erased = go.AddComponent(); + erased.enabled = false; // hide + erased.sharedMesh = mesh; + erased.sharedMaterials = renderer.sharedMaterials; + erased.bones = renderer.bones; + erased.rootBone = renderer.rootBone; + return erased; + } + else + { + // 削除対象が含まれないので何もしない + return null; + } + } + + bool m_done; + + async Task SetupSelfRendererAsync(GameObject go, UniGLTF.RuntimeGltfInstance runtime, + Transform firstPersonBone, RendererFirstPersonFlags x, + (int FirstPersonOnly, int ThirdPersonOnly) layer, IAwaitCaller awaitCaller = null) + { + switch (x.FirstPersonFlag) + { + case UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto: + { + if (x.GetRenderer(go.transform) is SkinnedMeshRenderer smr) + { + // 頭を取り除いた複製モデルを作成し、1人称用にする + var headless = await CreateHeadlessMeshAsync(smr, firstPersonBone, awaitCaller); + if (headless != null) + { + // オリジナルのモデルを3人称用にする + smr.gameObject.layer = layer.ThirdPersonOnly; + + headless.gameObject.layer = layer.FirstPersonOnly; + headless.transform.SetParent(smr.transform, false); + if (runtime != null) + { + runtime.AddResource(headless.sharedMesh); + runtime.AddRenderer(headless); + } + } + else + { + // ヘッドレスを作成しなかった場合は何もしない => both と同じ + } + } + else if (x.GetRenderer(go.transform) is MeshRenderer mr) + { + if (mr.transform.Ancestors().Any(y => y == firstPersonBone)) + { + // 頭の子孫なので1人称では非表示に + mr.gameObject.layer = layer.ThirdPersonOnly; + } + else + { + // 特に変更しない => 両方表示 + } + } + else + { + throw new NotImplementedException(); + } + } + break; + + case UniGLTF.Extensions.VRMC_vrm.FirstPersonType.firstPersonOnly: + // 1人称のカメラでだけ描画されるようにする + x.GetRenderer(go.transform).gameObject.layer = layer.FirstPersonOnly; + break; + + case UniGLTF.Extensions.VRMC_vrm.FirstPersonType.thirdPersonOnly: + // 3人称のカメラでだけ描画されるようにする + x.GetRenderer(go.transform).gameObject.layer = layer.ThirdPersonOnly; + break; + + case UniGLTF.Extensions.VRMC_vrm.FirstPersonType.both: + // 特に何もしない。すべてのカメラで描画される + break; + } + } + + /// + /// Each renderer is set according to the first person flag. + /// If the flag is `auto`, headless mesh creation will be performed. + /// Creating a headless mesh(Renderer) is a heavy process and can be done in threads. + /// + /// The target model root + /// The target model is the VR user himself + /// layer VRMFirstPersonOnly or 9 + /// layer VRMThirdPersonOnly ir 10 + /// Headless mesh creation task scheduler. By default, creation is immediate + /// + public async Task SetupAsync(GameObject go, IAwaitCaller awaitCaller, bool isSelf = true, int? firstPersonOnlyLayer = default, int? thirdPersonOnlyLayer = default) + { + if (awaitCaller == null) + { + throw new ArgumentNullException(); + } + + var layer = ( + Vrm10FirstPersonLayerSettings.GetFirstPersonOnlyLayer(firstPersonOnlyLayer), + Vrm10FirstPersonLayerSettings.GetThirdPersonOnlyLayer(thirdPersonOnlyLayer)); + + if (m_done) + { + return; + } + m_done = true; + + var runtime = go.GetComponent(); + var vrmInstance = go.GetComponent(); + // NOTE: This bone must be referenced by renderers instead of the control rig bone. + var firstPersonBone = vrmInstance.Humanoid.Head; + + var used = new HashSet(); + foreach (var x in Renderers) + { + if (!used.Add(x.Renderer)) + { + // 同じ対象が複数回現れた + Debug.LogWarning($"VRM10ObjectFirstPerson.SetupAsync: duplicated {x.Renderer}"); + continue; + } + + if (isSelf) + { + await SetupSelfRendererAsync(go, runtime, firstPersonBone, x, layer, awaitCaller); + } + else + { + switch (x.FirstPersonFlag) + { + case UniGLTF.Extensions.VRMC_vrm.FirstPersonType.firstPersonOnly: + if (x.GetRenderer(go.transform) is Renderer r) + { + // invisible + r.enabled = false; + runtime.VisibleRenderers.Remove(r); + } + break; + + case UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto: + // => Same as Both + case UniGLTF.Extensions.VRMC_vrm.FirstPersonType.both: + case UniGLTF.Extensions.VRMC_vrm.FirstPersonType.thirdPersonOnly: + // do nothing + break; + } + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs.meta b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs.meta new file mode 100644 index 000000000..47176cdca --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a54f419e664839f43a56ffffcbdf72db +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs new file mode 100644 index 000000000..01a0261c8 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs @@ -0,0 +1,43 @@ +using System; +using UnityEngine; +using UniGLTF.Extensions.VRMC_vrm; + +namespace UniVRM10 +{ + [Serializable] + public class VRM10ObjectLookAt + { + public enum LookAtTargetTypes + { + /// + /// Vrm10Instance に設定した Transform を見ます. + /// + SpecifiedTransform = 0, + /// + /// Vrm10RuntimeLookAt に設定した Yaw/Pitch 値に従います. + /// + YawPitchValue = 1, + + [Obsolete] CalcYawPitchToGaze = 0, + [Obsolete] SetYawPitch = 1, + } + + [SerializeField] + public Vector3 OffsetFromHead = new Vector3(0, 0.06f, 0); + + [SerializeField] + public LookAtType LookAtType; + + [SerializeField] + public CurveMapper HorizontalOuter = new CurveMapper(90.0f, 10.0f); + + [SerializeField] + public CurveMapper HorizontalInner = new CurveMapper(90.0f, 10.0f); + + [SerializeField] + public CurveMapper VerticalDown = new CurveMapper(90.0f, 10.0f); + + [SerializeField] + public CurveMapper VerticalUp = new CurveMapper(90.0f, 10.0f); + } +} diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs.meta b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs.meta new file mode 100644 index 000000000..afd2a63c1 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectLookAt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 98a194fb86eea8f49a97003a1038f31e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectMeta.cs b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectMeta.cs new file mode 100644 index 000000000..f871efe48 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectMeta.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UnityEngine; + + +namespace UniVRM10 +{ + [Serializable] + public class VRM10ObjectMeta + { + #region Info + [SerializeField] + public string Name; + + [SerializeField] + public string Version; + + [SerializeField] + public List Authors = new List(); + + [SerializeField] + public string CopyrightInformation; + + [SerializeField] + public string ContactInformation; + + [SerializeField] + public List References = new List(); + + [SerializeField] + public string ThirdPartyLicenses; + + [SerializeField] + public Texture2D Thumbnail; + #endregion + + #region AvatarPermission + [SerializeField, Tooltip("A person who can perform with this avatar")] + public UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType AvatarPermission; + + [SerializeField, Tooltip("Violent acts using this avatar")] + public bool ViolentUsage; + + [SerializeField, Tooltip("Sexuality acts using this avatar")] + public bool SexualUsage; + + [SerializeField, Tooltip("For commercial use")] + public UniGLTF.Extensions.VRMC_vrm.CommercialUsageType CommercialUsage; + + [SerializeField] + public bool PoliticalOrReligiousUsage; + + [SerializeField] + public bool AntisocialOrHateUsage; + #endregion + + #region Distribution License + [SerializeField] + public UniGLTF.Extensions.VRMC_vrm.CreditNotationType CreditNotation; + + [SerializeField] + public bool Redistribution; + + [SerializeField] + public UniGLTF.Extensions.VRMC_vrm.ModificationType Modification; + + [SerializeField] + public string OtherLicenseUrl; + #endregion + + public IEnumerable Validate(GameObject _ = null) + { + if (string.IsNullOrEmpty(Name)) + { + yield return Validation.Error("Require Name. "); + } + + if (Authors == null || Authors.Count == 0) + { + yield return Validation.Error("Require at leaset one Author."); + } + + if (Authors.All(x => string.IsNullOrWhiteSpace(x))) + { + yield return Validation.Error("All Authors is whitespace"); + } + } + + public void CopyTo(VRM10ObjectMeta dst) + { + dst.Name = Name; + dst.Version = Version; + dst.CopyrightInformation = CopyrightInformation; + if (Authors != null) + { + dst.Authors = Authors.Select(x => x).ToList(); + } + else + { + dst.Authors = new List(); + } + dst.ContactInformation = ContactInformation; + dst.CopyrightInformation = CopyrightInformation; + dst.References = References; + dst.ThirdPartyLicenses = ThirdPartyLicenses; + dst.Thumbnail = Thumbnail; + dst.AvatarPermission = AvatarPermission; + dst.ViolentUsage = ViolentUsage; + dst.SexualUsage = SexualUsage; + dst.CommercialUsage = CommercialUsage; + dst.PoliticalOrReligiousUsage = PoliticalOrReligiousUsage; + dst.CreditNotation = CreditNotation; + dst.Redistribution = Redistribution; + dst.Modification = Modification; + dst.OtherLicenseUrl = OtherLicenseUrl; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectMeta.cs.meta b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectMeta.cs.meta new file mode 100644 index 000000000..8ba5d3847 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VRM10Object/VRM10ObjectMeta.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1327f6acc7d07744ab3908816a800a6e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Instance.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Instance.meta new file mode 100644 index 000000000..cb810166e --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Instance.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a4d5df61674fa87489010760a85940e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs b/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs new file mode 100644 index 000000000..341d1fd21 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Serialization; + + +namespace UniVRM10 +{ + /// + /// VRM全体を制御するRoot + /// + /// Importer(scripted importer) -> Prefab(editor/asset) -> Instance(scene/MonoBehavior) -> Runtime(play時) + /// + /// * DefaultExecutionOrder(11000) means calculate springbone after FinalIK( VRIK ) + /// + [AddComponentMenu("VRM10/VRMInstance")] + [DisallowMultipleComponent] + [DefaultExecutionOrder(11000)] + [RequireComponent(typeof(UniHumanoid.Humanoid))] + public class Vrm10Instance : MonoBehaviour + { + /// + /// シリアライズ情報 + /// + [SerializeField, Header("VRM1")] + public VRM10Object Vrm; + + /// + /// SpringBone のシリアライズ情報 + /// + /// + [SerializeField] + public Vrm10InstanceSpringBone SpringBone = new Vrm10InstanceSpringBone(); + + public enum UpdateTypes + { + None, + Update, + LateUpdate, + } + + [SerializeField, Header("Runtime")] + public UpdateTypes UpdateType = UpdateTypes.LateUpdate; + + [SerializeField, Header("LookAt")] + public bool DrawLookAtGizmo = true; + + /// + /// The model looks at position of the Transform specified in this field. + /// That behaviour is available only when LookAtTargetType is SpecifiedTransform. + /// + /// モデルはここで指定した Transform の位置の方向に目を向けます。 + /// LookAtTargetType を SpecifiedTransform に設定したときのみ有効です。 + /// + [SerializeField, FormerlySerializedAs("Gaze")] + public Transform LookAtTarget; + + /// + /// Specify "LookAt" behaviour at runtime. + /// + /// 実行時の目の動かし方を指定します。 + /// + [SerializeField] + public VRM10ObjectLookAt.LookAtTargetTypes LookAtTargetType; + + private UniHumanoid.Humanoid m_humanoid; + private Vrm10Runtime m_runtime; + + /// + /// ControlRig の生成オプション + /// + private bool m_useControlRig; + + /// + /// VRM ファイルに記録された Humanoid ボーンに対応します。 + /// これは、コントロールリグのボーンとは異なります。 + /// + public UniHumanoid.Humanoid Humanoid + { + get + { + if (m_humanoid == null) + { + m_humanoid = GetComponent(); + } + return m_humanoid; + } + } + + /// + /// ランタイム情報 + /// + public Vrm10Runtime Runtime + { + get + { + if (m_runtime == null) + { + if (this == null) throw new MissingReferenceException("instance was destroyed"); + m_runtime = new Vrm10Runtime(this, m_useControlRig); + } + return m_runtime; + } + } + + internal void InitializeAtRuntime(bool useControlRig) + { + m_useControlRig = useControlRig; + } + + void Start() + { + if (Vrm == null) + { + Debug.LogError("no VRM10Object"); + enabled = false; + return; + } + + // cause new Vrm10Runtime. + // init LookAt init rotation. + var _ = Runtime; + } + + private void Update() + { + if (UpdateType == UpdateTypes.Update) + { + Runtime.Process(); + } + } + + private void LateUpdate() + { + if (UpdateType == UpdateTypes.LateUpdate) + { + Runtime.Process(); + } + } + + private void OnDestroy() + { + if (m_runtime != null) + { + m_runtime.Dispose(); + m_runtime = null; + } + } + + private void OnDrawGizmosSelected() + { + Gizmos.color = Color.green; + foreach (var spring in SpringBone.Springs) + { + foreach (var (head, tail) in spring.EnumHeadTail()) + { + Gizmos.DrawLine(head.transform.position, tail.transform.position); + Gizmos.DrawWireSphere(tail.transform.position, head.m_jointRadius); + } + } + } + + public bool TryGetBoneTransform(HumanBodyBones bone, out Transform t) + { + if (Humanoid == null) + { + t = null; + return false; + } + t = Humanoid.GetBoneTransform(bone); + if (t == null) + { + return false; + } + return true; + } + + #region Obsolete + + [Obsolete] + public Transform Gaze + { + get => LookAtTarget; + set => LookAtTarget = value; + } + + #endregion + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs.meta new file mode 100644 index 000000000..7e61c997e --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfba4ccd3f854e64f868ce83553071a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs b/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs new file mode 100644 index 000000000..28aaca1f5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// SpringBone の情報をすべて保持する + /// + /// * SpringBoneCollider + /// * SpringBoneJoint + /// + /// は、個別の MonoBehaviour として設定する + /// + /// + [Serializable] + public sealed class Vrm10InstanceSpringBone + { + [SerializeField] + public List ColliderGroups = new List(); + + [Serializable] + public class Spring + { + [SerializeField] + public string Name; + + public string GUIName(int i) => $"{i:00}:{Name}"; + + [SerializeField] + public List ColliderGroups = new List(); + + [SerializeField] + public List Joints = new List(); + + [SerializeField] + public Transform Center; + + public Spring(string name) + { + Name = name; + } + + public IEnumerable<(VRM10SpringBoneJoint, Transform)> EnumHeadTail() + { + for (int i = 0; i < Joints.Count; ++i) + { + var head = Joints[i]; + if (head == null) + { + continue; + } + for (int j = i + 1; j < Joints.Count; ++j) + { + var tail = Joints[j]; + if (tail != null) + { + yield return (head, tail.transform); + break; + } + } + } + } + } + + [SerializeField] + public List Springs = new List(); + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs.meta new file mode 100644 index 000000000..04d0cda81 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 59fabd31ab5a08240adb8ac808109022 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime.meta new file mode 100644 index 000000000..075e4e2b7 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea81ef4ff96a05a4f8d4f0eefc8bd2fd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig.meta new file mode 100644 index 000000000..801f624a0 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0f3a2bf6126d4a49b24a5fc2a7b6e64 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs new file mode 100644 index 000000000..4268f59d8 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs @@ -0,0 +1,17 @@ +namespace UniVRM10 +{ + public enum ControlRigGenerationOption + { + /// + /// コントロールリグを生成しません。 + /// + None = 0, + + /// + /// 推奨されるオプションです。 + /// コントロールリグのボーン Transform を生成し、Root の Animator はコントロールリグのボーンを制御するようになります。 + /// + Generate = 1, + Vrm0XCompatibleRig = 1, + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs.meta new file mode 100644 index 000000000..f32b76551 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 254b61afe523dd74b9579ff1e971bee7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs new file mode 100644 index 000000000..80c41055a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// The control bone of the control rig. + /// + /// このクラスのヒエラルキーが 正規化された TPose を表している。 + /// 同時に、元のヒエラルキーの初期回転を保持する。 + /// Apply 関数で、再帰的に正規化済みのローカル回転から初期回転を加味したローカル回転を作って適用する。 + /// + public sealed class Vrm10ControlBone + { + /// + /// このコントロールボーンに紐づくボーンの種類。 + /// + public HumanBodyBones BoneType { get; } + + /// + /// コントロール対象のボーン Transform。 + /// + public Transform ControlTarget { get; } + + /// + /// コントロールボーンの Transform。 + /// + /// VRM の T-Pose 姿勢をしているときに、回転とスケールが初期値になっている(正規化)。 + /// このボーンに対して localRotation を代入し、コントロールを行う。 + /// + public Transform ControlBone { get; } + + private readonly Quaternion _initialTargetLocalRotation; + private readonly Quaternion _initialTargetGlobalRotation; + public Vector3 InitialTargetGlobalPosition { get; } + private readonly List _children = new List(); + public IReadOnlyList Children => _children; + + private Vrm10ControlBone(Transform controlTarget, HumanBodyBones boneType, Vrm10ControlBone parent, Transform root) + { + if (boneType == HumanBodyBones.LastBone) + { + throw new ArgumentNullException(); + } + if (controlTarget == null) + { + throw new ArgumentNullException(); + } + + BoneType = boneType; + ControlTarget = controlTarget; + + // 回転とスケールが除去されたTPoseを構築 + // NOTE: bone name must be unique in the vrm instance. + ControlBone = new GameObject($"{nameof(Vrm10ControlBone)}:{boneType.ToString()}").transform; + ControlBone.position = controlTarget.position; + if (parent != null) + { + ControlBone.SetParent(parent.ControlBone, true); + parent._children.Add(this); + } + + _initialTargetLocalRotation = controlTarget.localRotation; + _initialTargetGlobalRotation = controlTarget.rotation; + InitialTargetGlobalPosition = root.worldToLocalMatrix.MultiplyPoint(controlTarget.position); + } + + /// + /// 親から再帰的にNormalized の ローカル回転を初期回転を加味して Target に適用する。 + /// + internal void ProcessRecursively() + { + ControlTarget.localRotation = _initialTargetLocalRotation * (Quaternion.Inverse(_initialTargetGlobalRotation) * ControlBone.localRotation * _initialTargetGlobalRotation); + foreach (var child in _children) + { + child.ProcessRecursively(); + } + } + + public static Vrm10ControlBone Build(UniHumanoid.Humanoid humanoid, out Dictionary boneMap, Transform root) + { + var hips = new Vrm10ControlBone(humanoid.Hips, HumanBodyBones.Hips, null, root); + boneMap = new Dictionary(); + boneMap.Add(HumanBodyBones.Hips, hips); + + foreach (Transform child in humanoid.Hips) + { + BuildRecursively(humanoid, child, hips, boneMap, root); + } + + return hips; + } + + private static void BuildRecursively(UniHumanoid.Humanoid humanoid, Transform current, Vrm10ControlBone parent, Dictionary boneMap, Transform root) + { + if (humanoid.TryGetBoneForTransform(current, out var bone)) + { + var newBone = new Vrm10ControlBone(current, bone, parent, root); + parent = newBone; + boneMap.Add(bone, newBone); + } + + foreach (Transform child in current) + { + BuildRecursively(humanoid, child, parent, boneMap, root); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs.meta new file mode 100644 index 000000000..35e73e07c --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eac40a89a1de8bc4a8d97b3cc2aea5fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs new file mode 100644 index 000000000..d054033e8 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniHumanoid; +using UnityEngine; +using UniGLTF.Utils; + +namespace UniVRM10 +{ + /// + /// VRM 1.0 モデルインスタンスに対して、コントロールリグを生成します。 + /// これは VRM 0.x のような、正規化されたボーン操作を提供します。 + /// + /// Create a control rig for the VRM 1.0 model instance. + /// This provides the normalized operation of bones, like VRM 0.x. + /// + public sealed class Vrm10RuntimeControlRig : IDisposable, INormalizedPoseApplicable, ITPoseProvider + { + private readonly Transform _controlRigRoot; + private readonly Vrm10ControlBone _hipBone; + private readonly Dictionary _bones; + private readonly Avatar _controlRigAvatar; + + public IReadOnlyDictionary Bones => _bones; + public Animator ControlRigAnimator { get; } + + /// + /// humanoid に対して ControlRig を生成します + /// + /// T-Pose である必要があります + /// + public Vrm10RuntimeControlRig(UniHumanoid.Humanoid humanoid, Transform vrmRoot) + { + _controlRigRoot = new GameObject("Runtime Control Rig").transform; + _controlRigRoot.SetParent(vrmRoot); + + _hipBone = Vrm10ControlBone.Build(humanoid, out _bones, _controlRigRoot); + _hipBone.ControlBone.SetParent(_controlRigRoot); + + var transformBonePairs = _bones.Select(kv => (kv.Value.ControlBone, kv.Key)); + _controlRigAvatar = HumanoidLoader.LoadHumanoidAvatar(vrmRoot, transformBonePairs); + _controlRigAvatar.name = "Runtime Control Rig"; + + ControlRigAnimator = vrmRoot.GetComponent(); + ControlRigAnimator.avatar = _controlRigAvatar; + } + + public void Dispose() + { + UnityEngine.Object.Destroy(_controlRigAvatar); + UnityEngine.Object.Destroy(_controlRigRoot); + } + + internal void Process() + { + _hipBone.ControlTarget.position = _hipBone.ControlBone.position; + _hipBone.ProcessRecursively(); + } + + public Transform GetBoneTransform(HumanBodyBones bone) + { + if (_bones.TryGetValue(bone, out var value)) + { + return value.ControlBone; + } + else + { + return null; + } + } + + void INormalizedPoseApplicable.SetRawHipsPosition(Vector3 position) + { + var world = _controlRigRoot.TransformPoint(position); + _hipBone.ControlBone.position = world; + } + + void INormalizedPoseApplicable.SetNormalizedLocalRotation(HumanBodyBones bone, Quaternion normalizedLocalRotation) + { + if (_bones.TryGetValue(bone, out var t)) + { + t.ControlBone.localRotation = normalizedLocalRotation; + } + } + + EuclideanTransform? ITPoseProvider.GetWorldTransform(HumanBodyBones bone) + { + if (_bones.TryGetValue(bone, out var t)) + { + return new EuclideanTransform(t.InitialTargetGlobalPosition); + } + else + { + return default; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs.meta new file mode 100644 index 000000000..e48351021 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c0af836ff386dd469cfedbd238ab2a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs new file mode 100644 index 000000000..8a40ad9e5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UniGLTF.Utils; +using UnityEngine; +using UniVRM10.FastSpringBones.Blittables; +using UniVRM10.FastSpringBones.System; + +namespace UniVRM10 +{ + /// + /// VRM モデルインスタンスを、状態をもって、元の状態から操作・変更するためのクラス。 + /// また、仕様に従ってその操作を行う。 + /// + /// 操作対象としては以下が挙げられる。 + /// - ControlRig + /// - Constraint + /// - LookAt + /// - Expression + /// + public class Vrm10Runtime : IDisposable + { + private readonly Vrm10Instance m_instance; + private readonly Transform m_head; + private readonly FastSpringBoneService m_fastSpringBoneService; + private readonly IReadOnlyDictionary m_defaultTransformStates; + + private FastSpringBoneBuffer m_fastSpringBoneBuffer; + private BlittableExternalData m_externalData; + + /// + /// Control Rig may be null. + /// Control Rig is generated at loading runtime only. + /// + public Vrm10RuntimeControlRig ControlRig { get; } + + public IVrm10Constraint[] Constraints { get; } + public Vrm10RuntimeExpression Expression { get; } + public Vrm10RuntimeLookAt LookAt { get; } + + public IVrm10Animation VrmAnimation { get; set; } + + public Vector3 ExternalForce + { + get => m_externalData.ExternalForce; + set + { + m_externalData.ExternalForce = value; + m_fastSpringBoneBuffer.ExternalData = m_externalData; + } + } + + public Vrm10Runtime(Vrm10Instance instance, bool useControlRig) + { + if (!Application.isPlaying) + { + Debug.LogWarning($"{nameof(Vrm10Runtime)} expects runtime behaviour."); + } + + m_instance = instance; + + if (!instance.TryGetBoneTransform(HumanBodyBones.Head, out m_head)) + { + throw new Exception(); + } + + if (useControlRig) + { + ControlRig = new Vrm10RuntimeControlRig(instance.Humanoid, m_instance.transform); + } + Constraints = instance.GetComponentsInChildren(); + LookAt = new Vrm10RuntimeLookAt(instance.Vrm.LookAt, instance.Humanoid, ControlRig); + Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable); + + var gltfInstance = instance.GetComponent(); + if (gltfInstance != null) + { + // ランタイムインポートならここに到達してゼロコストになる + m_defaultTransformStates = gltfInstance.InitialTransformStates; + } + else + { + // エディタでプレハブ配置してる奴ならこっちに到達して収集する + m_defaultTransformStates = instance.GetComponentsInChildren() + .ToDictionary(tf => tf, tf => new TransformState(tf)); + } + + // NOTE: FastSpringBoneService は UnitTest などでは動作しない + if (Application.isPlaying) + { + m_fastSpringBoneService = FastSpringBoneService.Instance; + m_fastSpringBoneBuffer = CreateFastSpringBoneBuffer(m_instance.SpringBone); + m_fastSpringBoneService.BufferCombiner.Register(m_fastSpringBoneBuffer); + } + } + + public void Dispose() + { + ControlRig?.Dispose(); + m_fastSpringBoneService.BufferCombiner.Unregister(m_fastSpringBoneBuffer); + m_fastSpringBoneBuffer.Dispose(); + } + + /// + /// このVRMに紐づくSpringBone関連のバッファを再構築する + /// ランタイム実行時にSpringBoneに対して変更を行いたいときは、このメソッドを明示的に呼ぶ必要がある + /// + public void ReconstructSpringBone() + { + m_fastSpringBoneService.BufferCombiner.Unregister(m_fastSpringBoneBuffer); + + m_fastSpringBoneBuffer.Dispose(); + m_fastSpringBoneBuffer = CreateFastSpringBoneBuffer(m_instance.SpringBone); + + m_fastSpringBoneService.BufferCombiner.Register(m_fastSpringBoneBuffer); + } + + private FastSpringBoneBuffer CreateFastSpringBoneBuffer(Vrm10InstanceSpringBone springBone) + { + return new FastSpringBoneBuffer( + springBone.Springs.Select(spring => new FastSpringBoneSpring + { + center = spring.Center, + colliders = spring.ColliderGroups + .SelectMany(group => group.Colliders) + .Select(collider => new FastSpringBoneCollider + { + Transform = collider.transform, + Collider = new BlittableCollider + { + offset = collider.Offset, + radius = collider.Radius, + tail = collider.Tail, + colliderType = TranslateColliderType(collider.ColliderType) + } + }).ToArray(), + joints = spring.Joints + .Select(joint => new FastSpringBoneJoint + { + Transform = joint.transform, + Joint = new BlittableJoint + { + radius = joint.m_jointRadius, + dragForce = joint.m_dragForce, + gravityDir = joint.m_gravityDir, + gravityPower = joint.m_gravityPower, + stiffnessForce = joint.m_stiffnessForce + }, + DefaultLocalRotation = GetOrAddDefaultTransformState(joint.transform).LocalRotation, + }).ToArray(), + }).ToArray(), + m_externalData); + } + + private TransformState GetOrAddDefaultTransformState(Transform tf) + { + if (m_defaultTransformStates.TryGetValue(tf, out var defaultTransformState)) + { + return defaultTransformState; + } + + Debug.LogWarning($"{tf.name} does not exist on load."); + return new TransformState(null); + } + + private static BlittableColliderType TranslateColliderType(VRM10SpringBoneColliderTypes colliderType) + { + switch (colliderType) + { + case VRM10SpringBoneColliderTypes.Sphere: + return BlittableColliderType.Sphere; + case VRM10SpringBoneColliderTypes.Capsule: + return BlittableColliderType.Capsule; + default: + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// 毎フレーム関連コンポーネントを解決する + /// + /// * Update from VrmAnimation + /// * Constraint + /// * Spring + /// * LookAt + /// * Expression + /// + /// + public void Process() + { + // 1. Update From VrmAnimation + if (VrmAnimation != null) + { + // copy pose + { + Vrm10Retarget.Retarget(VrmAnimation.ControlRig, (ControlRig, ControlRig)); + } + + // update expressions + foreach (var (k, v) in VrmAnimation.ExpressionMap) + { + Expression.SetWeight(k, v()); + } + + // look at + if (VrmAnimation.LookAt.HasValue) + { + LookAt.LookAtInput = VrmAnimation.LookAt.Value; + } + } + + // 2. Control Rig + ControlRig?.Process(); + + // 3. Constraints + foreach (var constraint in Constraints) + { + constraint.Process(); + } + + if (m_instance.LookAtTargetType == VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform + && m_instance.LookAtTarget != null) + { + // Transform 追跡で視線を生成する。 + // 値を上書きします。 + LookAt.LookAtInput = new LookAtInput { WorldPosition = m_instance.LookAtTarget.position }; + } + + // 4. Gaze control + var eyeDirection = LookAt.Process(); + + // 5. Apply Expression + // LookAt の角度制限などはこちらで処理されます。 + Expression.Process(eyeDirection); + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs.meta new file mode 100644 index 000000000..9d78fc946 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f690a05022c98184bacf46b6675f5bc8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs new file mode 100644 index 000000000..71ec15f9e --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs @@ -0,0 +1,136 @@ +using System.Collections.Generic; +using System.Linq; + +namespace UniVRM10 +{ + public sealed class Vrm10RuntimeExpression + { + public static IExpressionValidatorFactory ExpressionValidatorFactory = new DefaultExpressionValidator.Factory(); + + private List _keys = new List(); + private Dictionary _inputWeights = new Dictionary(); + private Dictionary _actualWeights = new Dictionary(); + private ExpressionMerger _merger; + private IExpressionValidator _validator; + private LookAtEyeDirection _actualEyeDirection; + private ILookAtEyeDirectionApplicable _eyeDirectionApplicable; + + public IReadOnlyList ExpressionKeys => _keys; + public IReadOnlyDictionary ActualWeights => _actualWeights; + public LookAtEyeDirection ActualEyeDirection => _actualEyeDirection; + public float BlinkOverrideRate { get; private set; } + public float LookAtOverrideRate { get; private set; } + public float MouthOverrideRate { get; private set; } + + int m_debugCount; + + internal Vrm10RuntimeExpression(Vrm10Instance target, ILookAtEyeDirectionApplicable eyeDirectionApplicable) + { + Restore(); + + _merger = new ExpressionMerger(target.Vrm.Expression, target.transform); + _keys = target.Vrm.Expression.Clips + .Select(x => target.Vrm.Expression.CreateKey(x.Clip)) + .ToList(); + var oldInputWeights = _inputWeights; + _inputWeights = _keys.ToDictionary( + x => x, + x => 0f, + ExpressionKey.Comparer + ); + foreach (var key in _keys) + { + // remain user input weights. + if (oldInputWeights.ContainsKey(key)) _inputWeights[key] = oldInputWeights[key]; + } + _actualWeights = _keys.ToDictionary( + x => x, + x => 0f, + ExpressionKey.Comparer + ); + _validator = ExpressionValidatorFactory.Create(target.Vrm.Expression); + _eyeDirectionApplicable = eyeDirectionApplicable; + } + + internal void Restore() + { + _merger?.RestoreMaterialInitialValues(); + _merger = null; + + _eyeDirectionApplicable?.Restore(); + _eyeDirectionApplicable = null; + } + + internal void Process(LookAtEyeDirection inputEyeDirection) + { + Apply(inputEyeDirection); + } + + public IDictionary GetWeights() + { + return _inputWeights; + } + + public float GetWeight(ExpressionKey expressionKey) + { + if (_inputWeights.ContainsKey(expressionKey)) + { + return _inputWeights[expressionKey]; + } + + return 0f; + } + + public void SetWeights(IEnumerable> weights) + { + foreach (var (expressionKey, weight) in weights) + { + if (_inputWeights.ContainsKey(expressionKey)) + { + _inputWeights[expressionKey] = weight; + } + } + } + + public void SetWeightsNonAlloc(Dictionary weights) + { + foreach (var (expressionKey, weight) in weights) + { + if (_inputWeights.ContainsKey(expressionKey)) + { + _inputWeights[expressionKey] = weight; + } + } + } + + public void SetWeight(ExpressionKey expressionKey, float weight) + { + if (_inputWeights.ContainsKey(expressionKey)) + { + _inputWeights[expressionKey] = weight; + } + } + + /// + /// 入力 Weight を基に、Validation を行い実際にモデルに適用される Weights を計算し、Merger を介して適用する。 + /// この際、LookAt の情報を pull してそれも適用する。 + /// + private void Apply(LookAtEyeDirection inputEyeDirection) + { + // 1. Validate user input, and Output as actual weights. + _validator.Validate(_inputWeights, _actualWeights, + inputEyeDirection, out _actualEyeDirection, + out var blink, out var lookAt, out var mouth); + + // 2. Set eye direction expression weights or any other side-effects (ex. eye bone). + _eyeDirectionApplicable?.Apply(_actualEyeDirection, _actualWeights); + + // 3. Set actual weights to raw blendshapes. + _merger.SetValues(_actualWeights); + + BlinkOverrideRate = blink; + LookAtOverrideRate = lookAt; + MouthOverrideRate = mouth; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs.meta new file mode 100644 index 000000000..ac7366f41 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c644583b448f6e743a6d2a55d1d617bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs new file mode 100644 index 000000000..c7b3d0c1d --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs @@ -0,0 +1,141 @@ +using System; +using UniGLTF.Extensions.VRMC_vrm; +using UnityEngine; + +namespace UniVRM10 +{ + public sealed class Vrm10RuntimeLookAt : ILookAtEyeDirectionProvider + { + private readonly VRM10ObjectLookAt _lookAt; + private readonly Transform _head; + private readonly Vector3 _lookAtOriginTransformLocalPosition; + private readonly Quaternion _lookAtOriginTransformLocalRotation; + + internal ILookAtEyeDirectionApplicable EyeDirectionApplicable { get; } + + /// + /// 入力値。適宜更新可。 + /// + public LookAtInput LookAtInput { get; set; } + + /// + /// 出力値。Process() のみが更新する + /// + public LookAtEyeDirection EyeDirection { get; private set; } + public float Yaw => EyeDirection.Yaw; + public float Pitch => EyeDirection.Pitch; + + /// + /// Transform that indicates the position center of eyes. + /// This only represents the position of center of eyes, not the viewing direction. + /// Local +Z axis represents forward vector of the head. + /// Local +Y axis represents up vector of the head. + /// + /// 目の位置を示す Transform。 + /// 視線方向は反映されない。 + /// ローカル +Z 軸が頭の正面方向を表す。 + /// ローカル +Y 軸が頭の上方向を表す。 + /// + public Transform LookAtOriginTransform { get; } + + internal Vrm10RuntimeLookAt(VRM10ObjectLookAt lookAt, UniHumanoid.Humanoid humanoid, Vrm10RuntimeControlRig controlRig) + { + _lookAt = lookAt; + LookAtOriginTransform = InitializeLookAtOriginTransform( + humanoid.Head, + controlRig != null ? controlRig.GetBoneTransform(HumanBodyBones.Head) : humanoid.Head, + _lookAt.OffsetFromHead); + _lookAtOriginTransformLocalPosition = LookAtOriginTransform.localPosition; + _lookAtOriginTransformLocalRotation = LookAtOriginTransform.localRotation; + + var leftEyeBone = humanoid.GetBoneTransform(HumanBodyBones.LeftEye); + var rightEyeBone = humanoid.GetBoneTransform(HumanBodyBones.RightEye); + if (_lookAt.LookAtType == LookAtType.bone && leftEyeBone != null && rightEyeBone != null) + { + EyeDirectionApplicable = new LookAtEyeDirectionApplicableToBone(leftEyeBone, rightEyeBone, _lookAt.HorizontalOuter, _lookAt.HorizontalInner, _lookAt.VerticalDown, _lookAt.VerticalUp); + } + else + { + EyeDirectionApplicable = new LookAtEyeDirectionApplicableToExpression(_lookAt.HorizontalOuter, _lookAt.HorizontalInner, _lookAt.VerticalDown, _lookAt.VerticalUp); + } + } + + internal LookAtEyeDirection Process() + { + LookAtOriginTransform.localPosition = _lookAtOriginTransformLocalPosition; + LookAtOriginTransform.localRotation = _lookAtOriginTransformLocalRotation; + + if (LookAtInput.YawPitch is LookAtEyeDirection dir) + { + EyeDirection = dir; + } + else if (LookAtInput.WorldPosition is Vector3 worldPosition) + { + // NOTE: 指定された Transform の位置を向くように Yaw/Pitch を計算して適用する + var (yaw, pitch) = CalculateYawPitchFromLookAtPosition(worldPosition); + EyeDirection = new LookAtEyeDirection(yaw, pitch); + } + return EyeDirection; + } + + /// + /// Yaw/Pitch 値を直接設定します。 + /// Vrm10Instance.LookAtTargetTypes が SpecifiedTransform の場合、ここで設定しても値は上書きされます。 + /// + /// Headボーンのforwardに対するyaw角(度) + /// Headボーンのforwardに対するpitch角(度) + public void SetYawPitchManually(float yaw, float pitch) + { + LookAtInput = new LookAtInput { YawPitch = new LookAtEyeDirection(yaw, pitch) }; + } + + public (float Yaw, float Pitch) CalculateYawPitchFromLookAtPosition(Vector3 lookAtWorldPosition) + { + var localPosition = LookAtOriginTransform.worldToLocalMatrix.MultiplyPoint(lookAtWorldPosition); + Matrix4x4.identity.CalcYawPitch(localPosition, out var yaw, out var pitch); + return (yaw, pitch); + } + + private static Transform InitializeLookAtOriginTransform(Transform rawHead, Transform actualHead, Vector3 eyeOffsetValue) + { + // NOTE: このメソッドを実行するとき、モデル全体は初期姿勢(T-Pose)でなければならない。 + var lookAtOrigin = new GameObject("_look_at_origin_").transform; + lookAtOrigin.SetParent(actualHead); + lookAtOrigin.position = rawHead.TransformPoint(eyeOffsetValue); + lookAtOrigin.rotation = Quaternion.identity; + + return lookAtOrigin; + } + + #region Obsolete + [Obsolete("Use " + nameof(LookAtOriginTransform))] + public Transform GetLookAtOrigin(Transform head) + { + return LookAtOriginTransform; + } + + [Obsolete("Use " + nameof(SetYawPitchManually))] + public void SetLookAtYawPitch(float yaw, float pitch) + { + SetYawPitchManually(yaw, pitch); + } + + [Obsolete("Use " + nameof(Yaw) + " & " + nameof(Pitch))] + public (float, float) GetLookAtYawPitch( + Transform head, + VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, + Transform gaze) + { + switch (lookAtTargetType) + { + case VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform: + return CalculateYawPitchFromLookAtPosition(gaze.position); + case VRM10ObjectLookAt.LookAtTargetTypes.YawPitchValue: + return (Yaw, Pitch); + default: + throw new ArgumentOutOfRangeException(nameof(lookAtTargetType), lookAtTargetType, null); + } + } + #endregion + } +} diff --git a/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs.meta b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs.meta new file mode 100644 index 000000000..2a02c607a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeLookAt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08fd3fec20846764dbb598cf75b13356 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance.meta b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance.meta new file mode 100644 index 000000000..bf657e5d1 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a6fde18d19837ab488a01dac4ddc962e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs new file mode 100644 index 000000000..6936ab7a3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + public interface IVrm10Animation : IDisposable + { + (INormalizedPoseProvider, ITPoseProvider) ControlRig { get; } + IReadOnlyDictionary> ExpressionMap { get; } + public void ShowBoxMan(bool enable); + LookAtInput? LookAt { get; } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs.meta b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs.meta new file mode 100644 index 000000000..9b2379524 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/IVrm10Animation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b2654d5824889e418b2f9bdc9456680 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs new file mode 100644 index 000000000..4cbb3b861 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs @@ -0,0 +1,334 @@ +using System; +using System.Collections.Generic; +using UniHumanoid; +using UnityEngine; + +namespace UniVRM10 +{ + public class Vrm10AnimationInstance : MonoBehaviour, IVrm10Animation + { + public SkinnedMeshRenderer BoxMan; + public void ShowBoxMan(bool enable) + { + BoxMan.enabled = enable; + } + + public void Dispose() + { + if (Application.isPlaying) + { + Destroy(this); + } + else + { + DestroyImmediate(this); + } + } + + public (INormalizedPoseProvider, ITPoseProvider) ControlRig { get; set; } + + readonly Dictionary> _ExpressionGetterMap = new(); + public IReadOnlyDictionary> ExpressionMap => _ExpressionGetterMap; + + readonly Dictionary> _ExpressionSetterMap = new(); + public IReadOnlyDictionary> ExpressionSetterMap => _ExpressionSetterMap; + + public LookAtInput? LookAt { get; set; } + + void InitializeExpression(ExpressionKey key, Func getter, Action setter) + { + _ExpressionGetterMap.Add(key, getter); + _ExpressionSetterMap.Add(key, setter); + } + + public float preset_happy; + public float preset_angry; + public float preset_sad; + public float preset_relaxed; + public float preset_surprised; + public float preset_aa; + public float preset_ih; + public float preset_ou; + public float preset_ee; + public float preset_oh; + public float preset_blink; + public float preset_blinkleft; + public float preset_blinkright; + // public float preset_lookup; + // public float preset_lookdown; + // public float preset_lookleft; + // public float preset_lookright; + public float preset_neutral; + + public float custom_00; + public float custom_01; + public float custom_02; + public float custom_03; + public float custom_04; + public float custom_05; + public float custom_06; + public float custom_07; + public float custom_08; + public float custom_09; + + public float custom_10; + public float custom_11; + public float custom_12; + public float custom_13; + public float custom_14; + public float custom_15; + public float custom_16; + public float custom_17; + public float custom_18; + public float custom_19; + + public float custom_20; + public float custom_21; + public float custom_22; + public float custom_23; + public float custom_24; + public float custom_25; + public float custom_26; + public float custom_27; + public float custom_28; + public float custom_29; + + public float custom_30; + public float custom_31; + public float custom_32; + public float custom_33; + public float custom_34; + public float custom_35; + public float custom_36; + public float custom_37; + public float custom_38; + public float custom_39; + + public float custom_40; + public float custom_41; + public float custom_42; + public float custom_43; + public float custom_44; + public float custom_45; + public float custom_46; + public float custom_47; + public float custom_48; + public float custom_49; + + public float custom_50; + public float custom_51; + public float custom_52; + public float custom_53; + public float custom_54; + public float custom_55; + public float custom_56; + public float custom_57; + public float custom_58; + public float custom_59; + + public float custom_60; + public float custom_61; + public float custom_62; + public float custom_63; + public float custom_64; + public float custom_65; + public float custom_66; + public float custom_67; + public float custom_68; + public float custom_69; + + public float custom_70; + public float custom_71; + public float custom_72; + public float custom_73; + public float custom_74; + public float custom_75; + public float custom_76; + public float custom_77; + public float custom_78; + public float custom_79; + + public float custom_80; + public float custom_81; + public float custom_82; + public float custom_83; + public float custom_84; + public float custom_85; + public float custom_86; + public float custom_87; + public float custom_88; + public float custom_89; + + public float custom_90; + public float custom_91; + public float custom_92; + public float custom_93; + public float custom_94; + public float custom_95; + public float custom_96; + public float custom_97; + public float custom_98; + public float custom_99; + + public void Initialize(IEnumerable keys) + { + var humanoid = gameObject.AddComponent(); + if (humanoid.AssignBonesFromAnimator()) + { + // require: transform is T-Pose + var provider = new InitRotationPoseProvider(transform, humanoid); + ControlRig = (provider, provider); + + // create SkinnedMesh for bone visualize + var animator = GetComponent(); + BoxMan = SkeletonMeshUtility.CreateRenderer(animator); + var material = new Material(Shader.Find("Standard")); + BoxMan.sharedMaterial = material; + var mesh = BoxMan.sharedMesh; + mesh.name = "box-man"; + } + + int customIndex = 0; + foreach (var key in keys) + { + switch (key.Preset) + { + case ExpressionPreset.happy: InitializeExpression(key, () => preset_happy, (value) => preset_happy = value); break; + case ExpressionPreset.angry: InitializeExpression(key, () => preset_angry, (value) => preset_angry = value); break; + case ExpressionPreset.sad: InitializeExpression(key, () => preset_sad, (value) => preset_sad = value); break; + case ExpressionPreset.relaxed: InitializeExpression(key, () => preset_relaxed, (value) => preset_relaxed = value); break; + case ExpressionPreset.surprised: InitializeExpression(key, () => preset_surprised, (value) => preset_surprised = value); break; + case ExpressionPreset.aa: InitializeExpression(key, () => preset_aa, (value) => preset_aa = value); break; + case ExpressionPreset.ih: InitializeExpression(key, () => preset_ih, (value) => preset_ih = value); break; + case ExpressionPreset.ou: InitializeExpression(key, () => preset_ou, (value) => preset_ou = value); break; + case ExpressionPreset.ee: InitializeExpression(key, () => preset_ee, (value) => preset_ee = value); break; + case ExpressionPreset.oh: InitializeExpression(key, () => preset_oh, (value) => preset_oh = value); break; + case ExpressionPreset.blink: InitializeExpression(key, () => preset_blink, (value) => preset_blink = value); break; + case ExpressionPreset.blinkLeft: InitializeExpression(key, () => preset_blinkleft, (value) => preset_blinkleft = value); break; + case ExpressionPreset.blinkRight: InitializeExpression(key, () => preset_blinkright, (value) => preset_blinkright = value); break; + // case ExpressionPreset.lookUp: _ExpressionMap.Add(key, () => preset_lookUp); break; + // case ExpressionPreset.lookDown: _ExpressionMap.Add(key, () => preset_lookDown); break; + // case ExpressionPreset.lookLeft: _ExpressionMap.Add(key, () => preset_lookLeft); break; + // case ExpressionPreset.lookRight: _ExpressionMap.Add(key, () => preset_lookRight); break; + case ExpressionPreset.neutral: InitializeExpression(key, () => preset_neutral, (value) => preset_neutral = value); break; + case ExpressionPreset.custom: + { + switch (customIndex++) + { + case 00: InitializeExpression(key, () => custom_00, (value) => custom_00 = value); break; + case 01: InitializeExpression(key, () => custom_01, (value) => custom_01 = value); break; + case 02: InitializeExpression(key, () => custom_02, (value) => custom_02 = value); break; + case 03: InitializeExpression(key, () => custom_03, (value) => custom_03 = value); break; + case 04: InitializeExpression(key, () => custom_04, (value) => custom_04 = value); break; + case 05: InitializeExpression(key, () => custom_05, (value) => custom_05 = value); break; + case 06: InitializeExpression(key, () => custom_06, (value) => custom_06 = value); break; + case 07: InitializeExpression(key, () => custom_07, (value) => custom_07 = value); break; + case 08: InitializeExpression(key, () => custom_08, (value) => custom_08 = value); break; + case 09: InitializeExpression(key, () => custom_09, (value) => custom_09 = value); break; + + case 10: InitializeExpression(key, () => custom_10, (value) => custom_10 = value); break; + case 11: InitializeExpression(key, () => custom_11, (value) => custom_11 = value); break; + case 12: InitializeExpression(key, () => custom_12, (value) => custom_12 = value); break; + case 13: InitializeExpression(key, () => custom_13, (value) => custom_13 = value); break; + case 14: InitializeExpression(key, () => custom_14, (value) => custom_14 = value); break; + case 15: InitializeExpression(key, () => custom_15, (value) => custom_15 = value); break; + case 16: InitializeExpression(key, () => custom_16, (value) => custom_16 = value); break; + case 17: InitializeExpression(key, () => custom_17, (value) => custom_17 = value); break; + case 18: InitializeExpression(key, () => custom_18, (value) => custom_18 = value); break; + case 19: InitializeExpression(key, () => custom_19, (value) => custom_19 = value); break; + + case 20: InitializeExpression(key, () => custom_20, (value) => custom_20 = value); break; + case 21: InitializeExpression(key, () => custom_21, (value) => custom_21 = value); break; + case 22: InitializeExpression(key, () => custom_22, (value) => custom_22 = value); break; + case 23: InitializeExpression(key, () => custom_23, (value) => custom_23 = value); break; + case 24: InitializeExpression(key, () => custom_24, (value) => custom_24 = value); break; + case 25: InitializeExpression(key, () => custom_25, (value) => custom_25 = value); break; + case 26: InitializeExpression(key, () => custom_26, (value) => custom_26 = value); break; + case 27: InitializeExpression(key, () => custom_27, (value) => custom_27 = value); break; + case 28: InitializeExpression(key, () => custom_28, (value) => custom_28 = value); break; + case 29: InitializeExpression(key, () => custom_29, (value) => custom_29 = value); break; + + case 30: InitializeExpression(key, () => custom_30, (value) => custom_30 = value); break; + case 31: InitializeExpression(key, () => custom_31, (value) => custom_31 = value); break; + case 32: InitializeExpression(key, () => custom_32, (value) => custom_32 = value); break; + case 33: InitializeExpression(key, () => custom_33, (value) => custom_33 = value); break; + case 34: InitializeExpression(key, () => custom_34, (value) => custom_34 = value); break; + case 35: InitializeExpression(key, () => custom_35, (value) => custom_35 = value); break; + case 36: InitializeExpression(key, () => custom_36, (value) => custom_36 = value); break; + case 37: InitializeExpression(key, () => custom_37, (value) => custom_37 = value); break; + case 38: InitializeExpression(key, () => custom_38, (value) => custom_38 = value); break; + case 39: InitializeExpression(key, () => custom_39, (value) => custom_39 = value); break; + + case 40: InitializeExpression(key, () => custom_40, (value) => custom_40 = value); break; + case 41: InitializeExpression(key, () => custom_41, (value) => custom_41 = value); break; + case 42: InitializeExpression(key, () => custom_42, (value) => custom_42 = value); break; + case 43: InitializeExpression(key, () => custom_43, (value) => custom_43 = value); break; + case 44: InitializeExpression(key, () => custom_44, (value) => custom_44 = value); break; + case 45: InitializeExpression(key, () => custom_45, (value) => custom_45 = value); break; + case 46: InitializeExpression(key, () => custom_46, (value) => custom_46 = value); break; + case 47: InitializeExpression(key, () => custom_47, (value) => custom_47 = value); break; + case 48: InitializeExpression(key, () => custom_48, (value) => custom_48 = value); break; + case 49: InitializeExpression(key, () => custom_49, (value) => custom_49 = value); break; + + case 50: InitializeExpression(key, () => custom_50, (value) => custom_50 = value); break; + case 51: InitializeExpression(key, () => custom_51, (value) => custom_51 = value); break; + case 52: InitializeExpression(key, () => custom_52, (value) => custom_52 = value); break; + case 53: InitializeExpression(key, () => custom_53, (value) => custom_53 = value); break; + case 54: InitializeExpression(key, () => custom_54, (value) => custom_54 = value); break; + case 55: InitializeExpression(key, () => custom_55, (value) => custom_55 = value); break; + case 56: InitializeExpression(key, () => custom_56, (value) => custom_56 = value); break; + case 57: InitializeExpression(key, () => custom_57, (value) => custom_57 = value); break; + case 58: InitializeExpression(key, () => custom_58, (value) => custom_58 = value); break; + case 59: InitializeExpression(key, () => custom_59, (value) => custom_59 = value); break; + + case 60: InitializeExpression(key, () => custom_60, (value) => custom_60 = value); break; + case 61: InitializeExpression(key, () => custom_61, (value) => custom_61 = value); break; + case 62: InitializeExpression(key, () => custom_62, (value) => custom_62 = value); break; + case 63: InitializeExpression(key, () => custom_63, (value) => custom_63 = value); break; + case 64: InitializeExpression(key, () => custom_64, (value) => custom_64 = value); break; + case 65: InitializeExpression(key, () => custom_65, (value) => custom_65 = value); break; + case 66: InitializeExpression(key, () => custom_66, (value) => custom_66 = value); break; + case 67: InitializeExpression(key, () => custom_67, (value) => custom_67 = value); break; + case 68: InitializeExpression(key, () => custom_68, (value) => custom_68 = value); break; + case 69: InitializeExpression(key, () => custom_69, (value) => custom_69 = value); break; + + case 70: InitializeExpression(key, () => custom_70, (value) => custom_70 = value); break; + case 71: InitializeExpression(key, () => custom_71, (value) => custom_71 = value); break; + case 72: InitializeExpression(key, () => custom_72, (value) => custom_72 = value); break; + case 73: InitializeExpression(key, () => custom_73, (value) => custom_73 = value); break; + case 74: InitializeExpression(key, () => custom_74, (value) => custom_74 = value); break; + case 75: InitializeExpression(key, () => custom_75, (value) => custom_75 = value); break; + case 76: InitializeExpression(key, () => custom_76, (value) => custom_76 = value); break; + case 77: InitializeExpression(key, () => custom_77, (value) => custom_77 = value); break; + case 78: InitializeExpression(key, () => custom_78, (value) => custom_78 = value); break; + case 79: InitializeExpression(key, () => custom_79, (value) => custom_79 = value); break; + + case 80: InitializeExpression(key, () => custom_80, (value) => custom_80 = value); break; + case 81: InitializeExpression(key, () => custom_81, (value) => custom_81 = value); break; + case 82: InitializeExpression(key, () => custom_82, (value) => custom_82 = value); break; + case 83: InitializeExpression(key, () => custom_83, (value) => custom_83 = value); break; + case 84: InitializeExpression(key, () => custom_84, (value) => custom_84 = value); break; + case 85: InitializeExpression(key, () => custom_85, (value) => custom_85 = value); break; + case 86: InitializeExpression(key, () => custom_86, (value) => custom_86 = value); break; + case 87: InitializeExpression(key, () => custom_87, (value) => custom_87 = value); break; + case 88: InitializeExpression(key, () => custom_88, (value) => custom_88 = value); break; + case 89: InitializeExpression(key, () => custom_89, (value) => custom_89 = value); break; + + case 90: InitializeExpression(key, () => custom_90, (value) => custom_90 = value); break; + case 91: InitializeExpression(key, () => custom_91, (value) => custom_91 = value); break; + case 92: InitializeExpression(key, () => custom_92, (value) => custom_92 = value); break; + case 93: InitializeExpression(key, () => custom_93, (value) => custom_93 = value); break; + case 94: InitializeExpression(key, () => custom_94, (value) => custom_94 = value); break; + case 95: InitializeExpression(key, () => custom_95, (value) => custom_95 = value); break; + case 96: InitializeExpression(key, () => custom_96, (value) => custom_96 = value); break; + case 97: InitializeExpression(key, () => custom_97, (value) => custom_97 = value); break; + case 98: InitializeExpression(key, () => custom_98, (value) => custom_98 = value); break; + case 99: InitializeExpression(key, () => custom_99, (value) => custom_99 = value); break; + } + break; + } + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs.meta b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs.meta new file mode 100644 index 000000000..81ed9bff9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 69dfb9ffd7c663f4cadc81e38a377672 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs new file mode 100644 index 000000000..2750d5271 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using UniGLTF; +using UniJSON; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + // + // extensions.VRMC_vrm_animation.extras.UNIVRM_pose + // + // no jsonscheme. + // + // extensions: { + // VRMC_vrm_animation: { + // humanoid : { + // humanBones: {} + // }, + // extras: { + // UNIVRM_pose: { + // humanoid: { + // translation: [ + // 0, + // 1, + // 0 + // ], + // rotations: { + // hips: [ + // 0, + // 0.707, + // 0, + // 0.707 + // ], + // spine: [ + // 0, + // 0.707, + // 0, + // 0.707 + // ], + // // ... + // } + // }, + // expressions: { + // preset: { + // happy: 1.0, + // }, + // }, + // lookAt: { + // position: [ + // 4, + // 5, + // 6 + // ], + // // yawPitchDegrees: [20, 30], + // } + // } + // } + // } + // } + public static class Vrm10PoseLoader + { + static Vector3 ToVec3(JsonNode j) + { + return new Vector3(-j[0].GetSingle(), j[1].GetSingle(), j[2].GetSingle()); + } + + static Quaternion ToQuat(JsonNode j) + { + return new Quaternion(j[0].GetSingle(), -j[1].GetSingle(), -j[2].GetSingle(), j[3].GetSingle()); + } + + static (Vector3, Dictionary) GetPose(JsonNode humanoid) + { + Vector3 root = default; + var map = new Dictionary(); + + if (humanoid.TryGet("translation", out var translation)) + { + root = ToVec3(translation); + } + if (humanoid.TryGet("rotations", out var rotations)) + { + foreach (var kv in rotations.ObjectItems()) + { + switch (kv.Key.GetString()) + { + case "hips": map.Add(HumanBodyBones.Hips, ToQuat(kv.Value)); break; + case "spine": map.Add(HumanBodyBones.Spine, ToQuat(kv.Value)); break; + case "chest": map.Add(HumanBodyBones.Chest, ToQuat(kv.Value)); break; + case "upperChest": map.Add(HumanBodyBones.UpperChest, ToQuat(kv.Value)); break; + case "neck": map.Add(HumanBodyBones.Neck, ToQuat(kv.Value)); break; + case "head": map.Add(HumanBodyBones.Head, ToQuat(kv.Value)); break; + // case "leftEye": map.Add(HumanBodyBones.leftEye, ToQuat(kv.Value)); break; + // case "rightEye": map.Add(HumanBodyBones.rightEye, ToQuat(kv.Value)); break; + case "jaw": map.Add(HumanBodyBones.Jaw, ToQuat(kv.Value)); break; + case "leftShoulder": map.Add(HumanBodyBones.LeftShoulder, ToQuat(kv.Value)); break; + case "leftUpperArm": map.Add(HumanBodyBones.LeftUpperArm, ToQuat(kv.Value)); break; + case "leftLowerArm": map.Add(HumanBodyBones.LeftLowerArm, ToQuat(kv.Value)); break; + case "leftHand": map.Add(HumanBodyBones.LeftHand, ToQuat(kv.Value)); break; + case "rightShoulder": map.Add(HumanBodyBones.RightShoulder, ToQuat(kv.Value)); break; + case "rightUpperArm": map.Add(HumanBodyBones.RightUpperArm, ToQuat(kv.Value)); break; + case "rightLowerArm": map.Add(HumanBodyBones.RightLowerArm, ToQuat(kv.Value)); break; + case "rightHand": map.Add(HumanBodyBones.RightHand, ToQuat(kv.Value)); break; + case "leftUpperLeg": map.Add(HumanBodyBones.LeftUpperLeg, ToQuat(kv.Value)); break; + case "leftLowerLeg": map.Add(HumanBodyBones.LeftLowerLeg, ToQuat(kv.Value)); break; + case "leftFoot": map.Add(HumanBodyBones.LeftFoot, ToQuat(kv.Value)); break; + case "leftToes": map.Add(HumanBodyBones.LeftToes, ToQuat(kv.Value)); break; + case "rightUpperLeg": map.Add(HumanBodyBones.RightUpperLeg, ToQuat(kv.Value)); break; + case "rightLowerLeg": map.Add(HumanBodyBones.RightLowerLeg, ToQuat(kv.Value)); break; + case "rightFoot": map.Add(HumanBodyBones.RightFoot, ToQuat(kv.Value)); break; + case "rightToes": map.Add(HumanBodyBones.RightToes, ToQuat(kv.Value)); break; + case "leftThumbMetacarpal": map.Add(HumanBodyBones.LeftThumbProximal, ToQuat(kv.Value)); break; + case "leftThumbProximal": map.Add(HumanBodyBones.LeftThumbIntermediate, ToQuat(kv.Value)); break; + case "leftThumbDistal": map.Add(HumanBodyBones.LeftThumbDistal, ToQuat(kv.Value)); break; + case "leftIndexProximal": map.Add(HumanBodyBones.LeftIndexProximal, ToQuat(kv.Value)); break; + case "leftIndexIntermediate": map.Add(HumanBodyBones.LeftIndexIntermediate, ToQuat(kv.Value)); break; + case "leftIndexDistal": map.Add(HumanBodyBones.LeftIndexDistal, ToQuat(kv.Value)); break; + case "leftMiddleProximal": map.Add(HumanBodyBones.LeftMiddleProximal, ToQuat(kv.Value)); break; + case "leftMiddleIntermediate": map.Add(HumanBodyBones.LeftMiddleIntermediate, ToQuat(kv.Value)); break; + case "leftMiddleDistal": map.Add(HumanBodyBones.LeftMiddleDistal, ToQuat(kv.Value)); break; + case "leftRingProximal": map.Add(HumanBodyBones.LeftRingProximal, ToQuat(kv.Value)); break; + case "leftRingIntermediate": map.Add(HumanBodyBones.LeftRingIntermediate, ToQuat(kv.Value)); break; + case "leftRingDistal": map.Add(HumanBodyBones.LeftRingDistal, ToQuat(kv.Value)); break; + case "leftLittleProximal": map.Add(HumanBodyBones.LeftLittleProximal, ToQuat(kv.Value)); break; + case "leftLittleIntermediate": map.Add(HumanBodyBones.LeftLittleIntermediate, ToQuat(kv.Value)); break; + case "leftLittleDistal": map.Add(HumanBodyBones.LeftLittleDistal, ToQuat(kv.Value)); break; + case "rightThumbMetacarpal": map.Add(HumanBodyBones.RightThumbProximal, ToQuat(kv.Value)); break; + case "rightThumbProximal": map.Add(HumanBodyBones.RightThumbIntermediate, ToQuat(kv.Value)); break; + case "rightThumbDistal": map.Add(HumanBodyBones.RightThumbDistal, ToQuat(kv.Value)); break; + case "rightIndexProximal": map.Add(HumanBodyBones.RightIndexProximal, ToQuat(kv.Value)); break; + case "rightIndexIntermediate": map.Add(HumanBodyBones.RightIndexIntermediate, ToQuat(kv.Value)); break; + case "rightIndexDistal": map.Add(HumanBodyBones.RightIndexDistal, ToQuat(kv.Value)); break; + case "rightMiddleProximal": map.Add(HumanBodyBones.RightMiddleProximal, ToQuat(kv.Value)); break; + case "rightMiddleIntermediate": map.Add(HumanBodyBones.RightMiddleIntermediate, ToQuat(kv.Value)); break; + case "rightMiddleDistal": map.Add(HumanBodyBones.RightMiddleDistal, ToQuat(kv.Value)); break; + case "rightRingProximal": map.Add(HumanBodyBones.RightRingProximal, ToQuat(kv.Value)); break; + case "rightRingIntermediate": map.Add(HumanBodyBones.RightRingIntermediate, ToQuat(kv.Value)); break; + case "rightRingDistal": map.Add(HumanBodyBones.RightRingDistal, ToQuat(kv.Value)); break; + case "rightLittleProximal": map.Add(HumanBodyBones.RightLittleProximal, ToQuat(kv.Value)); break; + case "rightLittleIntermediate": map.Add(HumanBodyBones.RightLittleIntermediate, ToQuat(kv.Value)); break; + case "rightLittleDistal": map.Add(HumanBodyBones.RightLittleDistal, ToQuat(kv.Value)); break; + } + } + } + + return (root, map); + } + + static void LoadHumanPose(Vrm10AnimationInstance instance, + UniJSON.JsonNode humanoid) + { + var (hips, map) = GetPose(humanoid); + + var animator = instance.GetComponent(); + + // update src ControlRig + animator.GetBoneTransform(HumanBodyBones.Hips).localPosition = hips; + + foreach (var kv in map) + { + var t = animator.GetBoneTransform(kv.Key); + if (t != null) + { + t.localRotation = kv.Value; + } + } + } + + static void LoadExpressions(Vrm10AnimationInstance instance, + UniJSON.JsonNode expressions) + { + if (expressions.TryGet("preset", out var preset)) + { + foreach (var kv in preset.ObjectItems()) + { + switch (kv.Key.GetString()) + { + case "happy": instance.preset_happy = kv.Value.GetSingle(); break; + case "angry": instance.preset_angry = kv.Value.GetSingle(); break; + case "sad": instance.preset_sad = kv.Value.GetSingle(); break; + case "relaxed": instance.preset_relaxed = kv.Value.GetSingle(); break; + case "surprised": instance.preset_surprised = kv.Value.GetSingle(); break; + case "aa": instance.preset_aa = kv.Value.GetSingle(); break; + case "ih": instance.preset_ih = kv.Value.GetSingle(); break; + case "ou": instance.preset_ou = kv.Value.GetSingle(); break; + case "ee": instance.preset_ee = kv.Value.GetSingle(); break; + case "oh": instance.preset_oh = kv.Value.GetSingle(); break; + case "blink": instance.preset_blink = kv.Value.GetSingle(); break; + case "blinkLeft": instance.preset_blinkleft = kv.Value.GetSingle(); break; + case "blinkRight": instance.preset_blinkright = kv.Value.GetSingle(); break; + // case "lookUp": instance.preset_lookUp = kv.Value.GetSingle(); break; + // case "lookDown": instance.preset_lookDown = kv.Value.GetSingle(); break; + // case "lookLeft": instance.preset_lookLeft = kv.Value.GetSingle(); break; + // case "lookRight": instance.preset_lookRight = kv.Value.GetSingle(); break; + case "neutral": instance.preset_neutral = kv.Value.GetSingle(); break; + } + } + } + if (expressions.TryGet("custom", out var custom)) + { + foreach (var kv in preset.ObjectItems()) + { + if (instance.ExpressionSetterMap.TryGetValue(ExpressionKey.CreateCustom(kv.Key.GetString()), out var setter)) + { + setter(kv.Key.GetSingle()); + } + } + } + } + + static void LoadLookAt(Vrm10AnimationInstance instance, + UniJSON.JsonNode lookAt) + { + if (lookAt.TryGet("position", out var position)) + { + // 注視点. 座標系? + } + } + + public static async Task LoadVrmAnimationPose(string text) + { + using GltfData data = GlbLowLevelParser.ParseGltf( + "tmp.vrma", + text, + new List(), // .gltf file has no chunks. + new FileSystemStorage("_dummy_root_"), // .gltf file has resource path at file system. + new MigrationFlags() + ); + using var loader = new VrmAnimationImporter(data); + var gltfInstance = await loader.LoadAsync(new ImmediateCaller()); + var instance = gltfInstance.GetComponent(); + + if (data.GLTF.extensions is UniGLTF.glTFExtensionImport extensions) + { + foreach (var kv in extensions.ObjectItems()) + { + if (kv.Key.GetString() == "VRMC_vrm_animation") + { + if (kv.Value.TryGet("extras", out var extras)) + { + if (extras.TryGet("UNIVRM_pose", out var pose)) + { + if (pose.TryGet("humanoid", out var humanoid)) + { + LoadHumanPose(instance, humanoid); + } + + if (extras.TryGet("expressions", out var expressions)) + { + LoadExpressions(instance, expressions); + } + + if (extras.TryGet("lookAt", out var lookAt)) + { + LoadLookAt(instance, lookAt); + } + } + } + } + } + } + + return instance; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs.meta b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs.meta new file mode 100644 index 000000000..2710da198 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e5c411775bed594e9698d805f06e710 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10TPose.cs b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10TPose.cs new file mode 100644 index 000000000..b4f2eef5f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10TPose.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using UniGLTF.Utils; +using UnityEngine; + +namespace UniVRM10 +{ + public class Vrm10TPose : IVrm10Animation + { + class NoRotation : INormalizedPoseProvider + { + readonly Vector3 m_hips; + + public NoRotation(Vector3 hips) + { + m_hips = hips; + } + + public Quaternion GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone) + { + return new Quaternion(0, 0, 0, 1); + } + + public Vector3 GetRawHipsPosition() + { + return m_hips; + } + } + + class Skeleton : ITPoseProvider + { + Vector3 m_hips; + public Skeleton(Vector3 hips) + { + m_hips = hips; + } + + public EuclideanTransform? GetWorldTransform(HumanBodyBones bone) + { + if (bone == HumanBodyBones.Hips) + { + return new EuclideanTransform(m_hips); + } + return default; + } + } + + public (INormalizedPoseProvider, ITPoseProvider) ControlRig { get; } + + public IReadOnlyDictionary> ExpressionMap { get; } + + public LookAtInput? LookAt { get; } + + public Vrm10TPose(Vector3 hips) + { + ControlRig = (new NoRotation(hips), new Skeleton(hips)); + ExpressionMap = new Dictionary>(); + LookAt = default; + } + + public void Dispose() + { + } + + public void ShowBoxMan(bool enable) + { + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10TPose.cs.meta b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10TPose.cs.meta new file mode 100644 index 000000000..82d7d6430 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10TPose.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 02b977ab7d273eb4881f3a4f9fc1fb1a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig.meta b/Assets/External/VRM10/Runtime/ControlRig.meta new file mode 100644 index 000000000..389dc424f --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2e8a3d812e744fb68c6469d96d57380d +timeCreated: 1662455048 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/ControlRig/AnimatorPoseProvider.cs b/Assets/External/VRM10/Runtime/ControlRig/AnimatorPoseProvider.cs new file mode 100644 index 000000000..5d570c36b --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/AnimatorPoseProvider.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using UniGLTF.Utils; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Animator から Pose 供給する。 + /// この Animator は以下の条件を満たすこと。 + /// + /// * TPoseであること + /// * 正規化済みであること + /// + /// + public sealed class AnimatorPoseProvider : INormalizedPoseProvider, ITPoseProvider + { + Transform m_root; + Animator m_animator; + Dictionary m_posMap = new Dictionary(); + + public AnimatorPoseProvider(Transform root, Animator animator) + { + m_root = root; + m_animator = animator; + + var hips = animator.GetBoneTransform(HumanBodyBones.Hips); + + foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) + { + if (bone == HumanBodyBones.LastBone) + { + continue; + } + var t = animator.GetBoneTransform(bone); + if (t != null) + { + m_posMap[bone] = new EuclideanTransform(root.worldToLocalMatrix * t.localToWorldMatrix); + } + } + } + + Quaternion INormalizedPoseProvider.GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone) + { + if (m_animator.GetBoneTransform(bone) is Transform t) + { + // TODO: parentBone relative + return t.localRotation; + } + else + { + // Debug.LogWarning($"{bone} not found"); + return Quaternion.identity; + } + } + + Vector3 INormalizedPoseProvider.GetRawHipsPosition() + { + // TODO: from model root ? + return m_animator.GetBoneTransform(HumanBodyBones.Hips).localPosition; + } + + EuclideanTransform? ITPoseProvider.GetWorldTransform(HumanBodyBones bone) + { + if (m_posMap.TryGetValue(bone, out var t)) + { + return t; + } + else + { + return default; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/ControlRig/AnimatorPoseProvider.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/AnimatorPoseProvider.cs.meta new file mode 100644 index 000000000..ae53d6441 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/AnimatorPoseProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77dc323422a0e59449bd822dac490495 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/BoneInitialRotation.cs b/Assets/External/VRM10/Runtime/ControlRig/BoneInitialRotation.cs new file mode 100644 index 000000000..d926be18b --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/BoneInitialRotation.cs @@ -0,0 +1,37 @@ +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Represents the rotation at the initial pose (TPose) + /// + public readonly struct BoneInitialRotation + { + public readonly Transform Transform; + + public readonly Vector3 InitialLocalPosition; + + public readonly Quaternion InitialLocalRotation; + + public readonly Quaternion InitialGlobalRotation; + + public BoneInitialRotation(Transform transform) + { + Transform = transform; + InitialLocalPosition = transform.localPosition; + InitialLocalRotation = transform.localRotation; + InitialGlobalRotation = transform.rotation; + } + + /// + /// Convert the local rotation, including the initial rotation, to a normalized local rotation + /// + public Quaternion NormalizedLocalRotation + { + get + { + return InitialGlobalRotation * Quaternion.Inverse(InitialLocalRotation) * Transform.localRotation * Quaternion.Inverse(InitialGlobalRotation); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/ControlRig/BoneInitialRotation.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/BoneInitialRotation.cs.meta new file mode 100644 index 000000000..dd0a4eec9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/BoneInitialRotation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: db1187bf0b13152439c8a145d9631916 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseApplicable.cs b/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseApplicable.cs new file mode 100644 index 000000000..30367b223 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseApplicable.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + public interface INormalizedPoseApplicable + { + void SetRawHipsPosition(Vector3 position); + + void SetNormalizedLocalRotation(HumanBodyBones bone, Quaternion normalizedLocalRotation); + } +} diff --git a/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseApplicable.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseApplicable.cs.meta new file mode 100644 index 000000000..8eee27ebc --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseApplicable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e200e64e4f18884d8a35bf9ce27cd4a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseProvider.cs b/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseProvider.cs new file mode 100644 index 000000000..a4b6b6b9c --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseProvider.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public interface INormalizedPoseProvider + { + /// + /// Get hips position in model root space + /// + Vector3 GetRawHipsPosition(); + + /// + /// Get normalized local rotation + /// + Quaternion GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone); + } +} diff --git a/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseProvider.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseProvider.cs.meta new file mode 100644 index 000000000..7169bd3ee --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/INormalizedPoseProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 624d9ba92e6c69b40abab8223e530d9e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/ITPoseProvider.cs b/Assets/External/VRM10/Runtime/ControlRig/ITPoseProvider.cs new file mode 100644 index 000000000..608f94424 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/ITPoseProvider.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using UniGLTF.Utils; +using UnityEngine; + +namespace UniVRM10 +{ + public interface ITPoseProvider + { + /// + /// TPose 時のモデルルートを基準とした、各ボーンの world 回転と位置を返す。 + /// 該当する bone が無いときは null。 + /// + /// 位置のスケーリングに使用するので hips は必ず値を返すこと。 + /// + EuclideanTransform? GetWorldTransform(HumanBodyBones bone); + } + + public static class ITPoseProviderExtensions + { + static HumanBodyBones GetParent(ITPoseProvider self, HumanBodyBones bone) + { + var current = bone; + // 無限ループ防止のため念のためカウンター付き + for (int i = 0; i < 100; ++i) + { + var vrmBone = Vrm10HumanoidBoneSpecification.ConvertFromUnityBone(current); + var def = Vrm10HumanoidBoneSpecification.GetDefine(vrmBone); + var parentBone = Vrm10HumanoidBoneSpecification.ConvertToUnityBone(def.ParentBone.Value); + if (self.GetWorldTransform(parentBone).HasValue) + { + return parentBone; + } + current = parentBone; + } + + // Hips 以外は必ず親ボーンが有るはずなのでここには来ない + throw new Exception("parent not found"); + } + + public static IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs(this ITPoseProvider self) + { + foreach (var bone in CachedEnum.GetValues()) + { + if (bone == HumanBodyBones.LastBone) + { + continue; + } + if (!self.GetWorldTransform(bone).HasValue) + { + continue; + } + + if (bone == HumanBodyBones.Hips) + { + yield return (bone, HumanBodyBones.LastBone); + } + else + { + yield return (bone, GetParent(self, bone)); + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/ControlRig/ITPoseProvider.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/ITPoseProvider.cs.meta new file mode 100644 index 000000000..16c14f4a1 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/ITPoseProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc1da1cfaa59c824295059dc6b1f22c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/InitialRotationPoseProvider.cs b/Assets/External/VRM10/Runtime/ControlRig/InitialRotationPoseProvider.cs new file mode 100644 index 000000000..eed24c030 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/InitialRotationPoseProvider.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using UniGLTF.Utils; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// VRM0TPose と異なる初期回転を持ったヒエラルキー + /// + /// - XR_EXT_hand_tracking + /// - XR_FB_body_tracking + /// - vrm-animation + /// + /// から VRM0TPose 互換の NormalizedLocalRotation(VRM0互換)を取り出す。 + /// BoneInitialRotation が値を計算できる。 + /// + public sealed class InitRotationPoseProvider : INormalizedPoseProvider, ITPoseProvider + { + Transform m_root; + Transform m_hips; + private readonly Dictionary m_bones = new Dictionary(); + private readonly Dictionary m_worldMap = new Dictionary(); + + public Vector3 HipTPoseWorldPosition => throw new System.NotImplementedException(); + + public InitRotationPoseProvider(Transform root, UniHumanoid.Humanoid humanoid) + { + m_root = root; + foreach (var (t, bone) in humanoid.BoneMap) + { + m_bones.Add(bone, new BoneInitialRotation(t)); + m_worldMap.Add(bone, new EuclideanTransform(root.localToWorldMatrix * t.localToWorldMatrix)); + } + m_hips = m_bones[HumanBodyBones.Hips].Transform; + } + + Quaternion INormalizedPoseProvider.GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone) + { + if (m_bones.TryGetValue(bone, out var c)) + { + return c.NormalizedLocalRotation; + } + else + { + // Debug.LogWarning($"${bone} not found"); + return Quaternion.identity; + } + } + + Vector3 INormalizedPoseProvider.GetRawHipsPosition() + { + if (m_hips.parent == m_root) + { + return m_hips.localPosition; + } + else + { + return m_root.worldToLocalMatrix.MultiplyPoint(m_hips.position); + } + } + + EuclideanTransform? ITPoseProvider.GetWorldTransform(HumanBodyBones bone) + { + if (m_worldMap.TryGetValue(bone, out var t)) + { + return t; + } + else + { + return default; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/ControlRig/InitialRotationPoseProvider.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/InitialRotationPoseProvider.cs.meta new file mode 100644 index 000000000..c3b1ac27e --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/InitialRotationPoseProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b21b9221f1a87564ea6dc5cf6037195a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/InitialRotations.meta b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations.meta new file mode 100644 index 000000000..990bb33f5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ebc9416609f7b734f87e487dfa0ae076 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_EXT_hand_tracking.cs b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_EXT_hand_tracking.cs new file mode 100644 index 000000000..fc08769c2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_EXT_hand_tracking.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// XR_EXT_hand_tracking の joint を VRM-1.0 の TPose に当てはめたときの方向を定義します。 + /// + /// * https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#_conventions_of_hand_joints + /// * https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/tpose.ja.md + /// + /// OpenXR は右手系なのに対して Unityは左手系です。 + /// この Rig が期待するボーンの値は、XR_EXT_hand_tracking の Joint の値を Z軸反転で座標変換したものです。 + /// + public static class XR_EXT_hand_tracking + { + /// + /// up vector と forward vector の外積により空間を算出して、回転を得ます。 + /// + /// + /// + /// + public static Quaternion GetRotation(Vector3 up, Vector3 forward) + { + var xAxis = Vector3.Cross(up, forward).normalized; + var m = new Matrix4x4(xAxis, up, forward, new Vector4(0, 0, 0, 1)); + return m.rotation; + } + + public static Quaternion LeftHand = GetRotation(Vector3.up, Vector3.left); + public static Quaternion RightHand = GetRotation(Vector3.up, Vector3.right); + + /// + /// 親指は XZ 平面45度です。 + /// + public static Quaternion LeftThumb = GetRotation((Vector3.forward + Vector3.right).normalized, (Vector3.left + Vector3.forward).normalized); + + /// + /// 親指は XZ 平面45度です。 + /// + public static Quaternion RightThumb = GetRotation((Vector3.forward + Vector3.left).normalized, (Vector3.right + Vector3.forward).normalized); + + /// + /// VRM-1.0 の T-Pose の定義から各指はX軸と並行です。親指はXZ平面に45度です。 + /// + public static IReadOnlyDictionary InitialRotations => new Dictionary() + { + // Left + {HumanBodyBones.LeftHand, LeftHand}, + {HumanBodyBones.LeftThumbProximal, LeftThumb}, + {HumanBodyBones.LeftThumbIntermediate, LeftThumb}, + {HumanBodyBones.LeftThumbDistal, LeftThumb}, + {HumanBodyBones.LeftIndexProximal, LeftHand}, + {HumanBodyBones.LeftIndexIntermediate, LeftHand}, + {HumanBodyBones.LeftIndexDistal, LeftHand}, + {HumanBodyBones.LeftMiddleProximal, LeftHand}, + {HumanBodyBones.LeftMiddleIntermediate, LeftHand}, + {HumanBodyBones.LeftMiddleDistal, LeftHand}, + {HumanBodyBones.LeftRingProximal, LeftHand}, + {HumanBodyBones.LeftRingIntermediate, LeftHand}, + {HumanBodyBones.LeftRingDistal, LeftHand}, + {HumanBodyBones.LeftLittleProximal, LeftHand}, + {HumanBodyBones.LeftLittleIntermediate, LeftHand}, + {HumanBodyBones.LeftLittleDistal, LeftHand}, + // Right + {HumanBodyBones.RightHand, RightHand}, + {HumanBodyBones.RightThumbProximal, RightThumb}, + {HumanBodyBones.RightThumbIntermediate, RightThumb}, + {HumanBodyBones.RightThumbDistal, RightThumb}, + {HumanBodyBones.RightIndexProximal, RightHand}, + {HumanBodyBones.RightIndexIntermediate, RightHand}, + {HumanBodyBones.RightIndexDistal, RightHand}, + {HumanBodyBones.RightMiddleProximal, RightHand}, + {HumanBodyBones.RightMiddleIntermediate, RightHand}, + {HumanBodyBones.RightMiddleDistal, RightHand}, + {HumanBodyBones.RightRingProximal, RightHand}, + {HumanBodyBones.RightRingIntermediate, RightHand}, + {HumanBodyBones.RightRingDistal, RightHand}, + {HumanBodyBones.RightLittleProximal, RightHand}, + {HumanBodyBones.RightLittleIntermediate, RightHand}, + {HumanBodyBones.RightLittleDistal, RightHand}, + }; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_EXT_hand_tracking.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_EXT_hand_tracking.cs.meta new file mode 100644 index 000000000..bd891171b --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_EXT_hand_tracking.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 551eba367636e4b45b222ce636a6adcf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_FB_body_tracking.cs b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_FB_body_tracking.cs new file mode 100644 index 000000000..296cee4e8 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_FB_body_tracking.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// XR_FB_body_tracking の joint を VRM-1.0 の TPose に当てはめたときの方向を定義します。 + /// + /// * https://developer.oculus.com/documentation/native/android/move-ref-body-joints/ + /// + /// OpenXR は右手系なのに対して Unityは左手系です。 + /// この Rig が期待するボーンの値は、XR_FB_body_tracking の Joint の値を Z軸反転で座標変換したものです。 + /// + public static class XR_FB_body_tracking + { + /// + /// up vector と forward vector の外積により空間を算出して、回転を得ます。 + /// + /// + /// + /// + public static Quaternion GetRotation(Vector3 yAxis, Vector3 zAxis) + { + var xAxis = Vector3.Cross(yAxis, zAxis).normalized; + var m = new Matrix4x4(xAxis, yAxis, zAxis, new Vector4(0, 0, 0, 1)); + return m.rotation; + } + + public static Quaternion Spine = GetRotation(Vector3.forward, Vector3.left); + + public static Quaternion Left = GetRotation(Vector3.forward, Vector3.down); + public static Quaternion LeftThumb = GetRotation((Vector3.left + Vector3.back).normalized, Vector3.up); + public static Quaternion LeftHand = GetRotation(Vector3.down, Vector3.back); + + public static Quaternion Right = GetRotation(Vector3.back, Vector3.up); + public static Quaternion RightThumb = GetRotation((Vector3.left + Vector3.forward).normalized, Vector3.down); + public static Quaternion RightHand = GetRotation(Vector3.up, Vector3.forward); + + public static IReadOnlyDictionary InitialRotations => new Dictionary() + { + {HumanBodyBones.Hips, Spine}, + {HumanBodyBones.Spine, Spine}, + {HumanBodyBones.Chest, Spine}, + {HumanBodyBones.UpperChest, Spine}, + {HumanBodyBones.Neck, Spine}, + {HumanBodyBones.Head, Spine}, + {HumanBodyBones.LeftShoulder, Left}, + {HumanBodyBones.LeftUpperArm, Left}, + {HumanBodyBones.LeftLowerArm, Left}, + {HumanBodyBones.RightShoulder, Right}, + {HumanBodyBones.RightUpperArm, Right}, + {HumanBodyBones.RightLowerArm, Right}, + // left + {HumanBodyBones.LeftHand, LeftHand}, + {HumanBodyBones.LeftThumbProximal, LeftThumb}, + {HumanBodyBones.LeftThumbIntermediate, LeftThumb}, + {HumanBodyBones.LeftThumbDistal, LeftThumb}, + {HumanBodyBones.LeftIndexProximal, LeftHand}, + {HumanBodyBones.LeftIndexIntermediate, LeftHand}, + {HumanBodyBones.LeftIndexDistal, LeftHand}, + {HumanBodyBones.LeftMiddleProximal, LeftHand}, + {HumanBodyBones.LeftMiddleIntermediate, LeftHand}, + {HumanBodyBones.LeftMiddleDistal, LeftHand}, + {HumanBodyBones.LeftRingProximal, LeftHand}, + {HumanBodyBones.LeftRingIntermediate, LeftHand}, + {HumanBodyBones.LeftRingDistal, LeftHand}, + {HumanBodyBones.LeftLittleProximal, LeftHand}, + {HumanBodyBones.LeftLittleIntermediate, LeftHand}, + {HumanBodyBones.LeftLittleDistal, LeftHand}, + // right + {HumanBodyBones.RightHand, RightHand}, + {HumanBodyBones.RightThumbProximal, RightThumb}, + {HumanBodyBones.RightThumbIntermediate, RightThumb}, + {HumanBodyBones.RightThumbDistal, RightThumb}, + {HumanBodyBones.RightIndexProximal, RightHand}, + {HumanBodyBones.RightIndexIntermediate, RightHand}, + {HumanBodyBones.RightIndexDistal, RightHand}, + {HumanBodyBones.RightMiddleProximal, RightHand}, + {HumanBodyBones.RightMiddleIntermediate, RightHand}, + {HumanBodyBones.RightMiddleDistal, RightHand}, + {HumanBodyBones.RightRingProximal, RightHand}, + {HumanBodyBones.RightRingIntermediate, RightHand}, + {HumanBodyBones.RightRingDistal, RightHand}, + {HumanBodyBones.RightLittleProximal, RightHand}, + {HumanBodyBones.RightLittleIntermediate, RightHand}, + {HumanBodyBones.RightLittleDistal, RightHand}, + }; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_FB_body_tracking.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_FB_body_tracking.cs.meta new file mode 100644 index 000000000..4e602f484 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/InitialRotations/XR_FB_body_tracking.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4e5ee6aa707a2044a9903133bbf085f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/ControlRig/Vrm10Retarget.cs b/Assets/External/VRM10/Runtime/ControlRig/Vrm10Retarget.cs new file mode 100644 index 000000000..53abe0bef --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/Vrm10Retarget.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public static class Vrm10Retarget + { + public static void Retarget((INormalizedPoseProvider Pose, ITPoseProvider TPose) source, (INormalizedPoseApplicable Pose, ITPoseProvider TPose) sink) + { + foreach (var (head, parent) in sink.TPose.EnumerateBoneParentPairs()) + { + var q = source.Pose.GetNormalizedLocalRotation(head, parent); + sink.Pose.SetNormalizedLocalRotation(head, q); + } + + // scaling hips position + var scaleRef = HumanBodyBones.Hips; + var scaling = sink.TPose.GetWorldTransform(scaleRef).Value.Translation.y / source.TPose.GetWorldTransform(scaleRef).Value.Translation.y; + var delta = source.Pose.GetRawHipsPosition() - source.TPose.GetWorldTransform(HumanBodyBones.Hips).Value.Translation; + sink.Pose.SetRawHipsPosition(sink.TPose.GetWorldTransform(HumanBodyBones.Hips).Value.Translation + delta * scaling); + } + + public static void EnforceTPose((INormalizedPoseApplicable Pose, ITPoseProvider TPose) sink) + { + foreach (var (bone, parent) in sink.TPose.EnumerateBoneParentPairs()) + { + sink.Pose.SetNormalizedLocalRotation(bone, Quaternion.identity); + } + + sink.Pose.SetRawHipsPosition(sink.TPose.GetWorldTransform(HumanBodyBones.Hips).Value.Translation); + } + } +} diff --git a/Assets/External/VRM10/Runtime/ControlRig/Vrm10Retarget.cs.meta b/Assets/External/VRM10/Runtime/ControlRig/Vrm10Retarget.cs.meta new file mode 100644 index 000000000..5ed531706 --- /dev/null +++ b/Assets/External/VRM10/Runtime/ControlRig/Vrm10Retarget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e44301f13c6a1e74ba0e5322262db259 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/EnumFlagsAttribute.cs b/Assets/External/VRM10/Runtime/EnumFlagsAttribute.cs new file mode 100644 index 000000000..698ab6e2c --- /dev/null +++ b/Assets/External/VRM10/Runtime/EnumFlagsAttribute.cs @@ -0,0 +1,8 @@ +using System; +using UnityEngine; + +namespace UniVRM10 +{ + [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)] + public sealed class EnumFlagsAttribute : PropertyAttribute { } +} diff --git a/Assets/External/VRM10/Runtime/EnumFlagsAttribute.cs.meta b/Assets/External/VRM10/Runtime/EnumFlagsAttribute.cs.meta new file mode 100644 index 000000000..3f89217c9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/EnumFlagsAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f3c3f9559a399143816d5eab6f0b4ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/FastSpringBone.meta b/Assets/External/VRM10/Runtime/FastSpringBone.meta new file mode 100644 index 000000000..f7e4648ad --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 197e77a1310790d4786b7d9adca918b6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables.meta new file mode 100644 index 000000000..45d059d0f --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e9d242d5eb124c341a1685fa016f73b7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs new file mode 100644 index 000000000..334887503 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs @@ -0,0 +1,19 @@ +using System; +using UnityEngine; +using UnityEngine.Serialization; + +namespace UniVRM10.FastSpringBones.Blittables +{ + /// + /// Blittableなコライダ + /// + [Serializable] + public struct BlittableCollider + { + public BlittableColliderType colliderType; + public Vector3 offset; + public float radius; + public Vector3 tail; + public int transformIndex; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs.meta new file mode 100644 index 000000000..22ed26aa2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 67352bbe9afc01940af2be44aa1416fc +timeCreated: 1550209189 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs new file mode 100644 index 000000000..04f0b9f25 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs @@ -0,0 +1,8 @@ +namespace UniVRM10.FastSpringBones.Blittables +{ + public enum BlittableColliderType + { + Sphere, + Capsule, + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs.meta new file mode 100644 index 000000000..715a2df22 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 27138554b75447d4b524f878abf0b107 +timeCreated: 1633081188 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableExternalData.cs b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableExternalData.cs new file mode 100644 index 000000000..f55dd5d97 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableExternalData.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +namespace UniVRM10.FastSpringBones.Blittables +{ + /// + /// 外力等の毎フレーム更新されうる外部から与えられる情報 + /// + public struct BlittableExternalData + { + public Vector3 ExternalForce; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableExternalData.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableExternalData.cs.meta new file mode 100644 index 000000000..173858d95 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableExternalData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a5066fc4e264010a58c19b781d477a0 +timeCreated: 1666166451 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableJoint.cs b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableJoint.cs new file mode 100644 index 000000000..3a670b0e0 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableJoint.cs @@ -0,0 +1,18 @@ +using System; +using UnityEngine; + +namespace UniVRM10.FastSpringBones.Blittables +{ + /// + /// SpringBoneの各関節を表すデータ型 + /// + [Serializable] + public struct BlittableJoint + { + public float stiffnessForce; + public float gravityPower; + public Vector3 gravityDir; + public float dragForce; + public float radius; + } +} diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableJoint.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableJoint.cs.meta new file mode 100644 index 000000000..de8b9f605 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableJoint.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8299788b0fbfe574397e8940e718f50f +timeCreated: 1549430605 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableLogic.cs b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableLogic.cs new file mode 100644 index 000000000..31397d8c7 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableLogic.cs @@ -0,0 +1,20 @@ +using System; +using UnityEngine; + +namespace UniVRM10.FastSpringBones.Blittables +{ + /// + /// SpringBoneの各関節に紐付いた計算情報を表すデータ型 + /// + [Serializable] + public struct BlittableLogic + { + public int parentTransformIndex; + public int headTransformIndex; + public float length; + public Vector3 currentTail; + public Vector3 prevTail; + public Quaternion localRotation; + public Vector3 boneAxis; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableLogic.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableLogic.cs.meta new file mode 100644 index 000000000..c317dbb9b --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableLogic.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e9731a165cdc47b5a6c9452cdab150a5 +timeCreated: 1633060275 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpan.cs b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpan.cs new file mode 100644 index 000000000..37a0f2962 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpan.cs @@ -0,0 +1,11 @@ +using System; + +namespace UniVRM10.FastSpringBones.Blittables +{ + [Serializable] + public struct BlittableSpan + { + public int startIndex; + public int count; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpan.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpan.cs.meta new file mode 100644 index 000000000..0a4f1b455 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpan.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 47daa1c068464f44987de43eba2210dc +timeCreated: 1633067618 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpring.cs b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpring.cs new file mode 100644 index 000000000..bd145fa04 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpring.cs @@ -0,0 +1,18 @@ +using System; + +namespace UniVRM10.FastSpringBones.Blittables +{ + /// + /// 1本の毛束を表すデータ型 + /// FastSpringBoneではこれを起点として並列化し、処理を行う + /// + [Serializable] + public struct BlittableSpring + { + public BlittableSpan colliderSpan; + public BlittableSpan logicSpan; + public int centerTransformIndex; + public int transformIndexOffset; + public unsafe BlittableExternalData* ExternalData; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpring.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpring.cs.meta new file mode 100644 index 000000000..5be432cd9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableSpring.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 30738bbbf18309448a80f7944ec2aef3 +timeCreated: 1549952425 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableTransform.cs b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableTransform.cs new file mode 100644 index 000000000..2c3745d34 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableTransform.cs @@ -0,0 +1,20 @@ +using System; +using UnityEngine; + +namespace UniVRM10.FastSpringBones.Blittables +{ + /// + /// Transformの必要な機能だけを絞り、Blittableに対応させたクラス + /// + [Serializable] + public struct BlittableTransform + { + public Vector3 position; + public Quaternion rotation; + public Vector3 localPosition; + public Quaternion localRotation; + public Vector3 localScale; + public Matrix4x4 localToWorldMatrix; + public Matrix4x4 worldToLocalMatrix; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableTransform.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableTransform.cs.meta new file mode 100644 index 000000000..f2b4e7fda --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/Blittables/BlittableTransform.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 95fac2f4af221054f99dbe868d26fc4b +timeCreated: 1550544819 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/FastSpringBone10.asmdef b/Assets/External/VRM10/Runtime/FastSpringBone/FastSpringBone10.asmdef new file mode 100644 index 000000000..70ab6d305 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/FastSpringBone10.asmdef @@ -0,0 +1,21 @@ +{ + "name": "FastSpringBone10", + "references": [ + "GUID:2665a8d13d1b3f18800f46e256720795" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.burst", + "expression": "0.0.1", + "define": "ENABLE_SPRINGBONE_BURST" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/FastSpringBone10.asmdef.meta b/Assets/External/VRM10/Runtime/FastSpringBone/FastSpringBone10.asmdef.meta new file mode 100644 index 000000000..3abaf0aae --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/FastSpringBone10.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f2ca1407928ebdc4bbe7765cc278be44 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts.meta b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts.meta new file mode 100644 index 000000000..b894d56db --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc529d8de129fe44ca6bfa94972f8951 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs new file mode 100644 index 000000000..c91391354 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using UnityEngine; +using UnityEngine.Profiling; +using UniVRM10.FastSpringBones.Blittables; + +namespace UniVRM10.FastSpringBones.System +{ + /// + /// ひとつのVRMに紐づくFastSpringBoneに関連したバッファを保持するクラス + /// + public class FastSpringBoneBuffer : IDisposable + { + // NOTE: これらはFastSpringBoneBufferCombinerによってバッチングされる + public NativeArray Springs { get; } + public NativeArray Joints { get; } + public NativeArray Colliders { get; } + public NativeArray Logics { get; } + public NativeArray BlittableTransforms { get; } + public Transform[] Transforms { get; } + public bool IsDisposed { get; private set; } + + // NOTE: これは更新頻度が高くバッチングが難しいため、ランダムアクセスを許容してメモリへ直接アクセスする + // 生のヒープ領域は扱いにくいので長さ1のNativeArrayで代用 + private NativeArray _externalData; + + public BlittableExternalData ExternalData + { + get => _externalData[0]; + set => _externalData[0] = value; + } + + public unsafe FastSpringBoneBuffer(IReadOnlyList springs, + BlittableExternalData externalData, + bool simulateLastBone = false) + { + Profiler.BeginSample("FastSpringBone.ConstructBuffers"); + + _externalData = new NativeArray(1, Allocator.Persistent); + ExternalData = externalData; + + // Transformの列挙 + Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructTransformBuffer"); + var transformHashSet = new HashSet(); + foreach (var spring in springs) + { + foreach (var joint in spring.joints) + { + transformHashSet.Add(joint.Transform); + if (joint.Transform.parent != null) transformHashSet.Add(joint.Transform.parent); + } + + foreach (var collider in spring.colliders) + { + transformHashSet.Add(collider.Transform); + } + + if (spring.center != null) transformHashSet.Add(spring.center); + } + + var transforms = transformHashSet.ToArray(); + var transformIndexDictionary = transforms.Select((trs, index) => (trs, index)) + .ToDictionary(tuple => tuple.trs, tuple => tuple.index); + Profiler.EndSample(); + + // 各種bufferの構築 + Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructBuffers"); + var blittableColliders = new List(); + var blittableJoints = new List(); + var blittableSprings = new List(); + var blittableLogics = new List(); + + foreach (var spring in springs) + { + var blittableSpring = new BlittableSpring + { + colliderSpan = new BlittableSpan + { + startIndex = blittableColliders.Count, + count = spring.colliders.Length, + }, + logicSpan = new BlittableSpan + { + startIndex = blittableJoints.Count, + count = simulateLastBone ? spring.joints.Length : spring.joints.Length - 1, + }, + centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1, + ExternalData = (BlittableExternalData*) _externalData.GetUnsafePtr() + }; + blittableSprings.Add(blittableSpring); + + blittableColliders.AddRange(spring.colliders.Select(collider => + { + var blittable = collider.Collider; + blittable.transformIndex = transformIndexDictionary[collider.Transform]; + return blittable; + })); + blittableJoints.AddRange(spring.joints + .Take(simulateLastBone ? spring.joints.Length : spring.joints.Length - 1).Select(joint => + { + var blittable = joint.Joint; + return blittable; + })); + + for (var i = 0; i < (simulateLastBone ? spring.joints.Length : spring.joints.Length - 1); ++i) + { + var joint = spring.joints[i]; + var tailJoint = i + 1 < spring.joints.Length ? spring.joints[i + 1] : (FastSpringBoneJoint?) null; + var parentJoint = i - 1 >= 0 ? spring.joints[i - 1] : (FastSpringBoneJoint?) null; + var localPosition = Vector3.zero; + if (tailJoint.HasValue) + { + localPosition = tailJoint.Value.Transform.localPosition; + } + else + { + if (parentJoint.HasValue) + { + var delta = joint.Transform.position - parentJoint.Value.Transform.position; + localPosition = + joint.Transform.worldToLocalMatrix.MultiplyPoint(joint.Transform.position + delta); + } + else + { + localPosition = Vector3.down; + } + } + + var scale = tailJoint.HasValue ? tailJoint.Value.Transform.lossyScale : joint.Transform.lossyScale; + var localChildPosition = + new Vector3( + localPosition.x * scale.x, + localPosition.y * scale.y, + localPosition.z * scale.z + ); + + var worldChildPosition = joint.Transform.TransformPoint(localChildPosition); + var currentTail = spring.center != null + ? spring.center.InverseTransformPoint(worldChildPosition) + : worldChildPosition; + var parent = joint.Transform.parent; + blittableLogics.Add(new BlittableLogic + { + headTransformIndex = transformIndexDictionary[joint.Transform], + parentTransformIndex = parent != null ? transformIndexDictionary[parent] : -1, + currentTail = currentTail, + prevTail = currentTail, + localRotation = joint.DefaultLocalRotation, + boneAxis = localChildPosition.normalized, + length = localChildPosition.magnitude + }); + } + } + + Profiler.EndSample(); + + // 各種bufferの初期化 + Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructNativeArrays"); + Springs = new NativeArray(blittableSprings.ToArray(), Allocator.Persistent); + + Joints = new NativeArray(blittableJoints.ToArray(), Allocator.Persistent); + Colliders = new NativeArray(blittableColliders.ToArray(), Allocator.Persistent); + Logics = new NativeArray(blittableLogics.ToArray(), Allocator.Persistent); + + BlittableTransforms = new NativeArray(transforms.Length, Allocator.Persistent); + Transforms = transforms.ToArray(); + Profiler.EndSample(); + + Profiler.EndSample(); + } + + public void Dispose() + { + if (IsDisposed) return; + IsDisposed = true; + Springs.Dispose(); + Joints.Dispose(); + BlittableTransforms.Dispose(); + Colliders.Dispose(); + Logics.Dispose(); + _externalData.Dispose(); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs.meta new file mode 100644 index 000000000..6dcc7fa2e --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 44fb3ab8e7b24e92ade483775da17002 +timeCreated: 1633487557 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneCollider.cs b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneCollider.cs new file mode 100644 index 000000000..b8386924c --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneCollider.cs @@ -0,0 +1,13 @@ +using System; +using UnityEngine; +using UniVRM10.FastSpringBones.Blittables; + +namespace UniVRM10.FastSpringBones.System +{ + [Serializable] + public struct FastSpringBoneCollider + { + public Transform Transform; + public BlittableCollider Collider; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneCollider.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneCollider.cs.meta new file mode 100644 index 000000000..8b31e8850 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneCollider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ffca416cb15a43239b73ed6067076458 +timeCreated: 1633066289 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneJoint.cs b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneJoint.cs new file mode 100644 index 000000000..98d1a8e65 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneJoint.cs @@ -0,0 +1,14 @@ +using System; +using UnityEngine; +using UniVRM10.FastSpringBones.Blittables; + +namespace UniVRM10.FastSpringBones.System +{ + [Serializable] + public struct FastSpringBoneJoint + { + public Transform Transform; + public BlittableJoint Joint; + public Quaternion DefaultLocalRotation; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneJoint.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneJoint.cs.meta new file mode 100644 index 000000000..d47bfbc18 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneJoint.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b6742aa2a6a34bd395add629c17ab952 +timeCreated: 1633066253 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneSpring.cs b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneSpring.cs new file mode 100644 index 000000000..6be893391 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneSpring.cs @@ -0,0 +1,13 @@ +using System; +using UnityEngine; + +namespace UniVRM10.FastSpringBones.System +{ + [Serializable] + public struct FastSpringBoneSpring + { + public Transform center; + public FastSpringBoneJoint[] joints; + public FastSpringBoneCollider[] colliders; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneSpring.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneSpring.cs.meta new file mode 100644 index 000000000..ea46ccb63 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneSpring.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e0a972985499416e8e95acdf16fae6ba +timeCreated: 1633066412 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System.meta b/Assets/External/VRM10/Runtime/FastSpringBone/System.meta new file mode 100644 index 000000000..47ac6e8e5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af417d77d895bc84ba5d2c8f0542bdd8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/CopyToNativeArrayTransformJob.cs b/Assets/External/VRM10/Runtime/FastSpringBone/System/CopyToNativeArrayTransformJob.cs new file mode 100644 index 000000000..d31ec3326 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/CopyToNativeArrayTransformJob.cs @@ -0,0 +1,33 @@ +using Unity.Collections; +using UnityEngine.Jobs; +using UniVRM10.FastSpringBones.Blittables; +#if ENABLE_SPRINGBONE_BURST +using Unity.Burst; +#endif + +namespace UniVRM10.FastSpringBones.System +{ + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + public struct PullTransformJob : IJobParallelForTransform + { + [WriteOnly] public NativeArray Transforms; + + public void Execute(int index, TransformAccess transform) + { + Transforms[index] = new BlittableTransform + { + position = transform.position, + rotation = transform.rotation, + localPosition = transform.localPosition, + localRotation = transform.localRotation, + localScale = transform.localScale, + localToWorldMatrix = transform.localToWorldMatrix, + worldToLocalMatrix = transform.worldToLocalMatrix + }; + } + } +} + \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/CopyToNativeArrayTransformJob.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/System/CopyToNativeArrayTransformJob.cs.meta new file mode 100644 index 000000000..78bdc82fe --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/CopyToNativeArrayTransformJob.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b9fd53b4431b41909c1b1d882a2d446b +timeCreated: 1633072084 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs new file mode 100644 index 000000000..ce2fb53a0 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs @@ -0,0 +1,289 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.Collections; +using Unity.Jobs; +using UnityEngine; +using UnityEngine.Jobs; +using UnityEngine.Profiling; +using UniVRM10.FastSpringBones.Blittables; +#if ENABLE_SPRINGBONE_BURST +using Unity.Burst; +#endif + +namespace UniVRM10.FastSpringBones.System +{ + /// + /// FastSpringBoneの処理に利用するバッファを全て結合して持つクラス + /// + public sealed class FastSpringBoneBufferCombiner : IDisposable + { + private NativeArray _springs; + private NativeArray _transforms; + private NativeArray _colliders; + private NativeArray _joints; + private NativeArray _logics; + private TransformAccessArray _transformAccessArray; + + private readonly LinkedList _buffers = new LinkedList(); + private FastSpringBoneBuffer[] _batchedBuffers; + private int[] _batchedBufferLogicSizes; + + private bool _isDirty; + + public NativeArray Springs => _springs; + public NativeArray Joints => _joints; + public NativeArray Transforms => _transforms; + public TransformAccessArray TransformAccessArray => _transformAccessArray; + public NativeArray Colliders => _colliders; + public NativeArray Logics => _logics; + + public bool HasBuffer => _batchedBuffers != null && _batchedBuffers.Length > 0; + + public void Register(FastSpringBoneBuffer buffer) + { + _buffers.AddLast(buffer); + _isDirty = true; + } + + public void Unregister(FastSpringBoneBuffer buffer) + { + _buffers.Remove(buffer); + _isDirty = true; + } + + /// + /// 変更があったならばバッファを再構築する + /// + public JobHandle ReconstructIfDirty(JobHandle handle) + { + if (_isDirty) + { + var result = ReconstructBuffers(handle); + _isDirty = false; + return result; + } + + return handle; + } + + /// + /// バッチングされたバッファから、個々のバッファへと値を戻す + /// バッファの再構築前にこの処理を行わないと、揺れの状態がリセットされてしまい、不自然な挙動になる + /// + private void SaveToSourceBuffer() + { + if (_batchedBuffers == null) return; + + var logicsIndex = 0; + for (var i = 0; i < _batchedBuffers.Length; ++i) + { + var length = _batchedBufferLogicSizes[i]; + if (!_batchedBuffers[i].IsDisposed && length > 0) + { + NativeArray.Copy(_logics, logicsIndex, _batchedBuffers[i].Logics, 0, length); + } + + logicsIndex += length; + } + } + + /// + /// バッファを再構築する + /// + private JobHandle ReconstructBuffers(JobHandle handle) + { + Profiler.BeginSample("FastSpringBone.ReconstructBuffers"); + + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.SaveToSourceBuffer"); + SaveToSourceBuffer(); + Profiler.EndSample(); + + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.DisposeBuffers"); + DisposeAllBuffers(); + Profiler.EndSample(); + + var springsCount = 0; + var collidersCount = 0; + var logicsCount = 0; + var transformsCount = 0; + + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CopyToBatchedBuffers"); + _batchedBuffers = _buffers.ToArray(); + _batchedBufferLogicSizes = _batchedBuffers.Select(buffer => buffer.Logics.Length).ToArray(); + Profiler.EndSample(); + + // バッファを数える + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CountBufferSize"); + foreach (var buffer in _buffers) + { + springsCount += buffer.Springs.Length; + collidersCount += buffer.Colliders.Length; + logicsCount += buffer.Logics.Length; + transformsCount += buffer.BlittableTransforms.Length; + } + + Profiler.EndSample(); + + // バッファの構築 + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CreateBuffers"); + _springs = new NativeArray(springsCount, Allocator.Persistent); + + _joints = new NativeArray(logicsCount, Allocator.Persistent); + _logics = new NativeArray(logicsCount, Allocator.Persistent); + _colliders = new NativeArray(collidersCount, Allocator.Persistent); + + _transforms = new NativeArray(transformsCount, Allocator.Persistent); + Profiler.EndSample(); + + var springsOffset = 0; + var collidersOffset = 0; + var logicsOffset = 0; + var transformOffset = 0; + + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.ScheduleLoadBufferJobs"); + for (var i = 0; i < _batchedBuffers.Length; i++) + { + var buffer = _batchedBuffers[i]; + + // バッファの読み込みをスケジュール + handle = new LoadTransformsJob + { + SrcTransforms = buffer.BlittableTransforms, + DestTransforms = + new NativeSlice(_transforms, transformOffset, + buffer.BlittableTransforms.Length) + }.Schedule(buffer.BlittableTransforms.Length, 1, handle); + handle = new LoadSpringsJob + { + SrcSprings = buffer.Springs, + DestSprings = new NativeSlice(_springs, springsOffset, buffer.Springs.Length), + CollidersOffset = collidersOffset, + LogicsOffset = logicsOffset, + TransformOffset = transformOffset, + }.Schedule(buffer.Springs.Length, 1, handle); + handle = new LoadCollidersJob + { + SrcColliders = buffer.Colliders, + DestColliders = + new NativeSlice(_colliders, collidersOffset, buffer.Colliders.Length) + }.Schedule(buffer.Colliders.Length, 1, handle); + handle = new OffsetLogicsJob + { + SrcLogics = buffer.Logics, + SrcJoints = buffer.Joints, + DestLogics = new NativeSlice(_logics, logicsOffset, buffer.Logics.Length), + DestJoints = new NativeSlice(_joints, logicsOffset, buffer.Logics.Length), + }.Schedule(buffer.Logics.Length, 1, handle); + + springsOffset += buffer.Springs.Length; + collidersOffset += buffer.Colliders.Length; + logicsOffset += buffer.Logics.Length; + transformOffset += buffer.BlittableTransforms.Length; + } + + // TransformAccessArrayの構築と並行してJobを行うため、この時点で走らせておく + JobHandle.ScheduleBatchedJobs(); + Profiler.EndSample(); + + // TransformAccessArrayの構築 + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.LoadTransformAccessArray"); + var transforms = new Transform[transformsCount]; + var transformAccessArrayOffset = 0; + foreach (var buffer in _batchedBuffers) + { + Array.Copy(buffer.Transforms, 0, transforms, transformAccessArrayOffset, buffer.Transforms.Length); + transformAccessArrayOffset += buffer.BlittableTransforms.Length; + } + + _transformAccessArray = new TransformAccessArray(transforms); + Profiler.EndSample(); + + Profiler.EndSample(); + + return handle; + } + + private void DisposeAllBuffers() + { + if (_springs.IsCreated) _springs.Dispose(); + if (_joints.IsCreated) _joints.Dispose(); + if (_transforms.IsCreated) _transforms.Dispose(); + if (_transformAccessArray.isCreated) _transformAccessArray.Dispose(); + if (_colliders.IsCreated) _colliders.Dispose(); + if (_logics.IsCreated) _logics.Dispose(); + } + + public void Dispose() + { + DisposeAllBuffers(); + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct LoadTransformsJob : IJobParallelFor + { + [ReadOnly] public NativeArray SrcTransforms; + [WriteOnly] public NativeSlice DestTransforms; + + public void Execute(int index) + { + DestTransforms[index] = SrcTransforms[index]; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct LoadSpringsJob : IJobParallelFor + { + [ReadOnly] public NativeArray SrcSprings; + [WriteOnly] public NativeSlice DestSprings; + + public int CollidersOffset; + public int LogicsOffset; + public int TransformOffset; + + public void Execute(int index) + { + var spring = SrcSprings[index]; + spring.colliderSpan.startIndex += CollidersOffset; + spring.logicSpan.startIndex += LogicsOffset; + spring.transformIndexOffset = TransformOffset; + DestSprings[index] = spring; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct LoadCollidersJob : IJobParallelFor + { + [ReadOnly] public NativeArray SrcColliders; + [WriteOnly] public NativeSlice DestColliders; + + public void Execute(int index) + { + DestColliders[index] = SrcColliders[index]; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct OffsetLogicsJob : IJobParallelFor + { + [ReadOnly] public NativeSlice SrcLogics; + [ReadOnly] public NativeSlice SrcJoints; + [WriteOnly] public NativeSlice DestLogics; + [WriteOnly] public NativeSlice DestJoints; + + public void Execute(int index) + { + DestLogics[index] = SrcLogics[index]; + DestJoints[index] = SrcJoints[index]; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs.meta new file mode 100644 index 000000000..ce9f4ec5a --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2b0299bf5bfe431e8e18a9b033b719a3 +timeCreated: 1633072502 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneScheduler.cs b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneScheduler.cs new file mode 100644 index 000000000..f3adb0bad --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneScheduler.cs @@ -0,0 +1,53 @@ +using System; +using Unity.Jobs; +using UnityEngine; +using UnityEngine.Jobs; + +namespace UniVRM10.FastSpringBones.System +{ + public sealed class FastSpringBoneScheduler : IDisposable + { + private readonly FastSpringBoneBufferCombiner _bufferCombiner; + public FastSpringBoneScheduler(FastSpringBoneBufferCombiner bufferCombiner) + { + _bufferCombiner = bufferCombiner; + } + + public JobHandle Schedule(float deltaTime) + { + var handle = default(JobHandle); + handle = _bufferCombiner.ReconstructIfDirty(handle); + if (!_bufferCombiner.HasBuffer) + { + return handle; + } + + handle = new PullTransformJob + { + Transforms = _bufferCombiner.Transforms + }.Schedule(_bufferCombiner.TransformAccessArray, handle); + + handle = new UpdateFastSpringBoneJob + { + Colliders = _bufferCombiner.Colliders, + Joints = _bufferCombiner.Joints, + Logics = _bufferCombiner.Logics, + Springs = _bufferCombiner.Springs, + Transforms = _bufferCombiner.Transforms, + DeltaTime = deltaTime, + }.Schedule(_bufferCombiner.Springs.Length, 1, handle); + + handle = new PushTransformJob + { + Transforms = _bufferCombiner.Transforms + }.Schedule(_bufferCombiner.TransformAccessArray, handle); + + return handle; + } + + public void Dispose() + { + _bufferCombiner.Dispose(); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneScheduler.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneScheduler.cs.meta new file mode 100644 index 000000000..3ebe6c1c4 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 897b4e814c0b5dc4d8d1f8a859ef746b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneService.cs b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneService.cs new file mode 100644 index 000000000..d33caa111 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneService.cs @@ -0,0 +1,101 @@ +using UnityEngine; + +namespace UniVRM10.FastSpringBones.System +{ + [DefaultExecutionOrder(11010)] + /// + /// VRM-1.0 ではコンポーネントの処理順が規定されている + /// + /// 1. ヒューマノイドボーンを解決 + /// 2. 頭の位置が決まるのでLookAtを解決 + /// 3. ExpressionUpdate + /// 4. コンストレイントを解決 + /// 5. SpringBoneを解決 + /// + /// 1~4 は Vrm10Runtime が管理し LateUpdate で処理される。 + /// このクラスは DefaultExecutionOrder(11000) によりその後ろにまわる。 + /// + /// # [Manual update] + /// + /// foreach(var vrmInstance in allVrm) + /// { + /// vrmInstance.UpdateType = None; + /// vrmInstance.Runtime.Process(); + /// } + /// FastSpringBoneService.Instance.UpdateType = Manual; + /// FastSpringBoneService.Instance.ManualUpdate(); + /// + /// + public sealed class FastSpringBoneService : MonoBehaviour + { + public enum UpdateTypes + { + Manual, + LateUpdate, + } + + [SerializeField, Header("Runtime")] + public UpdateTypes UpdateType = UpdateTypes.LateUpdate; + + + public FastSpringBoneBufferCombiner BufferCombiner { get; private set; } + private FastSpringBoneScheduler _fastSpringBoneScheduler; + + private static FastSpringBoneService _instance; + + public static FastSpringBoneService Instance + { + get + { + if (_instance) return _instance; + + _instance = FindObjectOfType(); + if (_instance) return _instance; + + var gameObject = new GameObject("FastSpringBone Service"); + DontDestroyOnLoad(gameObject); + _instance = gameObject.AddComponent(); + + return _instance; + } + } + + /// + /// 専有しているインスタンスを破棄する + /// + public static void Free() + { + Destroy(_instance.gameObject); + _instance = null; + } + + private void OnEnable() + { + BufferCombiner = new FastSpringBoneBufferCombiner(); + _fastSpringBoneScheduler = new FastSpringBoneScheduler(BufferCombiner); + } + + private void OnDisable() + { + BufferCombiner.Dispose(); + _fastSpringBoneScheduler.Dispose(); + } + + private void LateUpdate() + { + if (UpdateType == UpdateTypes.LateUpdate) + { + _fastSpringBoneScheduler.Schedule(Time.deltaTime).Complete(); + } + } + + public void ManualUpdate(float deltaTime) + { + if (UpdateType != UpdateTypes.Manual) + { + throw new global::System.ArgumentException("require UpdateTypes.Manual"); + } + _fastSpringBoneScheduler.Schedule(deltaTime).Complete(); + } + } +} diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneService.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneService.cs.meta new file mode 100644 index 000000000..4742756cb --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/FastSpringBoneService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4539bdbd058c41738f5eba86dba51e96 +timeCreated: 1633339379 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/PushTransformJob.cs b/Assets/External/VRM10/Runtime/FastSpringBone/System/PushTransformJob.cs new file mode 100644 index 000000000..cc19b6fa2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/PushTransformJob.cs @@ -0,0 +1,23 @@ +using Unity.Collections; +using UnityEngine.Jobs; +using UniVRM10.FastSpringBones.Blittables; +#if ENABLE_SPRINGBONE_BURST +using Unity.Burst; +#endif + +namespace UniVRM10.FastSpringBones.System +{ +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + public struct PushTransformJob : IJobParallelForTransform + { + [ReadOnly] + public NativeArray Transforms; + + public void Execute(int index, TransformAccess transform) + { + transform.rotation = Transforms[index].rotation; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/PushTransformJob.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/System/PushTransformJob.cs.meta new file mode 100644 index 000000000..dea0f1598 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/PushTransformJob.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fd0a0bfba0ec4bc6b050527b92d4decf +timeCreated: 1633075989 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs b/Assets/External/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs new file mode 100644 index 000000000..8da06bef0 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs @@ -0,0 +1,200 @@ +using System; +using Unity.Collections; +using Unity.Jobs; +using UnityEngine; +using UniVRM10.FastSpringBones.Blittables; +#if ENABLE_SPRINGBONE_BURST +using Unity.Burst; +#endif + +namespace UniVRM10.FastSpringBones.System +{ +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + public struct UpdateFastSpringBoneJob : IJobParallelFor + { + [ReadOnly] public NativeArray Springs; + [ReadOnly] public NativeArray Joints; + [ReadOnly] public NativeArray Colliders; + + [NativeDisableParallelForRestriction] public NativeArray Logics; + [NativeDisableParallelForRestriction] public NativeArray Transforms; + + public float DeltaTime; + + public unsafe void Execute(int index) + { + var spring = Springs[index]; + var transformIndexOffset = spring.transformIndexOffset; + var colliderSpan = spring.colliderSpan; + var logicSpan = spring.logicSpan; + + for (var logicIndex = logicSpan.startIndex; logicIndex < logicSpan.startIndex + logicSpan.count; ++logicIndex) + { + var logic = Logics[logicIndex]; + var joint = Joints[logicIndex]; + + var headTransform = Transforms[logic.headTransformIndex + transformIndexOffset]; + var parentTransform = logic.parentTransformIndex >= 0 + ? Transforms[logic.parentTransformIndex + transformIndexOffset] + : (BlittableTransform?)null; + var centerTransform = spring.centerTransformIndex >= 0 + ? Transforms[spring.centerTransformIndex + transformIndexOffset] + : (BlittableTransform?)null; + + // 親があったら、親に依存するTransformを再計算 + if (parentTransform.HasValue) + { + headTransform.position = + parentTransform.Value.localToWorldMatrix.MultiplyPoint3x4(headTransform.localPosition); + headTransform.rotation = parentTransform.Value.rotation * headTransform.localRotation; + } + + var currentTail = centerTransform.HasValue + ? centerTransform.Value.localToWorldMatrix.MultiplyPoint3x4(logic.currentTail) + : logic.currentTail; + var prevTail = centerTransform.HasValue + ? centerTransform.Value.localToWorldMatrix.MultiplyPoint3x4(logic.prevTail) + : logic.prevTail; + + var parentRotation = parentTransform?.rotation ?? Quaternion.identity; + + // verlet積分で次の位置を計算 + var external = (joint.gravityDir * joint.gravityPower + spring.ExternalData->ExternalForce) * DeltaTime; + var nextTail = currentTail + + (currentTail - prevTail) * (1.0f - joint.dragForce) // 前フレームの移動を継続する(減衰もあるよ) + + parentRotation * logic.localRotation * logic.boneAxis * + joint.stiffnessForce * DeltaTime // 親の回転による子ボーンの移動目標 + + external; // 外力による移動量 + + // 長さをboneLengthに強制 + nextTail = headTransform.position + (nextTail - headTransform.position).normalized * logic.length; + + // Collisionで移動 + for (var colliderIndex = colliderSpan.startIndex; colliderIndex < colliderSpan.startIndex + colliderSpan.count; ++colliderIndex) + { + var collider = Colliders[colliderIndex]; + var colliderTransform = Transforms[collider.transformIndex + transformIndexOffset]; + var colliderScale = colliderTransform.localToWorldMatrix.lossyScale; + var maxColliderScale = Mathf.Max(Mathf.Max(Mathf.Abs(colliderScale.x), Mathf.Abs(colliderScale.y)), Mathf.Abs(colliderScale.z)); + var worldPosition = colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.offset); + var worldTail = colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.tail); + + switch (collider.colliderType) + { + case BlittableColliderType.Sphere: + ResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + break; + case BlittableColliderType.Capsule: + ResolveCapsuleCollision(worldTail, worldPosition, headTransform, joint, collider, maxColliderScale, logic, ref nextTail); + break; + } + } + + logic.prevTail = centerTransform.HasValue + ? centerTransform.Value.worldToLocalMatrix.MultiplyPoint3x4(currentTail) + : currentTail; + logic.currentTail = centerTransform.HasValue + ? centerTransform.Value.worldToLocalMatrix.MultiplyPoint3x4(nextTail) + : nextTail; + + + //回転を適用 + var rotation = parentRotation * logic.localRotation; + headTransform.rotation = Quaternion.FromToRotation(rotation * logic.boneAxis, + nextTail - headTransform.position) * rotation; + + // Transformを更新 + if (parentTransform.HasValue) + { + var parentLocalToWorldMatrix = parentTransform.Value.localToWorldMatrix; + headTransform.localRotation = Normalize(Quaternion.Inverse(parentTransform.Value.rotation) * headTransform.rotation); + headTransform.localToWorldMatrix = + parentLocalToWorldMatrix * + Matrix4x4.TRS( + headTransform.localPosition, + headTransform.localRotation, + headTransform.localScale + ); + headTransform.worldToLocalMatrix = headTransform.localToWorldMatrix.inverse; + } + else + { + headTransform.localToWorldMatrix = + Matrix4x4.TRS( + headTransform.position, + headTransform.rotation, + headTransform.localScale + ); + headTransform.worldToLocalMatrix = headTransform.localToWorldMatrix.inverse; + headTransform.localRotation = headTransform.rotation; + } + + // 値をバッファに戻す + Transforms[logic.headTransformIndex + transformIndexOffset] = headTransform; + Logics[logicIndex] = logic; + } + } + + /// + /// BurstではMathfがエラーを吐くため、内部でMathfを呼ばないNormalizeを自前実装 + /// + private static Quaternion Normalize(Quaternion q) + { + var num = (float)Math.Sqrt(Quaternion.Dot(q, q)); + return num < float.Epsilon ? Quaternion.identity : new Quaternion(q.x / num, q.y / num, q.z / num, q.w / num); + } + + private static void ResolveCapsuleCollision( + Vector3 worldTail, + Vector3 worldPosition, + BlittableTransform headTransform, + BlittableJoint joint, + BlittableCollider collider, + float maxColliderScale, + BlittableLogic logic, + ref Vector3 nextTail) + { + var P = (worldTail - worldPosition).normalized; + var Q = headTransform.position - worldPosition; + var dot = Vector3.Dot(P, Q); + if (dot <= 0) + { + // head側半球の球判定 + ResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + } + + var t = dot / P.magnitude; + if (t >= 1.0f) + { + // tail側半球の球判定 + ResolveSphereCollision(joint, collider, worldTail, headTransform, maxColliderScale, logic, ref nextTail); + } + + // head-tail上の m_transform.position との最近点 + var p = worldPosition + P * t; + ResolveSphereCollision(joint, collider, p, headTransform, maxColliderScale, logic, ref nextTail); + } + + private static void ResolveSphereCollision( + BlittableJoint joint, + BlittableCollider collider, + Vector3 worldPosition, + BlittableTransform headTransform, + float maxColliderScale, + BlittableLogic logic, + ref Vector3 nextTail) + { + var r = joint.radius + collider.radius * maxColliderScale; + if (Vector3.SqrMagnitude(nextTail - worldPosition) <= (r * r)) + { + // ヒット。Colliderの半径方向に押し出す + var normal = (nextTail - worldPosition).normalized; + var posFromCollider = worldPosition + normal * r; + // 長さをboneLengthに強制 + nextTail = headTransform.position + (posFromCollider - headTransform.position).normalized * logic.length; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs.meta b/Assets/External/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs.meta new file mode 100644 index 000000000..c74d73f74 --- /dev/null +++ b/Assets/External/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 30ca968f0008470da9418cd48832709e +timeCreated: 1633077901 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Format.meta b/Assets/External/VRM10/Runtime/Format.meta new file mode 100644 index 000000000..33ae33272 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 94f2f5e159af11947ac84f4a2fff8aca +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Animation.meta b/Assets/External/VRM10/Runtime/Format/Animation.meta new file mode 100644 index 000000000..4503b5bf7 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Animation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d15d1d42c630e94faaf48208777a17a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Animation/Deserializer.g.cs b/Assets/External/VRM10/Runtime/Format/Animation/Deserializer.g.cs new file mode 100644 index 000000000..d74221b5b --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Animation/Deserializer.g.cs @@ -0,0 +1,2504 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using UniJSON; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF.Extensions.VRMC_vrm_animation { + +public static class GltfDeserializer +{ + public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_vrm_animation.ExtensionName); + +public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_vrm_animation extension) +{ + if(src is UniGLTF.glTFExtensionImport extensions) + { + foreach(var kv in extensions.ObjectItems()) + { + if(kv.Key.GetUtf8String() == ExtensionNameUtf8) + { + extension = Deserialize(kv.Value); + return true; + } + } + } + + extension = default; + return false; +} + + +public static VRMC_vrm_animation Deserialize(JsonNode parsed) +{ + var value = new VRMC_vrm_animation(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="specVersion"){ + value.SpecVersion = kv.Value.GetString(); + continue; + } + + if(key=="humanoid"){ + value.Humanoid = Deserialize_Humanoid(kv.Value); + continue; + } + + if(key=="expressions"){ + value.Expressions = Deserialize_Expressions(kv.Value); + continue; + } + + if(key=="lookAt"){ + value.LookAt = Deserialize_LookAt(kv.Value); + continue; + } + + } + return value; +} + +public static Humanoid Deserialize_Humanoid(JsonNode parsed) +{ + var value = new Humanoid(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="humanBones"){ + value.HumanBones = __humanoid_Deserialize_HumanBones(kv.Value); + continue; + } + + } + return value; +} + +public static HumanBones __humanoid_Deserialize_HumanBones(JsonNode parsed) +{ + var value = new HumanBones(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="hips"){ + value.Hips = __humanoid__humanBones_Deserialize_Hips(kv.Value); + continue; + } + + if(key=="spine"){ + value.Spine = __humanoid__humanBones_Deserialize_Spine(kv.Value); + continue; + } + + if(key=="chest"){ + value.Chest = __humanoid__humanBones_Deserialize_Chest(kv.Value); + continue; + } + + if(key=="upperChest"){ + value.UpperChest = __humanoid__humanBones_Deserialize_UpperChest(kv.Value); + continue; + } + + if(key=="neck"){ + value.Neck = __humanoid__humanBones_Deserialize_Neck(kv.Value); + continue; + } + + if(key=="head"){ + value.Head = __humanoid__humanBones_Deserialize_Head(kv.Value); + continue; + } + + if(key=="jaw"){ + value.Jaw = __humanoid__humanBones_Deserialize_Jaw(kv.Value); + continue; + } + + if(key=="leftUpperLeg"){ + value.LeftUpperLeg = __humanoid__humanBones_Deserialize_LeftUpperLeg(kv.Value); + continue; + } + + if(key=="leftLowerLeg"){ + value.LeftLowerLeg = __humanoid__humanBones_Deserialize_LeftLowerLeg(kv.Value); + continue; + } + + if(key=="leftFoot"){ + value.LeftFoot = __humanoid__humanBones_Deserialize_LeftFoot(kv.Value); + continue; + } + + if(key=="leftToes"){ + value.LeftToes = __humanoid__humanBones_Deserialize_LeftToes(kv.Value); + continue; + } + + if(key=="rightUpperLeg"){ + value.RightUpperLeg = __humanoid__humanBones_Deserialize_RightUpperLeg(kv.Value); + continue; + } + + if(key=="rightLowerLeg"){ + value.RightLowerLeg = __humanoid__humanBones_Deserialize_RightLowerLeg(kv.Value); + continue; + } + + if(key=="rightFoot"){ + value.RightFoot = __humanoid__humanBones_Deserialize_RightFoot(kv.Value); + continue; + } + + if(key=="rightToes"){ + value.RightToes = __humanoid__humanBones_Deserialize_RightToes(kv.Value); + continue; + } + + if(key=="leftShoulder"){ + value.LeftShoulder = __humanoid__humanBones_Deserialize_LeftShoulder(kv.Value); + continue; + } + + if(key=="leftUpperArm"){ + value.LeftUpperArm = __humanoid__humanBones_Deserialize_LeftUpperArm(kv.Value); + continue; + } + + if(key=="leftLowerArm"){ + value.LeftLowerArm = __humanoid__humanBones_Deserialize_LeftLowerArm(kv.Value); + continue; + } + + if(key=="leftHand"){ + value.LeftHand = __humanoid__humanBones_Deserialize_LeftHand(kv.Value); + continue; + } + + if(key=="rightShoulder"){ + value.RightShoulder = __humanoid__humanBones_Deserialize_RightShoulder(kv.Value); + continue; + } + + if(key=="rightUpperArm"){ + value.RightUpperArm = __humanoid__humanBones_Deserialize_RightUpperArm(kv.Value); + continue; + } + + if(key=="rightLowerArm"){ + value.RightLowerArm = __humanoid__humanBones_Deserialize_RightLowerArm(kv.Value); + continue; + } + + if(key=="rightHand"){ + value.RightHand = __humanoid__humanBones_Deserialize_RightHand(kv.Value); + continue; + } + + if(key=="leftThumbMetacarpal"){ + value.LeftThumbMetacarpal = __humanoid__humanBones_Deserialize_LeftThumbMetacarpal(kv.Value); + continue; + } + + if(key=="leftThumbProximal"){ + value.LeftThumbProximal = __humanoid__humanBones_Deserialize_LeftThumbProximal(kv.Value); + continue; + } + + if(key=="leftThumbDistal"){ + value.LeftThumbDistal = __humanoid__humanBones_Deserialize_LeftThumbDistal(kv.Value); + continue; + } + + if(key=="leftIndexProximal"){ + value.LeftIndexProximal = __humanoid__humanBones_Deserialize_LeftIndexProximal(kv.Value); + continue; + } + + if(key=="leftIndexIntermediate"){ + value.LeftIndexIntermediate = __humanoid__humanBones_Deserialize_LeftIndexIntermediate(kv.Value); + continue; + } + + if(key=="leftIndexDistal"){ + value.LeftIndexDistal = __humanoid__humanBones_Deserialize_LeftIndexDistal(kv.Value); + continue; + } + + if(key=="leftMiddleProximal"){ + value.LeftMiddleProximal = __humanoid__humanBones_Deserialize_LeftMiddleProximal(kv.Value); + continue; + } + + if(key=="leftMiddleIntermediate"){ + value.LeftMiddleIntermediate = __humanoid__humanBones_Deserialize_LeftMiddleIntermediate(kv.Value); + continue; + } + + if(key=="leftMiddleDistal"){ + value.LeftMiddleDistal = __humanoid__humanBones_Deserialize_LeftMiddleDistal(kv.Value); + continue; + } + + if(key=="leftRingProximal"){ + value.LeftRingProximal = __humanoid__humanBones_Deserialize_LeftRingProximal(kv.Value); + continue; + } + + if(key=="leftRingIntermediate"){ + value.LeftRingIntermediate = __humanoid__humanBones_Deserialize_LeftRingIntermediate(kv.Value); + continue; + } + + if(key=="leftRingDistal"){ + value.LeftRingDistal = __humanoid__humanBones_Deserialize_LeftRingDistal(kv.Value); + continue; + } + + if(key=="leftLittleProximal"){ + value.LeftLittleProximal = __humanoid__humanBones_Deserialize_LeftLittleProximal(kv.Value); + continue; + } + + if(key=="leftLittleIntermediate"){ + value.LeftLittleIntermediate = __humanoid__humanBones_Deserialize_LeftLittleIntermediate(kv.Value); + continue; + } + + if(key=="leftLittleDistal"){ + value.LeftLittleDistal = __humanoid__humanBones_Deserialize_LeftLittleDistal(kv.Value); + continue; + } + + if(key=="rightThumbMetacarpal"){ + value.RightThumbMetacarpal = __humanoid__humanBones_Deserialize_RightThumbMetacarpal(kv.Value); + continue; + } + + if(key=="rightThumbProximal"){ + value.RightThumbProximal = __humanoid__humanBones_Deserialize_RightThumbProximal(kv.Value); + continue; + } + + if(key=="rightThumbDistal"){ + value.RightThumbDistal = __humanoid__humanBones_Deserialize_RightThumbDistal(kv.Value); + continue; + } + + if(key=="rightIndexProximal"){ + value.RightIndexProximal = __humanoid__humanBones_Deserialize_RightIndexProximal(kv.Value); + continue; + } + + if(key=="rightIndexIntermediate"){ + value.RightIndexIntermediate = __humanoid__humanBones_Deserialize_RightIndexIntermediate(kv.Value); + continue; + } + + if(key=="rightIndexDistal"){ + value.RightIndexDistal = __humanoid__humanBones_Deserialize_RightIndexDistal(kv.Value); + continue; + } + + if(key=="rightMiddleProximal"){ + value.RightMiddleProximal = __humanoid__humanBones_Deserialize_RightMiddleProximal(kv.Value); + continue; + } + + if(key=="rightMiddleIntermediate"){ + value.RightMiddleIntermediate = __humanoid__humanBones_Deserialize_RightMiddleIntermediate(kv.Value); + continue; + } + + if(key=="rightMiddleDistal"){ + value.RightMiddleDistal = __humanoid__humanBones_Deserialize_RightMiddleDistal(kv.Value); + continue; + } + + if(key=="rightRingProximal"){ + value.RightRingProximal = __humanoid__humanBones_Deserialize_RightRingProximal(kv.Value); + continue; + } + + if(key=="rightRingIntermediate"){ + value.RightRingIntermediate = __humanoid__humanBones_Deserialize_RightRingIntermediate(kv.Value); + continue; + } + + if(key=="rightRingDistal"){ + value.RightRingDistal = __humanoid__humanBones_Deserialize_RightRingDistal(kv.Value); + continue; + } + + if(key=="rightLittleProximal"){ + value.RightLittleProximal = __humanoid__humanBones_Deserialize_RightLittleProximal(kv.Value); + continue; + } + + if(key=="rightLittleIntermediate"){ + value.RightLittleIntermediate = __humanoid__humanBones_Deserialize_RightLittleIntermediate(kv.Value); + continue; + } + + if(key=="rightLittleDistal"){ + value.RightLittleDistal = __humanoid__humanBones_Deserialize_RightLittleDistal(kv.Value); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Hips(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Spine(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Chest(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_UpperChest(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Neck(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Head(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Jaw(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftUpperLeg(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLowerLeg(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftFoot(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftToes(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightUpperLeg(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLowerLeg(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightFoot(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightToes(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftShoulder(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftUpperArm(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLowerArm(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftHand(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightShoulder(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightUpperArm(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLowerArm(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightHand(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftThumbMetacarpal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftThumbProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftThumbDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftIndexProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftIndexIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftIndexDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftMiddleProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftMiddleIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftMiddleDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftRingProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftRingIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftRingDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLittleProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLittleIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLittleDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightThumbMetacarpal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightThumbProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightThumbDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightIndexProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightIndexIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightIndexDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightMiddleProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightMiddleIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightMiddleDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightRingProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightRingIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightRingDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLittleProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLittleIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLittleDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expressions Deserialize_Expressions(JsonNode parsed) +{ + var value = new Expressions(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="preset"){ + value.Preset = __expressions_Deserialize_Preset(kv.Value); + continue; + } + + if(key=="custom"){ + value.Custom = __expressions_Deserialize_Custom(kv.Value); + continue; + } + + } + return value; +} + +public static Preset __expressions_Deserialize_Preset(JsonNode parsed) +{ + var value = new Preset(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="happy"){ + value.Happy = __expressions__preset_Deserialize_Happy(kv.Value); + continue; + } + + if(key=="angry"){ + value.Angry = __expressions__preset_Deserialize_Angry(kv.Value); + continue; + } + + if(key=="sad"){ + value.Sad = __expressions__preset_Deserialize_Sad(kv.Value); + continue; + } + + if(key=="relaxed"){ + value.Relaxed = __expressions__preset_Deserialize_Relaxed(kv.Value); + continue; + } + + if(key=="surprised"){ + value.Surprised = __expressions__preset_Deserialize_Surprised(kv.Value); + continue; + } + + if(key=="aa"){ + value.Aa = __expressions__preset_Deserialize_Aa(kv.Value); + continue; + } + + if(key=="ih"){ + value.Ih = __expressions__preset_Deserialize_Ih(kv.Value); + continue; + } + + if(key=="ou"){ + value.Ou = __expressions__preset_Deserialize_Ou(kv.Value); + continue; + } + + if(key=="ee"){ + value.Ee = __expressions__preset_Deserialize_Ee(kv.Value); + continue; + } + + if(key=="oh"){ + value.Oh = __expressions__preset_Deserialize_Oh(kv.Value); + continue; + } + + if(key=="blink"){ + value.Blink = __expressions__preset_Deserialize_Blink(kv.Value); + continue; + } + + if(key=="blinkLeft"){ + value.BlinkLeft = __expressions__preset_Deserialize_BlinkLeft(kv.Value); + continue; + } + + if(key=="blinkRight"){ + value.BlinkRight = __expressions__preset_Deserialize_BlinkRight(kv.Value); + continue; + } + + if(key=="lookUp"){ + value.LookUp = __expressions__preset_Deserialize_LookUp(kv.Value); + continue; + } + + if(key=="lookDown"){ + value.LookDown = __expressions__preset_Deserialize_LookDown(kv.Value); + continue; + } + + if(key=="lookLeft"){ + value.LookLeft = __expressions__preset_Deserialize_LookLeft(kv.Value); + continue; + } + + if(key=="lookRight"){ + value.LookRight = __expressions__preset_Deserialize_LookRight(kv.Value); + continue; + } + + if(key=="neutral"){ + value.Neutral = __expressions__preset_Deserialize_Neutral(kv.Value); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Happy(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Angry(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Sad(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Relaxed(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Surprised(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Aa(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Ih(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Ou(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Ee(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Oh(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Blink(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_BlinkLeft(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_BlinkRight(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_LookUp(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_LookDown(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_LookLeft(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_LookRight(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Neutral(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static Dictionary __expressions_Deserialize_Custom(JsonNode parsed) +{ + var value = new Dictionary(); + foreach(var kv in parsed.ObjectItems()) + { + value.Add(kv.Key.GetString(), __expressions_Deserialize_Custom_ITEM(kv.Value)); + } + return value; +} + +public static Expression __expressions_Deserialize_Custom_ITEM(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static LookAt Deserialize_LookAt(JsonNode parsed) +{ + var value = new LookAt(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +} // GltfDeserializer +} // UniGLTF diff --git a/Assets/External/VRM10/Runtime/Format/Animation/Deserializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Animation/Deserializer.g.cs.meta new file mode 100644 index 000000000..f86f0263b --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Animation/Deserializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4496eacf38a3897479cfb145617739ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Animation/Format.g.cs b/Assets/External/VRM10/Runtime/Format/Animation/Format.g.cs new file mode 100644 index 000000000..df697d818 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Animation/Format.g.cs @@ -0,0 +1,319 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; + + +namespace UniGLTF.Extensions.VRMC_vrm_animation +{ + + public class HumanBone + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Represents a single glTF node mapped to this humanBone. + public int? Node; + } + + public class HumanBones + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Represents a single bone of a Humanoid. + public HumanBone Hips; + + // Represents a single bone of a Humanoid. + public HumanBone Spine; + + // Represents a single bone of a Humanoid. + public HumanBone Chest; + + // Represents a single bone of a Humanoid. + public HumanBone UpperChest; + + // Represents a single bone of a Humanoid. + public HumanBone Neck; + + // Represents a single bone of a Humanoid. + public HumanBone Head; + + // Represents a single bone of a Humanoid. + public HumanBone Jaw; + + // Represents a single bone of a Humanoid. + public HumanBone LeftUpperLeg; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLowerLeg; + + // Represents a single bone of a Humanoid. + public HumanBone LeftFoot; + + // Represents a single bone of a Humanoid. + public HumanBone LeftToes; + + // Represents a single bone of a Humanoid. + public HumanBone RightUpperLeg; + + // Represents a single bone of a Humanoid. + public HumanBone RightLowerLeg; + + // Represents a single bone of a Humanoid. + public HumanBone RightFoot; + + // Represents a single bone of a Humanoid. + public HumanBone RightToes; + + // Represents a single bone of a Humanoid. + public HumanBone LeftShoulder; + + // Represents a single bone of a Humanoid. + public HumanBone LeftUpperArm; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLowerArm; + + // Represents a single bone of a Humanoid. + public HumanBone LeftHand; + + // Represents a single bone of a Humanoid. + public HumanBone RightShoulder; + + // Represents a single bone of a Humanoid. + public HumanBone RightUpperArm; + + // Represents a single bone of a Humanoid. + public HumanBone RightLowerArm; + + // Represents a single bone of a Humanoid. + public HumanBone RightHand; + + // Represents a single bone of a Humanoid. + public HumanBone LeftThumbMetacarpal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftThumbProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftThumbDistal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftIndexProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftIndexIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone LeftIndexDistal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftMiddleProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftMiddleIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone LeftMiddleDistal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftRingProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftRingIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone LeftRingDistal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLittleProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLittleIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLittleDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightThumbMetacarpal; + + // Represents a single bone of a Humanoid. + public HumanBone RightThumbProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightThumbDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightIndexProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightIndexIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone RightIndexDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightMiddleProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightMiddleIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone RightMiddleDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightRingProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightRingIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone RightRingDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightLittleProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightLittleIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone RightLittleDistal; + } + + public class Humanoid + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // An object which maps humanoid bones to nodes. + public HumanBones HumanBones; + } + + public class Expression + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Represents a single glTF node mapped to this expression. + public int? Node; + } + + public class Preset + { + // Represents a single expression. + public Expression Happy; + + // Represents a single expression. + public Expression Angry; + + // Represents a single expression. + public Expression Sad; + + // Represents a single expression. + public Expression Relaxed; + + // Represents a single expression. + public Expression Surprised; + + // Represents a single expression. + public Expression Aa; + + // Represents a single expression. + public Expression Ih; + + // Represents a single expression. + public Expression Ou; + + // Represents a single expression. + public Expression Ee; + + // Represents a single expression. + public Expression Oh; + + // Represents a single expression. + public Expression Blink; + + // Represents a single expression. + public Expression BlinkLeft; + + // Represents a single expression. + public Expression BlinkRight; + + // Represents a single expression. + public Expression LookUp; + + // Represents a single expression. + public Expression LookDown; + + // Represents a single expression. + public Expression LookLeft; + + // Represents a single expression. + public Expression LookRight; + + // Represents a single expression. + public Expression Neutral; + } + + public class Expressions + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // An object that contains definitions of preset expressions. + public Preset Preset; + + // An object that contains definitions of custom expressions. + public Dictionary Custom; + } + + public class LookAt + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Represents a single glTF node represents the eye gaze point. + public int? Node; + } + + public class VRMC_vrm_animation + { + public const string ExtensionName = "VRMC_vrm_animation"; + + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Specification version of VRMC_vrm_animation + public string SpecVersion; + + // An object which describes about humanoid bones. + public Humanoid Humanoid; + + // An object which maps expressions to nodes. + public Expressions Expressions; + + // An object which maps a eye gaze point to a node. + public LookAt LookAt; + } +} diff --git a/Assets/External/VRM10/Runtime/Format/Animation/Format.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Animation/Format.g.cs.meta new file mode 100644 index 000000000..9e67b39b4 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Animation/Format.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f595db5658d457449b2fa63cfdc29c6d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Animation/Serializer.g.cs b/Assets/External/VRM10/Runtime/Format/Animation/Serializer.g.cs new file mode 100644 index 000000000..d27bd05a6 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Animation/Serializer.g.cs @@ -0,0 +1,2194 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; +using System.Linq; +using UniJSON; + +namespace UniGLTF.Extensions.VRMC_vrm_animation { + + static public class GltfSerializer + { + + public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_vrm_animation extension) + { + if (dst is glTFExtensionImport) + { + throw new NotImplementedException(); + } + + if (!(dst is glTFExtensionExport extensions)) + { + extensions = new glTFExtensionExport(); + dst = extensions; + } + + var f = new JsonFormatter(); + Serialize(f, extension); + extensions.Add(VRMC_vrm_animation.ExtensionName, f.GetStoreBytes()); + } + + +public static void Serialize(JsonFormatter f, VRMC_vrm_animation value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.SpecVersion)){ + f.Key("specVersion"); + f.Value(value.SpecVersion); + } + + if(value.Humanoid!=null){ + f.Key("humanoid"); + Serialize_Humanoid(f, value.Humanoid); + } + + if(value.Expressions!=null){ + f.Key("expressions"); + Serialize_Expressions(f, value.Expressions); + } + + if(value.LookAt!=null){ + f.Key("lookAt"); + Serialize_LookAt(f, value.LookAt); + } + + f.EndMap(); +} + +public static void Serialize_Humanoid(JsonFormatter f, Humanoid value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.HumanBones!=null){ + f.Key("humanBones"); + __humanoid_Serialize_HumanBones(f, value.HumanBones); + } + + f.EndMap(); +} + +public static void __humanoid_Serialize_HumanBones(JsonFormatter f, HumanBones value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Hips!=null){ + f.Key("hips"); + __humanoid__humanBones_Serialize_Hips(f, value.Hips); + } + + if(value.Spine!=null){ + f.Key("spine"); + __humanoid__humanBones_Serialize_Spine(f, value.Spine); + } + + if(value.Chest!=null){ + f.Key("chest"); + __humanoid__humanBones_Serialize_Chest(f, value.Chest); + } + + if(value.UpperChest!=null){ + f.Key("upperChest"); + __humanoid__humanBones_Serialize_UpperChest(f, value.UpperChest); + } + + if(value.Neck!=null){ + f.Key("neck"); + __humanoid__humanBones_Serialize_Neck(f, value.Neck); + } + + if(value.Head!=null){ + f.Key("head"); + __humanoid__humanBones_Serialize_Head(f, value.Head); + } + + if(value.Jaw!=null){ + f.Key("jaw"); + __humanoid__humanBones_Serialize_Jaw(f, value.Jaw); + } + + if(value.LeftUpperLeg!=null){ + f.Key("leftUpperLeg"); + __humanoid__humanBones_Serialize_LeftUpperLeg(f, value.LeftUpperLeg); + } + + if(value.LeftLowerLeg!=null){ + f.Key("leftLowerLeg"); + __humanoid__humanBones_Serialize_LeftLowerLeg(f, value.LeftLowerLeg); + } + + if(value.LeftFoot!=null){ + f.Key("leftFoot"); + __humanoid__humanBones_Serialize_LeftFoot(f, value.LeftFoot); + } + + if(value.LeftToes!=null){ + f.Key("leftToes"); + __humanoid__humanBones_Serialize_LeftToes(f, value.LeftToes); + } + + if(value.RightUpperLeg!=null){ + f.Key("rightUpperLeg"); + __humanoid__humanBones_Serialize_RightUpperLeg(f, value.RightUpperLeg); + } + + if(value.RightLowerLeg!=null){ + f.Key("rightLowerLeg"); + __humanoid__humanBones_Serialize_RightLowerLeg(f, value.RightLowerLeg); + } + + if(value.RightFoot!=null){ + f.Key("rightFoot"); + __humanoid__humanBones_Serialize_RightFoot(f, value.RightFoot); + } + + if(value.RightToes!=null){ + f.Key("rightToes"); + __humanoid__humanBones_Serialize_RightToes(f, value.RightToes); + } + + if(value.LeftShoulder!=null){ + f.Key("leftShoulder"); + __humanoid__humanBones_Serialize_LeftShoulder(f, value.LeftShoulder); + } + + if(value.LeftUpperArm!=null){ + f.Key("leftUpperArm"); + __humanoid__humanBones_Serialize_LeftUpperArm(f, value.LeftUpperArm); + } + + if(value.LeftLowerArm!=null){ + f.Key("leftLowerArm"); + __humanoid__humanBones_Serialize_LeftLowerArm(f, value.LeftLowerArm); + } + + if(value.LeftHand!=null){ + f.Key("leftHand"); + __humanoid__humanBones_Serialize_LeftHand(f, value.LeftHand); + } + + if(value.RightShoulder!=null){ + f.Key("rightShoulder"); + __humanoid__humanBones_Serialize_RightShoulder(f, value.RightShoulder); + } + + if(value.RightUpperArm!=null){ + f.Key("rightUpperArm"); + __humanoid__humanBones_Serialize_RightUpperArm(f, value.RightUpperArm); + } + + if(value.RightLowerArm!=null){ + f.Key("rightLowerArm"); + __humanoid__humanBones_Serialize_RightLowerArm(f, value.RightLowerArm); + } + + if(value.RightHand!=null){ + f.Key("rightHand"); + __humanoid__humanBones_Serialize_RightHand(f, value.RightHand); + } + + if(value.LeftThumbMetacarpal!=null){ + f.Key("leftThumbMetacarpal"); + __humanoid__humanBones_Serialize_LeftThumbMetacarpal(f, value.LeftThumbMetacarpal); + } + + if(value.LeftThumbProximal!=null){ + f.Key("leftThumbProximal"); + __humanoid__humanBones_Serialize_LeftThumbProximal(f, value.LeftThumbProximal); + } + + if(value.LeftThumbDistal!=null){ + f.Key("leftThumbDistal"); + __humanoid__humanBones_Serialize_LeftThumbDistal(f, value.LeftThumbDistal); + } + + if(value.LeftIndexProximal!=null){ + f.Key("leftIndexProximal"); + __humanoid__humanBones_Serialize_LeftIndexProximal(f, value.LeftIndexProximal); + } + + if(value.LeftIndexIntermediate!=null){ + f.Key("leftIndexIntermediate"); + __humanoid__humanBones_Serialize_LeftIndexIntermediate(f, value.LeftIndexIntermediate); + } + + if(value.LeftIndexDistal!=null){ + f.Key("leftIndexDistal"); + __humanoid__humanBones_Serialize_LeftIndexDistal(f, value.LeftIndexDistal); + } + + if(value.LeftMiddleProximal!=null){ + f.Key("leftMiddleProximal"); + __humanoid__humanBones_Serialize_LeftMiddleProximal(f, value.LeftMiddleProximal); + } + + if(value.LeftMiddleIntermediate!=null){ + f.Key("leftMiddleIntermediate"); + __humanoid__humanBones_Serialize_LeftMiddleIntermediate(f, value.LeftMiddleIntermediate); + } + + if(value.LeftMiddleDistal!=null){ + f.Key("leftMiddleDistal"); + __humanoid__humanBones_Serialize_LeftMiddleDistal(f, value.LeftMiddleDistal); + } + + if(value.LeftRingProximal!=null){ + f.Key("leftRingProximal"); + __humanoid__humanBones_Serialize_LeftRingProximal(f, value.LeftRingProximal); + } + + if(value.LeftRingIntermediate!=null){ + f.Key("leftRingIntermediate"); + __humanoid__humanBones_Serialize_LeftRingIntermediate(f, value.LeftRingIntermediate); + } + + if(value.LeftRingDistal!=null){ + f.Key("leftRingDistal"); + __humanoid__humanBones_Serialize_LeftRingDistal(f, value.LeftRingDistal); + } + + if(value.LeftLittleProximal!=null){ + f.Key("leftLittleProximal"); + __humanoid__humanBones_Serialize_LeftLittleProximal(f, value.LeftLittleProximal); + } + + if(value.LeftLittleIntermediate!=null){ + f.Key("leftLittleIntermediate"); + __humanoid__humanBones_Serialize_LeftLittleIntermediate(f, value.LeftLittleIntermediate); + } + + if(value.LeftLittleDistal!=null){ + f.Key("leftLittleDistal"); + __humanoid__humanBones_Serialize_LeftLittleDistal(f, value.LeftLittleDistal); + } + + if(value.RightThumbMetacarpal!=null){ + f.Key("rightThumbMetacarpal"); + __humanoid__humanBones_Serialize_RightThumbMetacarpal(f, value.RightThumbMetacarpal); + } + + if(value.RightThumbProximal!=null){ + f.Key("rightThumbProximal"); + __humanoid__humanBones_Serialize_RightThumbProximal(f, value.RightThumbProximal); + } + + if(value.RightThumbDistal!=null){ + f.Key("rightThumbDistal"); + __humanoid__humanBones_Serialize_RightThumbDistal(f, value.RightThumbDistal); + } + + if(value.RightIndexProximal!=null){ + f.Key("rightIndexProximal"); + __humanoid__humanBones_Serialize_RightIndexProximal(f, value.RightIndexProximal); + } + + if(value.RightIndexIntermediate!=null){ + f.Key("rightIndexIntermediate"); + __humanoid__humanBones_Serialize_RightIndexIntermediate(f, value.RightIndexIntermediate); + } + + if(value.RightIndexDistal!=null){ + f.Key("rightIndexDistal"); + __humanoid__humanBones_Serialize_RightIndexDistal(f, value.RightIndexDistal); + } + + if(value.RightMiddleProximal!=null){ + f.Key("rightMiddleProximal"); + __humanoid__humanBones_Serialize_RightMiddleProximal(f, value.RightMiddleProximal); + } + + if(value.RightMiddleIntermediate!=null){ + f.Key("rightMiddleIntermediate"); + __humanoid__humanBones_Serialize_RightMiddleIntermediate(f, value.RightMiddleIntermediate); + } + + if(value.RightMiddleDistal!=null){ + f.Key("rightMiddleDistal"); + __humanoid__humanBones_Serialize_RightMiddleDistal(f, value.RightMiddleDistal); + } + + if(value.RightRingProximal!=null){ + f.Key("rightRingProximal"); + __humanoid__humanBones_Serialize_RightRingProximal(f, value.RightRingProximal); + } + + if(value.RightRingIntermediate!=null){ + f.Key("rightRingIntermediate"); + __humanoid__humanBones_Serialize_RightRingIntermediate(f, value.RightRingIntermediate); + } + + if(value.RightRingDistal!=null){ + f.Key("rightRingDistal"); + __humanoid__humanBones_Serialize_RightRingDistal(f, value.RightRingDistal); + } + + if(value.RightLittleProximal!=null){ + f.Key("rightLittleProximal"); + __humanoid__humanBones_Serialize_RightLittleProximal(f, value.RightLittleProximal); + } + + if(value.RightLittleIntermediate!=null){ + f.Key("rightLittleIntermediate"); + __humanoid__humanBones_Serialize_RightLittleIntermediate(f, value.RightLittleIntermediate); + } + + if(value.RightLittleDistal!=null){ + f.Key("rightLittleDistal"); + __humanoid__humanBones_Serialize_RightLittleDistal(f, value.RightLittleDistal); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Hips(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Spine(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Chest(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_UpperChest(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Neck(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Head(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Jaw(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftUpperLeg(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLowerLeg(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftFoot(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftToes(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightUpperLeg(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLowerLeg(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightFoot(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightToes(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftShoulder(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftUpperArm(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLowerArm(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftHand(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightShoulder(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightUpperArm(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLowerArm(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightHand(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftThumbMetacarpal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftThumbProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftThumbDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftIndexProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftIndexIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftIndexDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftMiddleProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftMiddleIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftMiddleDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftRingProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftRingIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftRingDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLittleProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLittleIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLittleDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightThumbMetacarpal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightThumbProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightThumbDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightIndexProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightIndexIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightIndexDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightMiddleProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightMiddleIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightMiddleDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightRingProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightRingIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightRingDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLittleProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLittleIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLittleDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_Expressions(JsonFormatter f, Expressions value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Preset!=null){ + f.Key("preset"); + __expressions_Serialize_Preset(f, value.Preset); + } + + if(value.Custom!=null&&value.Custom.Count()>0){ + f.Key("custom"); + __expressions_Serialize_Custom(f, value.Custom); + } + + f.EndMap(); +} + +public static void __expressions_Serialize_Preset(JsonFormatter f, Preset value) +{ + f.BeginMap(); + + + if(value.Happy!=null){ + f.Key("happy"); + __expressions__preset_Serialize_Happy(f, value.Happy); + } + + if(value.Angry!=null){ + f.Key("angry"); + __expressions__preset_Serialize_Angry(f, value.Angry); + } + + if(value.Sad!=null){ + f.Key("sad"); + __expressions__preset_Serialize_Sad(f, value.Sad); + } + + if(value.Relaxed!=null){ + f.Key("relaxed"); + __expressions__preset_Serialize_Relaxed(f, value.Relaxed); + } + + if(value.Surprised!=null){ + f.Key("surprised"); + __expressions__preset_Serialize_Surprised(f, value.Surprised); + } + + if(value.Aa!=null){ + f.Key("aa"); + __expressions__preset_Serialize_Aa(f, value.Aa); + } + + if(value.Ih!=null){ + f.Key("ih"); + __expressions__preset_Serialize_Ih(f, value.Ih); + } + + if(value.Ou!=null){ + f.Key("ou"); + __expressions__preset_Serialize_Ou(f, value.Ou); + } + + if(value.Ee!=null){ + f.Key("ee"); + __expressions__preset_Serialize_Ee(f, value.Ee); + } + + if(value.Oh!=null){ + f.Key("oh"); + __expressions__preset_Serialize_Oh(f, value.Oh); + } + + if(value.Blink!=null){ + f.Key("blink"); + __expressions__preset_Serialize_Blink(f, value.Blink); + } + + if(value.BlinkLeft!=null){ + f.Key("blinkLeft"); + __expressions__preset_Serialize_BlinkLeft(f, value.BlinkLeft); + } + + if(value.BlinkRight!=null){ + f.Key("blinkRight"); + __expressions__preset_Serialize_BlinkRight(f, value.BlinkRight); + } + + if(value.LookUp!=null){ + f.Key("lookUp"); + __expressions__preset_Serialize_LookUp(f, value.LookUp); + } + + if(value.LookDown!=null){ + f.Key("lookDown"); + __expressions__preset_Serialize_LookDown(f, value.LookDown); + } + + if(value.LookLeft!=null){ + f.Key("lookLeft"); + __expressions__preset_Serialize_LookLeft(f, value.LookLeft); + } + + if(value.LookRight!=null){ + f.Key("lookRight"); + __expressions__preset_Serialize_LookRight(f, value.LookRight); + } + + if(value.Neutral!=null){ + f.Key("neutral"); + __expressions__preset_Serialize_Neutral(f, value.Neutral); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Happy(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Angry(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Sad(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Relaxed(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Surprised(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Aa(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Ih(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Ou(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Ee(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Oh(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Blink(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_BlinkLeft(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_BlinkRight(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_LookUp(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_LookDown(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_LookLeft(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_LookRight(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Neutral(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions_Serialize_Custom(JsonFormatter f, Dictionary value) +{ + f.BeginMap(); + + foreach(var kv in value) + { + f.Key(kv.Key); + __expressions_Serialize_Custom_ITEM(f, kv.Value); + + } + f.EndMap(); +} + +public static void __expressions_Serialize_Custom_ITEM(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_LookAt(JsonFormatter f, LookAt value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + + } // class +} // namespace diff --git a/Assets/External/VRM10/Runtime/Format/Animation/Serializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Animation/Serializer.g.cs.meta new file mode 100644 index 000000000..02d691857 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Animation/Serializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b1cc771337f6bbf4b932505a7847455a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Constraints.meta b/Assets/External/VRM10/Runtime/Format/Constraints.meta new file mode 100644 index 000000000..4f63dc225 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Constraints.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d4e43cf583d402a468a91afdcd47a323 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Constraints/Deserializer.g.cs b/Assets/External/VRM10/Runtime/Format/Constraints/Deserializer.g.cs new file mode 100644 index 000000000..c68ee4494 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Constraints/Deserializer.g.cs @@ -0,0 +1,223 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using UniJSON; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF.Extensions.VRMC_node_constraint { + +public static class GltfDeserializer +{ + public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_node_constraint.ExtensionName); + +public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_node_constraint extension) +{ + if(src is UniGLTF.glTFExtensionImport extensions) + { + foreach(var kv in extensions.ObjectItems()) + { + if(kv.Key.GetUtf8String() == ExtensionNameUtf8) + { + extension = Deserialize(kv.Value); + return true; + } + } + } + + extension = default; + return false; +} + + +public static VRMC_node_constraint Deserialize(JsonNode parsed) +{ + var value = new VRMC_node_constraint(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="specVersion"){ + value.SpecVersion = kv.Value.GetString(); + continue; + } + + if(key=="constraint"){ + value.Constraint = Deserialize_Constraint(kv.Value); + continue; + } + + } + return value; +} + +public static Constraint Deserialize_Constraint(JsonNode parsed) +{ + var value = new Constraint(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="roll"){ + value.Roll = __constraint_Deserialize_Roll(kv.Value); + continue; + } + + if(key=="aim"){ + value.Aim = __constraint_Deserialize_Aim(kv.Value); + continue; + } + + if(key=="rotation"){ + value.Rotation = __constraint_Deserialize_Rotation(kv.Value); + continue; + } + + } + return value; +} + +public static RollConstraint __constraint_Deserialize_Roll(JsonNode parsed) +{ + var value = new RollConstraint(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="name"){ + value.Name = kv.Value.GetString(); + continue; + } + + if(key=="source"){ + value.Source = kv.Value.GetInt32(); + continue; + } + + if(key=="rollAxis"){ + value.RollAxis = (RollAxis)Enum.Parse(typeof(RollAxis), kv.Value.GetString(), true); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static AimConstraint __constraint_Deserialize_Aim(JsonNode parsed) +{ + var value = new AimConstraint(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="name"){ + value.Name = kv.Value.GetString(); + continue; + } + + if(key=="source"){ + value.Source = kv.Value.GetInt32(); + continue; + } + + if(key=="aimAxis"){ + value.AimAxis = (AimAxis)Enum.Parse(typeof(AimAxis), kv.Value.GetString(), true); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static RotationConstraint __constraint_Deserialize_Rotation(JsonNode parsed) +{ + var value = new RotationConstraint(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="name"){ + value.Name = kv.Value.GetString(); + continue; + } + + if(key=="source"){ + value.Source = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +} // GltfDeserializer +} // UniGLTF diff --git a/Assets/External/VRM10/Runtime/Format/Constraints/Deserializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Constraints/Deserializer.g.cs.meta new file mode 100644 index 000000000..446fe34c4 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Constraints/Deserializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 43eecb71e6b907349bb0ecca3647fb36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Constraints/Format.g.cs b/Assets/External/VRM10/Runtime/Format/Constraints/Format.g.cs new file mode 100644 index 000000000..d9981025f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Constraints/Format.g.cs @@ -0,0 +1,122 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; + + +namespace UniGLTF.Extensions.VRMC_node_constraint +{ + + public enum RollAxis + { + X, + Y, + Z, + + } + + public class RollConstraint + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The user-defined name of this object. + public string Name; + + // The index of the node constrains the node. + public int? Source; + + // The roll axis of the constraint. + public RollAxis RollAxis; + + // The weight of the constraint. + public float? Weight; + } + + public enum AimAxis + { + PositiveX, + NegativeX, + PositiveY, + NegativeY, + PositiveZ, + NegativeZ, + + } + + public class AimConstraint + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The user-defined name of this object. + public string Name; + + // The index of the node constrains the node. + public int? Source; + + // The aim axis of the constraint. + public AimAxis AimAxis; + + // The weight of the constraint. + public float? Weight; + } + + public class RotationConstraint + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The user-defined name of this object. + public string Name; + + // The index of the node constrains the node. + public int? Source; + + // The weight of the constraint. + public float? Weight; + } + + public class Constraint + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // A constraint that transfers a rotation around one axis of a source. + public RollConstraint Roll; + + // A constraint that makes it look at a source object. + public AimConstraint Aim; + + // A constraint that links the rotation with a source. + public RotationConstraint Rotation; + } + + public class VRMC_node_constraint + { + public const string ExtensionName = "VRMC_node_constraint"; + + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Specification version of VRMC_node_constraint + public string SpecVersion; + + // Contains roll, aim, or rotation + public Constraint Constraint; + } +} diff --git a/Assets/External/VRM10/Runtime/Format/Constraints/Format.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Constraints/Format.g.cs.meta new file mode 100644 index 000000000..067282758 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Constraints/Format.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7547f9592a249434d8adc9def62b607e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Constraints/Serializer.g.cs b/Assets/External/VRM10/Runtime/Format/Constraints/Serializer.g.cs new file mode 100644 index 000000000..0828fd008 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Constraints/Serializer.g.cs @@ -0,0 +1,202 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; +using System.Linq; +using UniJSON; + +namespace UniGLTF.Extensions.VRMC_node_constraint { + + static public class GltfSerializer + { + + public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_node_constraint extension) + { + if (dst is glTFExtensionImport) + { + throw new NotImplementedException(); + } + + if (!(dst is glTFExtensionExport extensions)) + { + extensions = new glTFExtensionExport(); + dst = extensions; + } + + var f = new JsonFormatter(); + Serialize(f, extension); + extensions.Add(VRMC_node_constraint.ExtensionName, f.GetStoreBytes()); + } + + +public static void Serialize(JsonFormatter f, VRMC_node_constraint value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.SpecVersion)){ + f.Key("specVersion"); + f.Value(value.SpecVersion); + } + + if(value.Constraint!=null){ + f.Key("constraint"); + Serialize_Constraint(f, value.Constraint); + } + + f.EndMap(); +} + +public static void Serialize_Constraint(JsonFormatter f, Constraint value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Roll!=null){ + f.Key("roll"); + __constraint_Serialize_Roll(f, value.Roll); + } + + if(value.Aim!=null){ + f.Key("aim"); + __constraint_Serialize_Aim(f, value.Aim); + } + + if(value.Rotation!=null){ + f.Key("rotation"); + __constraint_Serialize_Rotation(f, value.Rotation); + } + + f.EndMap(); +} + +public static void __constraint_Serialize_Roll(JsonFormatter f, RollConstraint value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.Name)){ + f.Key("name"); + f.Value(value.Name); + } + + if(value.Source.HasValue){ + f.Key("source"); + f.Value(value.Source.GetValueOrDefault()); + } + + if(true){ + f.Key("rollAxis"); + f.Value(value.RollAxis.ToString()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __constraint_Serialize_Aim(JsonFormatter f, AimConstraint value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.Name)){ + f.Key("name"); + f.Value(value.Name); + } + + if(value.Source.HasValue){ + f.Key("source"); + f.Value(value.Source.GetValueOrDefault()); + } + + if(true){ + f.Key("aimAxis"); + f.Value(value.AimAxis.ToString()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __constraint_Serialize_Rotation(JsonFormatter f, RotationConstraint value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.Name)){ + f.Key("name"); + f.Value(value.Name); + } + + if(value.Source.HasValue){ + f.Key("source"); + f.Value(value.Source.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + + } // class +} // namespace diff --git a/Assets/External/VRM10/Runtime/Format/Constraints/Serializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Constraints/Serializer.g.cs.meta new file mode 100644 index 000000000..a549d95f0 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Constraints/Serializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f81ff5ee0b16a14abf76d93cc5bece7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/MaterialsMToon.meta b/Assets/External/VRM10/Runtime/Format/MaterialsMToon.meta new file mode 100644 index 000000000..3179411c4 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/MaterialsMToon.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec5c4b408d986ed47bf5f2f618f0cbba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Deserializer.g.cs b/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Deserializer.g.cs new file mode 100644 index 000000000..6130bfe00 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Deserializer.g.cs @@ -0,0 +1,421 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using UniJSON; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF.Extensions.VRMC_materials_mtoon { + +public static class GltfDeserializer +{ + public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_materials_mtoon.ExtensionName); + +public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_materials_mtoon extension) +{ + if(src is UniGLTF.glTFExtensionImport extensions) + { + foreach(var kv in extensions.ObjectItems()) + { + if(kv.Key.GetUtf8String() == ExtensionNameUtf8) + { + extension = Deserialize(kv.Value); + return true; + } + } + } + + extension = default; + return false; +} + + +public static VRMC_materials_mtoon Deserialize(JsonNode parsed) +{ + var value = new VRMC_materials_mtoon(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="specVersion"){ + value.SpecVersion = kv.Value.GetString(); + continue; + } + + if(key=="transparentWithZWrite"){ + value.TransparentWithZWrite = kv.Value.GetBoolean(); + continue; + } + + if(key=="renderQueueOffsetNumber"){ + value.RenderQueueOffsetNumber = kv.Value.GetInt32(); + continue; + } + + if(key=="shadeColorFactor"){ + value.ShadeColorFactor = Deserialize_ShadeColorFactor(kv.Value); + continue; + } + + if(key=="shadeMultiplyTexture"){ + value.ShadeMultiplyTexture = Deserialize_ShadeMultiplyTexture(kv.Value); + continue; + } + + if(key=="shadingShiftFactor"){ + value.ShadingShiftFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="shadingShiftTexture"){ + value.ShadingShiftTexture = Deserialize_ShadingShiftTexture(kv.Value); + continue; + } + + if(key=="shadingToonyFactor"){ + value.ShadingToonyFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="giEqualizationFactor"){ + value.GiEqualizationFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="matcapFactor"){ + value.MatcapFactor = Deserialize_MatcapFactor(kv.Value); + continue; + } + + if(key=="matcapTexture"){ + value.MatcapTexture = Deserialize_MatcapTexture(kv.Value); + continue; + } + + if(key=="parametricRimColorFactor"){ + value.ParametricRimColorFactor = Deserialize_ParametricRimColorFactor(kv.Value); + continue; + } + + if(key=="rimMultiplyTexture"){ + value.RimMultiplyTexture = Deserialize_RimMultiplyTexture(kv.Value); + continue; + } + + if(key=="rimLightingMixFactor"){ + value.RimLightingMixFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="parametricRimFresnelPowerFactor"){ + value.ParametricRimFresnelPowerFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="parametricRimLiftFactor"){ + value.ParametricRimLiftFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="outlineWidthMode"){ + value.OutlineWidthMode = (OutlineWidthMode)Enum.Parse(typeof(OutlineWidthMode), kv.Value.GetString(), true); + continue; + } + + if(key=="outlineWidthFactor"){ + value.OutlineWidthFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="outlineWidthMultiplyTexture"){ + value.OutlineWidthMultiplyTexture = Deserialize_OutlineWidthMultiplyTexture(kv.Value); + continue; + } + + if(key=="outlineColorFactor"){ + value.OutlineColorFactor = Deserialize_OutlineColorFactor(kv.Value); + continue; + } + + if(key=="outlineLightingMixFactor"){ + value.OutlineLightingMixFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="uvAnimationMaskTexture"){ + value.UvAnimationMaskTexture = Deserialize_UvAnimationMaskTexture(kv.Value); + continue; + } + + if(key=="uvAnimationScrollXSpeedFactor"){ + value.UvAnimationScrollXSpeedFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="uvAnimationScrollYSpeedFactor"){ + value.UvAnimationScrollYSpeedFactor = kv.Value.GetSingle(); + continue; + } + + if(key=="uvAnimationRotationSpeedFactor"){ + value.UvAnimationRotationSpeedFactor = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static float[] Deserialize_ShadeColorFactor(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static TextureInfo Deserialize_ShadeMultiplyTexture(JsonNode parsed) +{ + var value = new TextureInfo(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="texCoord"){ + value.TexCoord = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static ShadingShiftTextureInfo Deserialize_ShadingShiftTexture(JsonNode parsed) +{ + var value = new ShadingShiftTextureInfo(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="texCoord"){ + value.TexCoord = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static float[] Deserialize_MatcapFactor(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static TextureInfo Deserialize_MatcapTexture(JsonNode parsed) +{ + var value = new TextureInfo(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="texCoord"){ + value.TexCoord = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static float[] Deserialize_ParametricRimColorFactor(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static TextureInfo Deserialize_RimMultiplyTexture(JsonNode parsed) +{ + var value = new TextureInfo(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="texCoord"){ + value.TexCoord = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static TextureInfo Deserialize_OutlineWidthMultiplyTexture(JsonNode parsed) +{ + var value = new TextureInfo(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="texCoord"){ + value.TexCoord = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static float[] Deserialize_OutlineColorFactor(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static TextureInfo Deserialize_UvAnimationMaskTexture(JsonNode parsed) +{ + var value = new TextureInfo(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="texCoord"){ + value.TexCoord = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +} // GltfDeserializer +} // UniGLTF diff --git a/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Deserializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Deserializer.g.cs.meta new file mode 100644 index 000000000..50b528f5d --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Deserializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef33feaabe6513840802975ece5179d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Serializer.g.cs b/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Serializer.g.cs new file mode 100644 index 000000000..48bf768c8 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Serializer.g.cs @@ -0,0 +1,396 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; +using System.Linq; +using UniJSON; + +namespace UniGLTF.Extensions.VRMC_materials_mtoon { + + static public class GltfSerializer + { + + public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_materials_mtoon extension) + { + if (dst is glTFExtensionImport) + { + throw new NotImplementedException(); + } + + if (!(dst is glTFExtensionExport extensions)) + { + extensions = new glTFExtensionExport(); + dst = extensions; + } + + var f = new JsonFormatter(); + Serialize(f, extension); + extensions.Add(VRMC_materials_mtoon.ExtensionName, f.GetStoreBytes()); + } + + +public static void Serialize(JsonFormatter f, VRMC_materials_mtoon value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.SpecVersion)){ + f.Key("specVersion"); + f.Value(value.SpecVersion); + } + + if(value.TransparentWithZWrite.HasValue){ + f.Key("transparentWithZWrite"); + f.Value(value.TransparentWithZWrite.GetValueOrDefault()); + } + + if(value.RenderQueueOffsetNumber.HasValue){ + f.Key("renderQueueOffsetNumber"); + f.Value(value.RenderQueueOffsetNumber.GetValueOrDefault()); + } + + if(value.ShadeColorFactor!=null&&value.ShadeColorFactor.Count()>=3){ + f.Key("shadeColorFactor"); + Serialize_ShadeColorFactor(f, value.ShadeColorFactor); + } + + if(value.ShadeMultiplyTexture!=null){ + f.Key("shadeMultiplyTexture"); + Serialize_ShadeMultiplyTexture(f, value.ShadeMultiplyTexture); + } + + if(value.ShadingShiftFactor.HasValue){ + f.Key("shadingShiftFactor"); + f.Value(value.ShadingShiftFactor.GetValueOrDefault()); + } + + if(value.ShadingShiftTexture!=null){ + f.Key("shadingShiftTexture"); + Serialize_ShadingShiftTexture(f, value.ShadingShiftTexture); + } + + if(value.ShadingToonyFactor.HasValue){ + f.Key("shadingToonyFactor"); + f.Value(value.ShadingToonyFactor.GetValueOrDefault()); + } + + if(value.GiEqualizationFactor.HasValue){ + f.Key("giEqualizationFactor"); + f.Value(value.GiEqualizationFactor.GetValueOrDefault()); + } + + if(value.MatcapFactor!=null&&value.MatcapFactor.Count()>=3){ + f.Key("matcapFactor"); + Serialize_MatcapFactor(f, value.MatcapFactor); + } + + if(value.MatcapTexture!=null){ + f.Key("matcapTexture"); + Serialize_MatcapTexture(f, value.MatcapTexture); + } + + if(value.ParametricRimColorFactor!=null&&value.ParametricRimColorFactor.Count()>=3){ + f.Key("parametricRimColorFactor"); + Serialize_ParametricRimColorFactor(f, value.ParametricRimColorFactor); + } + + if(value.RimMultiplyTexture!=null){ + f.Key("rimMultiplyTexture"); + Serialize_RimMultiplyTexture(f, value.RimMultiplyTexture); + } + + if(value.RimLightingMixFactor.HasValue){ + f.Key("rimLightingMixFactor"); + f.Value(value.RimLightingMixFactor.GetValueOrDefault()); + } + + if(value.ParametricRimFresnelPowerFactor.HasValue){ + f.Key("parametricRimFresnelPowerFactor"); + f.Value(value.ParametricRimFresnelPowerFactor.GetValueOrDefault()); + } + + if(value.ParametricRimLiftFactor.HasValue){ + f.Key("parametricRimLiftFactor"); + f.Value(value.ParametricRimLiftFactor.GetValueOrDefault()); + } + + if(true){ + f.Key("outlineWidthMode"); + f.Value(value.OutlineWidthMode.ToString()); + } + + if(value.OutlineWidthFactor.HasValue){ + f.Key("outlineWidthFactor"); + f.Value(value.OutlineWidthFactor.GetValueOrDefault()); + } + + if(value.OutlineWidthMultiplyTexture!=null){ + f.Key("outlineWidthMultiplyTexture"); + Serialize_OutlineWidthMultiplyTexture(f, value.OutlineWidthMultiplyTexture); + } + + if(value.OutlineColorFactor!=null&&value.OutlineColorFactor.Count()>=3){ + f.Key("outlineColorFactor"); + Serialize_OutlineColorFactor(f, value.OutlineColorFactor); + } + + if(value.OutlineLightingMixFactor.HasValue){ + f.Key("outlineLightingMixFactor"); + f.Value(value.OutlineLightingMixFactor.GetValueOrDefault()); + } + + if(value.UvAnimationMaskTexture!=null){ + f.Key("uvAnimationMaskTexture"); + Serialize_UvAnimationMaskTexture(f, value.UvAnimationMaskTexture); + } + + if(value.UvAnimationScrollXSpeedFactor.HasValue){ + f.Key("uvAnimationScrollXSpeedFactor"); + f.Value(value.UvAnimationScrollXSpeedFactor.GetValueOrDefault()); + } + + if(value.UvAnimationScrollYSpeedFactor.HasValue){ + f.Key("uvAnimationScrollYSpeedFactor"); + f.Value(value.UvAnimationScrollYSpeedFactor.GetValueOrDefault()); + } + + if(value.UvAnimationRotationSpeedFactor.HasValue){ + f.Key("uvAnimationRotationSpeedFactor"); + f.Value(value.UvAnimationRotationSpeedFactor.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_ShadeColorFactor(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void Serialize_ShadeMultiplyTexture(JsonFormatter f, TextureInfo value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.TexCoord.HasValue){ + f.Key("texCoord"); + f.Value(value.TexCoord.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_ShadingShiftTexture(JsonFormatter f, ShadingShiftTextureInfo value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.TexCoord.HasValue){ + f.Key("texCoord"); + f.Value(value.TexCoord.GetValueOrDefault()); + } + + if(value.Scale.HasValue){ + f.Key("scale"); + f.Value(value.Scale.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_MatcapFactor(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void Serialize_MatcapTexture(JsonFormatter f, TextureInfo value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.TexCoord.HasValue){ + f.Key("texCoord"); + f.Value(value.TexCoord.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_ParametricRimColorFactor(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void Serialize_RimMultiplyTexture(JsonFormatter f, TextureInfo value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.TexCoord.HasValue){ + f.Key("texCoord"); + f.Value(value.TexCoord.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_OutlineWidthMultiplyTexture(JsonFormatter f, TextureInfo value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.TexCoord.HasValue){ + f.Key("texCoord"); + f.Value(value.TexCoord.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_OutlineColorFactor(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void Serialize_UvAnimationMaskTexture(JsonFormatter f, TextureInfo value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.TexCoord.HasValue){ + f.Key("texCoord"); + f.Value(value.TexCoord.GetValueOrDefault()); + } + + f.EndMap(); +} + + } // class +} // namespace diff --git a/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Serializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Serializer.g.cs.meta new file mode 100644 index 000000000..87212bea6 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/MaterialsMToon/Serializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88f0964f72d8de44983c4ed691f41558 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/SpringBone.meta b/Assets/External/VRM10/Runtime/Format/SpringBone.meta new file mode 100644 index 000000000..557e328df --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/SpringBone.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a9d1c8d206a79724aa4a6f6ea4957c2a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/SpringBone/Deserializer.g.cs b/Assets/External/VRM10/Runtime/Format/SpringBone/Deserializer.g.cs new file mode 100644 index 000000000..4861c58fc --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/SpringBone/Deserializer.g.cs @@ -0,0 +1,420 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using UniJSON; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF.Extensions.VRMC_springBone { + +public static class GltfDeserializer +{ + public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_springBone.ExtensionName); + +public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_springBone extension) +{ + if(src is UniGLTF.glTFExtensionImport extensions) + { + foreach(var kv in extensions.ObjectItems()) + { + if(kv.Key.GetUtf8String() == ExtensionNameUtf8) + { + extension = Deserialize(kv.Value); + return true; + } + } + } + + extension = default; + return false; +} + + +public static VRMC_springBone Deserialize(JsonNode parsed) +{ + var value = new VRMC_springBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="specVersion"){ + value.SpecVersion = kv.Value.GetString(); + continue; + } + + if(key=="colliders"){ + value.Colliders = Deserialize_Colliders(kv.Value); + continue; + } + + if(key=="colliderGroups"){ + value.ColliderGroups = Deserialize_ColliderGroups(kv.Value); + continue; + } + + if(key=="springs"){ + value.Springs = Deserialize_Springs(kv.Value); + continue; + } + + } + return value; +} + +public static List Deserialize_Colliders(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(Deserialize_Colliders_ITEM(x)); + } + return value; +} + +public static Collider Deserialize_Colliders_ITEM(JsonNode parsed) +{ + var value = new Collider(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="shape"){ + value.Shape = __colliders_ITEM_Deserialize_Shape(kv.Value); + continue; + } + + } + return value; +} + +public static ColliderShape __colliders_ITEM_Deserialize_Shape(JsonNode parsed) +{ + var value = new ColliderShape(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="sphere"){ + value.Sphere = __colliders_ITEM__shape_Deserialize_Sphere(kv.Value); + continue; + } + + if(key=="capsule"){ + value.Capsule = __colliders_ITEM__shape_Deserialize_Capsule(kv.Value); + continue; + } + + } + return value; +} + +public static ColliderShapeSphere __colliders_ITEM__shape_Deserialize_Sphere(JsonNode parsed) +{ + var value = new ColliderShapeSphere(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="offset"){ + value.Offset = __colliders_ITEM__shape__sphere_Deserialize_Offset(kv.Value); + continue; + } + + if(key=="radius"){ + value.Radius = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static float[] __colliders_ITEM__shape__sphere_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static ColliderShapeCapsule __colliders_ITEM__shape_Deserialize_Capsule(JsonNode parsed) +{ + var value = new ColliderShapeCapsule(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="offset"){ + value.Offset = __colliders_ITEM__shape__capsule_Deserialize_Offset(kv.Value); + continue; + } + + if(key=="radius"){ + value.Radius = kv.Value.GetSingle(); + continue; + } + + if(key=="tail"){ + value.Tail = __colliders_ITEM__shape__capsule_Deserialize_Tail(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __colliders_ITEM__shape__capsule_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __colliders_ITEM__shape__capsule_Deserialize_Tail(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List Deserialize_ColliderGroups(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(Deserialize_ColliderGroups_ITEM(x)); + } + return value; +} + +public static ColliderGroup Deserialize_ColliderGroups_ITEM(JsonNode parsed) +{ + var value = new ColliderGroup(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="name"){ + value.Name = kv.Value.GetString(); + continue; + } + + if(key=="colliders"){ + value.Colliders = __colliderGroups_ITEM_Deserialize_Colliders(kv.Value); + continue; + } + + } + return value; +} + +public static int[] __colliderGroups_ITEM_Deserialize_Colliders(JsonNode parsed) +{ + var value = new int[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetInt32(); + } + return value; +} + +public static List Deserialize_Springs(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(Deserialize_Springs_ITEM(x)); + } + return value; +} + +public static Spring Deserialize_Springs_ITEM(JsonNode parsed) +{ + var value = new Spring(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="name"){ + value.Name = kv.Value.GetString(); + continue; + } + + if(key=="joints"){ + value.Joints = __springs_ITEM_Deserialize_Joints(kv.Value); + continue; + } + + if(key=="colliderGroups"){ + value.ColliderGroups = __springs_ITEM_Deserialize_ColliderGroups(kv.Value); + continue; + } + + if(key=="center"){ + value.Center = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static List __springs_ITEM_Deserialize_Joints(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__springs_ITEM_Deserialize_Joints_ITEM(x)); + } + return value; +} + +public static SpringBoneJoint __springs_ITEM_Deserialize_Joints_ITEM(JsonNode parsed) +{ + var value = new SpringBoneJoint(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="hitRadius"){ + value.HitRadius = kv.Value.GetSingle(); + continue; + } + + if(key=="stiffness"){ + value.Stiffness = kv.Value.GetSingle(); + continue; + } + + if(key=="gravityPower"){ + value.GravityPower = kv.Value.GetSingle(); + continue; + } + + if(key=="gravityDir"){ + value.GravityDir = __springs_ITEM__joints_ITEM_Deserialize_GravityDir(kv.Value); + continue; + } + + if(key=="dragForce"){ + value.DragForce = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static float[] __springs_ITEM__joints_ITEM_Deserialize_GravityDir(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static int[] __springs_ITEM_Deserialize_ColliderGroups(JsonNode parsed) +{ + var value = new int[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetInt32(); + } + return value; +} + +} // GltfDeserializer +} // UniGLTF diff --git a/Assets/External/VRM10/Runtime/Format/SpringBone/Deserializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/SpringBone/Deserializer.g.cs.meta new file mode 100644 index 000000000..f382cb416 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/SpringBone/Deserializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e0fa030990ac4146afcf75a0ef81e33 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/SpringBone/Format.g.cs b/Assets/External/VRM10/Runtime/Format/SpringBone/Format.g.cs new file mode 100644 index 000000000..17bf58678 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/SpringBone/Format.g.cs @@ -0,0 +1,142 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; + + +namespace UniGLTF.Extensions.VRMC_springBone +{ + + public class ColliderShapeSphere + { + // The sphere center. vector3 + public float[] Offset; + + // The sphere radius + public float? Radius; + } + + public class ColliderShapeCapsule + { + // The capsule head. vector3 + public float[] Offset; + + // The capsule radius + public float? Radius; + + // The capsule tail. vector3 + public float[] Tail; + } + + public class ColliderShape + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + public ColliderShapeSphere Sphere; + + public ColliderShapeCapsule Capsule; + } + + public class Collider + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The node index. + public int? Node; + + public ColliderShape Shape; + } + + public class ColliderGroup + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Name of the ColliderGroup + public string Name; + + // An array of colliders. + public int[] Colliders; + } + + public class SpringBoneJoint + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The node index. + public int? Node; + + // The radius of spring sphere. + public float? HitRadius; + + // The force to return to the initial pose. + public float? Stiffness; + + // Gravitational acceleration. + public float? GravityPower; + + // The direction of gravity. A gravity other than downward direction also works. + public float[] GravityDir; + + // Air resistance. Deceleration force. + public float? DragForce; + } + + public class Spring + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Name of the Spring + public string Name; + + // Joints of the spring. Except for the first element, a previous joint of the array must be an ancestor of the joint. + public List Joints; + + // Indices of ColliderGroups that detect collision with this spring. + public int[] ColliderGroups; + + // An index of node which is used as a root of center space. + public int? Center; + } + + public class VRMC_springBone + { + public const string ExtensionName = "VRMC_springBone"; + + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Specification version of VRMC_springBone + public string SpecVersion; + + // An array of colliders. + public List Colliders; + + // An array of colliderGroups. + public List ColliderGroups; + + // An array of springs. + public List Springs; + } +} diff --git a/Assets/External/VRM10/Runtime/Format/SpringBone/Format.g.cs.meta b/Assets/External/VRM10/Runtime/Format/SpringBone/Format.g.cs.meta new file mode 100644 index 000000000..b5fa59d57 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/SpringBone/Format.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6bcc6164cd229c942b95c80f002df2be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/SpringBone/Serializer.g.cs b/Assets/External/VRM10/Runtime/Format/SpringBone/Serializer.g.cs new file mode 100644 index 000000000..434dd2c33 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/SpringBone/Serializer.g.cs @@ -0,0 +1,401 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; +using System.Linq; +using UniJSON; + +namespace UniGLTF.Extensions.VRMC_springBone { + + static public class GltfSerializer + { + + public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_springBone extension) + { + if (dst is glTFExtensionImport) + { + throw new NotImplementedException(); + } + + if (!(dst is glTFExtensionExport extensions)) + { + extensions = new glTFExtensionExport(); + dst = extensions; + } + + var f = new JsonFormatter(); + Serialize(f, extension); + extensions.Add(VRMC_springBone.ExtensionName, f.GetStoreBytes()); + } + + +public static void Serialize(JsonFormatter f, VRMC_springBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.SpecVersion)){ + f.Key("specVersion"); + f.Value(value.SpecVersion); + } + + if(value.Colliders!=null&&value.Colliders.Count()>=1){ + f.Key("colliders"); + Serialize_Colliders(f, value.Colliders); + } + + if(value.ColliderGroups!=null&&value.ColliderGroups.Count()>=1){ + f.Key("colliderGroups"); + Serialize_ColliderGroups(f, value.ColliderGroups); + } + + if(value.Springs!=null&&value.Springs.Count()>=1){ + f.Key("springs"); + Serialize_Springs(f, value.Springs); + } + + f.EndMap(); +} + +public static void Serialize_Colliders(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + Serialize_Colliders_ITEM(f, item); + + } + f.EndList(); +} + +public static void Serialize_Colliders_ITEM(JsonFormatter f, Collider value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Shape!=null){ + f.Key("shape"); + __colliders_ITEM_Serialize_Shape(f, value.Shape); + } + + f.EndMap(); +} + +public static void __colliders_ITEM_Serialize_Shape(JsonFormatter f, ColliderShape value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Sphere!=null){ + f.Key("sphere"); + __colliders_ITEM__shape_Serialize_Sphere(f, value.Sphere); + } + + if(value.Capsule!=null){ + f.Key("capsule"); + __colliders_ITEM__shape_Serialize_Capsule(f, value.Capsule); + } + + f.EndMap(); +} + +public static void __colliders_ITEM__shape_Serialize_Sphere(JsonFormatter f, ColliderShapeSphere value) +{ + f.BeginMap(); + + + if(value.Offset!=null&&value.Offset.Count()>=3){ + f.Key("offset"); + __colliders_ITEM__shape__sphere_Serialize_Offset(f, value.Offset); + } + + if(value.Radius.HasValue){ + f.Key("radius"); + f.Value(value.Radius.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __colliders_ITEM__shape__sphere_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __colliders_ITEM__shape_Serialize_Capsule(JsonFormatter f, ColliderShapeCapsule value) +{ + f.BeginMap(); + + + if(value.Offset!=null&&value.Offset.Count()>=3){ + f.Key("offset"); + __colliders_ITEM__shape__capsule_Serialize_Offset(f, value.Offset); + } + + if(value.Radius.HasValue){ + f.Key("radius"); + f.Value(value.Radius.GetValueOrDefault()); + } + + if(value.Tail!=null&&value.Tail.Count()>=3){ + f.Key("tail"); + __colliders_ITEM__shape__capsule_Serialize_Tail(f, value.Tail); + } + + f.EndMap(); +} + +public static void __colliders_ITEM__shape__capsule_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __colliders_ITEM__shape__capsule_Serialize_Tail(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void Serialize_ColliderGroups(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + Serialize_ColliderGroups_ITEM(f, item); + + } + f.EndList(); +} + +public static void Serialize_ColliderGroups_ITEM(JsonFormatter f, ColliderGroup value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.Name)){ + f.Key("name"); + f.Value(value.Name); + } + + if(value.Colliders!=null&&value.Colliders.Count()>=1){ + f.Key("colliders"); + __colliderGroups_ITEM_Serialize_Colliders(f, value.Colliders); + } + + f.EndMap(); +} + +public static void __colliderGroups_ITEM_Serialize_Colliders(JsonFormatter f, int[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void Serialize_Springs(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + Serialize_Springs_ITEM(f, item); + + } + f.EndList(); +} + +public static void Serialize_Springs_ITEM(JsonFormatter f, Spring value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.Name)){ + f.Key("name"); + f.Value(value.Name); + } + + if(value.Joints!=null&&value.Joints.Count()>=1){ + f.Key("joints"); + __springs_ITEM_Serialize_Joints(f, value.Joints); + } + + if(value.ColliderGroups!=null&&value.ColliderGroups.Count()>=1){ + f.Key("colliderGroups"); + __springs_ITEM_Serialize_ColliderGroups(f, value.ColliderGroups); + } + + if(value.Center.HasValue){ + f.Key("center"); + f.Value(value.Center.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __springs_ITEM_Serialize_Joints(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __springs_ITEM_Serialize_Joints_ITEM(f, item); + + } + f.EndList(); +} + +public static void __springs_ITEM_Serialize_Joints_ITEM(JsonFormatter f, SpringBoneJoint value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.HitRadius.HasValue){ + f.Key("hitRadius"); + f.Value(value.HitRadius.GetValueOrDefault()); + } + + if(value.Stiffness.HasValue){ + f.Key("stiffness"); + f.Value(value.Stiffness.GetValueOrDefault()); + } + + if(value.GravityPower.HasValue){ + f.Key("gravityPower"); + f.Value(value.GravityPower.GetValueOrDefault()); + } + + if(value.GravityDir!=null&&value.GravityDir.Count()>=3){ + f.Key("gravityDir"); + __springs_ITEM__joints_ITEM_Serialize_GravityDir(f, value.GravityDir); + } + + if(value.DragForce.HasValue){ + f.Key("dragForce"); + f.Value(value.DragForce.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __springs_ITEM__joints_ITEM_Serialize_GravityDir(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __springs_ITEM_Serialize_ColliderGroups(JsonFormatter f, int[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + + } // class +} // namespace diff --git a/Assets/External/VRM10/Runtime/Format/SpringBone/Serializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/SpringBone/Serializer.g.cs.meta new file mode 100644 index 000000000..0035cfc07 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/SpringBone/Serializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7061394db043f8468755f4d1f3b92f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Vrm.meta b/Assets/External/VRM10/Runtime/Format/Vrm.meta new file mode 100644 index 000000000..528ca25d3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Vrm.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6e411dd959d9da04fa4fc738a688b709 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Vrm/Deserializer.g.cs b/Assets/External/VRM10/Runtime/Format/Vrm/Deserializer.g.cs new file mode 100644 index 000000000..38a6b4db4 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Vrm/Deserializer.g.cs @@ -0,0 +1,6814 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using UniJSON; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF.Extensions.VRMC_vrm { + +public static class GltfDeserializer +{ + public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_vrm.ExtensionName); + +public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_vrm extension) +{ + if(src is UniGLTF.glTFExtensionImport extensions) + { + foreach(var kv in extensions.ObjectItems()) + { + if(kv.Key.GetUtf8String() == ExtensionNameUtf8) + { + extension = Deserialize(kv.Value); + return true; + } + } + } + + extension = default; + return false; +} + + +public static VRMC_vrm Deserialize(JsonNode parsed) +{ + var value = new VRMC_vrm(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="specVersion"){ + value.SpecVersion = kv.Value.GetString(); + continue; + } + + if(key=="meta"){ + value.Meta = Deserialize_Meta(kv.Value); + continue; + } + + if(key=="humanoid"){ + value.Humanoid = Deserialize_Humanoid(kv.Value); + continue; + } + + if(key=="firstPerson"){ + value.FirstPerson = Deserialize_FirstPerson(kv.Value); + continue; + } + + if(key=="lookAt"){ + value.LookAt = Deserialize_LookAt(kv.Value); + continue; + } + + if(key=="expressions"){ + value.Expressions = Deserialize_Expressions(kv.Value); + continue; + } + + } + return value; +} + +public static Meta Deserialize_Meta(JsonNode parsed) +{ + var value = new Meta(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="name"){ + value.Name = kv.Value.GetString(); + continue; + } + + if(key=="version"){ + value.Version = kv.Value.GetString(); + continue; + } + + if(key=="authors"){ + value.Authors = __meta_Deserialize_Authors(kv.Value); + continue; + } + + if(key=="copyrightInformation"){ + value.CopyrightInformation = kv.Value.GetString(); + continue; + } + + if(key=="contactInformation"){ + value.ContactInformation = kv.Value.GetString(); + continue; + } + + if(key=="references"){ + value.References = __meta_Deserialize_References(kv.Value); + continue; + } + + if(key=="thirdPartyLicenses"){ + value.ThirdPartyLicenses = kv.Value.GetString(); + continue; + } + + if(key=="thumbnailImage"){ + value.ThumbnailImage = kv.Value.GetInt32(); + continue; + } + + if(key=="licenseUrl"){ + value.LicenseUrl = kv.Value.GetString(); + continue; + } + + if(key=="avatarPermission"){ + value.AvatarPermission = (AvatarPermissionType)Enum.Parse(typeof(AvatarPermissionType), kv.Value.GetString(), true); + continue; + } + + if(key=="allowExcessivelyViolentUsage"){ + value.AllowExcessivelyViolentUsage = kv.Value.GetBoolean(); + continue; + } + + if(key=="allowExcessivelySexualUsage"){ + value.AllowExcessivelySexualUsage = kv.Value.GetBoolean(); + continue; + } + + if(key=="commercialUsage"){ + value.CommercialUsage = (CommercialUsageType)Enum.Parse(typeof(CommercialUsageType), kv.Value.GetString(), true); + continue; + } + + if(key=="allowPoliticalOrReligiousUsage"){ + value.AllowPoliticalOrReligiousUsage = kv.Value.GetBoolean(); + continue; + } + + if(key=="allowAntisocialOrHateUsage"){ + value.AllowAntisocialOrHateUsage = kv.Value.GetBoolean(); + continue; + } + + if(key=="creditNotation"){ + value.CreditNotation = (CreditNotationType)Enum.Parse(typeof(CreditNotationType), kv.Value.GetString(), true); + continue; + } + + if(key=="allowRedistribution"){ + value.AllowRedistribution = kv.Value.GetBoolean(); + continue; + } + + if(key=="modification"){ + value.Modification = (ModificationType)Enum.Parse(typeof(ModificationType), kv.Value.GetString(), true); + continue; + } + + if(key=="otherLicenseUrl"){ + value.OtherLicenseUrl = kv.Value.GetString(); + continue; + } + + } + return value; +} + +public static List __meta_Deserialize_Authors(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(x.GetString()); + } + return value; +} + +public static List __meta_Deserialize_References(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(x.GetString()); + } + return value; +} + +public static Humanoid Deserialize_Humanoid(JsonNode parsed) +{ + var value = new Humanoid(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="humanBones"){ + value.HumanBones = __humanoid_Deserialize_HumanBones(kv.Value); + continue; + } + + } + return value; +} + +public static HumanBones __humanoid_Deserialize_HumanBones(JsonNode parsed) +{ + var value = new HumanBones(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="hips"){ + value.Hips = __humanoid__humanBones_Deserialize_Hips(kv.Value); + continue; + } + + if(key=="spine"){ + value.Spine = __humanoid__humanBones_Deserialize_Spine(kv.Value); + continue; + } + + if(key=="chest"){ + value.Chest = __humanoid__humanBones_Deserialize_Chest(kv.Value); + continue; + } + + if(key=="upperChest"){ + value.UpperChest = __humanoid__humanBones_Deserialize_UpperChest(kv.Value); + continue; + } + + if(key=="neck"){ + value.Neck = __humanoid__humanBones_Deserialize_Neck(kv.Value); + continue; + } + + if(key=="head"){ + value.Head = __humanoid__humanBones_Deserialize_Head(kv.Value); + continue; + } + + if(key=="leftEye"){ + value.LeftEye = __humanoid__humanBones_Deserialize_LeftEye(kv.Value); + continue; + } + + if(key=="rightEye"){ + value.RightEye = __humanoid__humanBones_Deserialize_RightEye(kv.Value); + continue; + } + + if(key=="jaw"){ + value.Jaw = __humanoid__humanBones_Deserialize_Jaw(kv.Value); + continue; + } + + if(key=="leftUpperLeg"){ + value.LeftUpperLeg = __humanoid__humanBones_Deserialize_LeftUpperLeg(kv.Value); + continue; + } + + if(key=="leftLowerLeg"){ + value.LeftLowerLeg = __humanoid__humanBones_Deserialize_LeftLowerLeg(kv.Value); + continue; + } + + if(key=="leftFoot"){ + value.LeftFoot = __humanoid__humanBones_Deserialize_LeftFoot(kv.Value); + continue; + } + + if(key=="leftToes"){ + value.LeftToes = __humanoid__humanBones_Deserialize_LeftToes(kv.Value); + continue; + } + + if(key=="rightUpperLeg"){ + value.RightUpperLeg = __humanoid__humanBones_Deserialize_RightUpperLeg(kv.Value); + continue; + } + + if(key=="rightLowerLeg"){ + value.RightLowerLeg = __humanoid__humanBones_Deserialize_RightLowerLeg(kv.Value); + continue; + } + + if(key=="rightFoot"){ + value.RightFoot = __humanoid__humanBones_Deserialize_RightFoot(kv.Value); + continue; + } + + if(key=="rightToes"){ + value.RightToes = __humanoid__humanBones_Deserialize_RightToes(kv.Value); + continue; + } + + if(key=="leftShoulder"){ + value.LeftShoulder = __humanoid__humanBones_Deserialize_LeftShoulder(kv.Value); + continue; + } + + if(key=="leftUpperArm"){ + value.LeftUpperArm = __humanoid__humanBones_Deserialize_LeftUpperArm(kv.Value); + continue; + } + + if(key=="leftLowerArm"){ + value.LeftLowerArm = __humanoid__humanBones_Deserialize_LeftLowerArm(kv.Value); + continue; + } + + if(key=="leftHand"){ + value.LeftHand = __humanoid__humanBones_Deserialize_LeftHand(kv.Value); + continue; + } + + if(key=="rightShoulder"){ + value.RightShoulder = __humanoid__humanBones_Deserialize_RightShoulder(kv.Value); + continue; + } + + if(key=="rightUpperArm"){ + value.RightUpperArm = __humanoid__humanBones_Deserialize_RightUpperArm(kv.Value); + continue; + } + + if(key=="rightLowerArm"){ + value.RightLowerArm = __humanoid__humanBones_Deserialize_RightLowerArm(kv.Value); + continue; + } + + if(key=="rightHand"){ + value.RightHand = __humanoid__humanBones_Deserialize_RightHand(kv.Value); + continue; + } + + if(key=="leftThumbMetacarpal"){ + value.LeftThumbMetacarpal = __humanoid__humanBones_Deserialize_LeftThumbMetacarpal(kv.Value); + continue; + } + + if(key=="leftThumbProximal"){ + value.LeftThumbProximal = __humanoid__humanBones_Deserialize_LeftThumbProximal(kv.Value); + continue; + } + + if(key=="leftThumbDistal"){ + value.LeftThumbDistal = __humanoid__humanBones_Deserialize_LeftThumbDistal(kv.Value); + continue; + } + + if(key=="leftIndexProximal"){ + value.LeftIndexProximal = __humanoid__humanBones_Deserialize_LeftIndexProximal(kv.Value); + continue; + } + + if(key=="leftIndexIntermediate"){ + value.LeftIndexIntermediate = __humanoid__humanBones_Deserialize_LeftIndexIntermediate(kv.Value); + continue; + } + + if(key=="leftIndexDistal"){ + value.LeftIndexDistal = __humanoid__humanBones_Deserialize_LeftIndexDistal(kv.Value); + continue; + } + + if(key=="leftMiddleProximal"){ + value.LeftMiddleProximal = __humanoid__humanBones_Deserialize_LeftMiddleProximal(kv.Value); + continue; + } + + if(key=="leftMiddleIntermediate"){ + value.LeftMiddleIntermediate = __humanoid__humanBones_Deserialize_LeftMiddleIntermediate(kv.Value); + continue; + } + + if(key=="leftMiddleDistal"){ + value.LeftMiddleDistal = __humanoid__humanBones_Deserialize_LeftMiddleDistal(kv.Value); + continue; + } + + if(key=="leftRingProximal"){ + value.LeftRingProximal = __humanoid__humanBones_Deserialize_LeftRingProximal(kv.Value); + continue; + } + + if(key=="leftRingIntermediate"){ + value.LeftRingIntermediate = __humanoid__humanBones_Deserialize_LeftRingIntermediate(kv.Value); + continue; + } + + if(key=="leftRingDistal"){ + value.LeftRingDistal = __humanoid__humanBones_Deserialize_LeftRingDistal(kv.Value); + continue; + } + + if(key=="leftLittleProximal"){ + value.LeftLittleProximal = __humanoid__humanBones_Deserialize_LeftLittleProximal(kv.Value); + continue; + } + + if(key=="leftLittleIntermediate"){ + value.LeftLittleIntermediate = __humanoid__humanBones_Deserialize_LeftLittleIntermediate(kv.Value); + continue; + } + + if(key=="leftLittleDistal"){ + value.LeftLittleDistal = __humanoid__humanBones_Deserialize_LeftLittleDistal(kv.Value); + continue; + } + + if(key=="rightThumbMetacarpal"){ + value.RightThumbMetacarpal = __humanoid__humanBones_Deserialize_RightThumbMetacarpal(kv.Value); + continue; + } + + if(key=="rightThumbProximal"){ + value.RightThumbProximal = __humanoid__humanBones_Deserialize_RightThumbProximal(kv.Value); + continue; + } + + if(key=="rightThumbDistal"){ + value.RightThumbDistal = __humanoid__humanBones_Deserialize_RightThumbDistal(kv.Value); + continue; + } + + if(key=="rightIndexProximal"){ + value.RightIndexProximal = __humanoid__humanBones_Deserialize_RightIndexProximal(kv.Value); + continue; + } + + if(key=="rightIndexIntermediate"){ + value.RightIndexIntermediate = __humanoid__humanBones_Deserialize_RightIndexIntermediate(kv.Value); + continue; + } + + if(key=="rightIndexDistal"){ + value.RightIndexDistal = __humanoid__humanBones_Deserialize_RightIndexDistal(kv.Value); + continue; + } + + if(key=="rightMiddleProximal"){ + value.RightMiddleProximal = __humanoid__humanBones_Deserialize_RightMiddleProximal(kv.Value); + continue; + } + + if(key=="rightMiddleIntermediate"){ + value.RightMiddleIntermediate = __humanoid__humanBones_Deserialize_RightMiddleIntermediate(kv.Value); + continue; + } + + if(key=="rightMiddleDistal"){ + value.RightMiddleDistal = __humanoid__humanBones_Deserialize_RightMiddleDistal(kv.Value); + continue; + } + + if(key=="rightRingProximal"){ + value.RightRingProximal = __humanoid__humanBones_Deserialize_RightRingProximal(kv.Value); + continue; + } + + if(key=="rightRingIntermediate"){ + value.RightRingIntermediate = __humanoid__humanBones_Deserialize_RightRingIntermediate(kv.Value); + continue; + } + + if(key=="rightRingDistal"){ + value.RightRingDistal = __humanoid__humanBones_Deserialize_RightRingDistal(kv.Value); + continue; + } + + if(key=="rightLittleProximal"){ + value.RightLittleProximal = __humanoid__humanBones_Deserialize_RightLittleProximal(kv.Value); + continue; + } + + if(key=="rightLittleIntermediate"){ + value.RightLittleIntermediate = __humanoid__humanBones_Deserialize_RightLittleIntermediate(kv.Value); + continue; + } + + if(key=="rightLittleDistal"){ + value.RightLittleDistal = __humanoid__humanBones_Deserialize_RightLittleDistal(kv.Value); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Hips(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Spine(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Chest(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_UpperChest(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Neck(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Head(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftEye(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightEye(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_Jaw(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftUpperLeg(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLowerLeg(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftFoot(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftToes(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightUpperLeg(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLowerLeg(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightFoot(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightToes(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftShoulder(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftUpperArm(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLowerArm(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftHand(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightShoulder(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightUpperArm(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLowerArm(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightHand(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftThumbMetacarpal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftThumbProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftThumbDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftIndexProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftIndexIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftIndexDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftMiddleProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftMiddleIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftMiddleDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftRingProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftRingIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftRingDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLittleProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLittleIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_LeftLittleDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightThumbMetacarpal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightThumbProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightThumbDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightIndexProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightIndexIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightIndexDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightMiddleProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightMiddleIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightMiddleDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightRingProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightRingIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightRingDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLittleProximal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLittleIntermediate(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static HumanBone __humanoid__humanBones_Deserialize_RightLittleDistal(JsonNode parsed) +{ + var value = new HumanBone(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + +public static FirstPerson Deserialize_FirstPerson(JsonNode parsed) +{ + var value = new FirstPerson(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="meshAnnotations"){ + value.MeshAnnotations = __firstPerson_Deserialize_MeshAnnotations(kv.Value); + continue; + } + + } + return value; +} + +public static List __firstPerson_Deserialize_MeshAnnotations(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__firstPerson_Deserialize_MeshAnnotations_ITEM(x)); + } + return value; +} + +public static MeshAnnotation __firstPerson_Deserialize_MeshAnnotations_ITEM(JsonNode parsed) +{ + var value = new MeshAnnotation(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (FirstPersonType)Enum.Parse(typeof(FirstPersonType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static LookAt Deserialize_LookAt(JsonNode parsed) +{ + var value = new LookAt(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="offsetFromHeadBone"){ + value.OffsetFromHeadBone = __lookAt_Deserialize_OffsetFromHeadBone(kv.Value); + continue; + } + + if(key=="type"){ + value.Type = (LookAtType)Enum.Parse(typeof(LookAtType), kv.Value.GetString(), true); + continue; + } + + if(key=="rangeMapHorizontalInner"){ + value.RangeMapHorizontalInner = __lookAt_Deserialize_RangeMapHorizontalInner(kv.Value); + continue; + } + + if(key=="rangeMapHorizontalOuter"){ + value.RangeMapHorizontalOuter = __lookAt_Deserialize_RangeMapHorizontalOuter(kv.Value); + continue; + } + + if(key=="rangeMapVerticalDown"){ + value.RangeMapVerticalDown = __lookAt_Deserialize_RangeMapVerticalDown(kv.Value); + continue; + } + + if(key=="rangeMapVerticalUp"){ + value.RangeMapVerticalUp = __lookAt_Deserialize_RangeMapVerticalUp(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __lookAt_Deserialize_OffsetFromHeadBone(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static LookAtRangeMap __lookAt_Deserialize_RangeMapHorizontalInner(JsonNode parsed) +{ + var value = new LookAtRangeMap(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="inputMaxValue"){ + value.InputMaxValue = kv.Value.GetSingle(); + continue; + } + + if(key=="outputScale"){ + value.OutputScale = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static LookAtRangeMap __lookAt_Deserialize_RangeMapHorizontalOuter(JsonNode parsed) +{ + var value = new LookAtRangeMap(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="inputMaxValue"){ + value.InputMaxValue = kv.Value.GetSingle(); + continue; + } + + if(key=="outputScale"){ + value.OutputScale = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static LookAtRangeMap __lookAt_Deserialize_RangeMapVerticalDown(JsonNode parsed) +{ + var value = new LookAtRangeMap(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="inputMaxValue"){ + value.InputMaxValue = kv.Value.GetSingle(); + continue; + } + + if(key=="outputScale"){ + value.OutputScale = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static LookAtRangeMap __lookAt_Deserialize_RangeMapVerticalUp(JsonNode parsed) +{ + var value = new LookAtRangeMap(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="inputMaxValue"){ + value.InputMaxValue = kv.Value.GetSingle(); + continue; + } + + if(key=="outputScale"){ + value.OutputScale = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static Expressions Deserialize_Expressions(JsonNode parsed) +{ + var value = new Expressions(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="preset"){ + value.Preset = __expressions_Deserialize_Preset(kv.Value); + continue; + } + + if(key=="custom"){ + value.Custom = __expressions_Deserialize_Custom(kv.Value); + continue; + } + + } + return value; +} + +public static Preset __expressions_Deserialize_Preset(JsonNode parsed) +{ + var value = new Preset(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="happy"){ + value.Happy = __expressions__preset_Deserialize_Happy(kv.Value); + continue; + } + + if(key=="angry"){ + value.Angry = __expressions__preset_Deserialize_Angry(kv.Value); + continue; + } + + if(key=="sad"){ + value.Sad = __expressions__preset_Deserialize_Sad(kv.Value); + continue; + } + + if(key=="relaxed"){ + value.Relaxed = __expressions__preset_Deserialize_Relaxed(kv.Value); + continue; + } + + if(key=="surprised"){ + value.Surprised = __expressions__preset_Deserialize_Surprised(kv.Value); + continue; + } + + if(key=="aa"){ + value.Aa = __expressions__preset_Deserialize_Aa(kv.Value); + continue; + } + + if(key=="ih"){ + value.Ih = __expressions__preset_Deserialize_Ih(kv.Value); + continue; + } + + if(key=="ou"){ + value.Ou = __expressions__preset_Deserialize_Ou(kv.Value); + continue; + } + + if(key=="ee"){ + value.Ee = __expressions__preset_Deserialize_Ee(kv.Value); + continue; + } + + if(key=="oh"){ + value.Oh = __expressions__preset_Deserialize_Oh(kv.Value); + continue; + } + + if(key=="blink"){ + value.Blink = __expressions__preset_Deserialize_Blink(kv.Value); + continue; + } + + if(key=="blinkLeft"){ + value.BlinkLeft = __expressions__preset_Deserialize_BlinkLeft(kv.Value); + continue; + } + + if(key=="blinkRight"){ + value.BlinkRight = __expressions__preset_Deserialize_BlinkRight(kv.Value); + continue; + } + + if(key=="lookUp"){ + value.LookUp = __expressions__preset_Deserialize_LookUp(kv.Value); + continue; + } + + if(key=="lookDown"){ + value.LookDown = __expressions__preset_Deserialize_LookDown(kv.Value); + continue; + } + + if(key=="lookLeft"){ + value.LookLeft = __expressions__preset_Deserialize_LookLeft(kv.Value); + continue; + } + + if(key=="lookRight"){ + value.LookRight = __expressions__preset_Deserialize_LookRight(kv.Value); + continue; + } + + if(key=="neutral"){ + value.Neutral = __expressions__preset_Deserialize_Neutral(kv.Value); + continue; + } + + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Happy(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__happy_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__happy_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__happy_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__happy_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__happy_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__happy_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__happy_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__happy_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__happy_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__happy__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__happy__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__happy_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__happy_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__happy_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__happy__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__happy__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__happy__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__happy__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Angry(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__angry_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__angry_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__angry_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__angry_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__angry_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__angry_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__angry_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__angry_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__angry_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__angry__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__angry__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__angry_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__angry_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__angry_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__angry__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__angry__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__angry__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__angry__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Sad(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__sad_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__sad_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__sad_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__sad_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__sad_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__sad_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__sad_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__sad_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__sad_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__sad__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__sad__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__sad_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__sad_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__sad_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__sad__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__sad__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__sad__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__sad__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Relaxed(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__relaxed_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__relaxed_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__relaxed_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__relaxed_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__relaxed_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__relaxed_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__relaxed_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__relaxed_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__relaxed_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__relaxed__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__relaxed__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__relaxed_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__relaxed_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__relaxed_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__relaxed__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__relaxed__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__relaxed__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__relaxed__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Surprised(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__surprised_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__surprised_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__surprised_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__surprised_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__surprised_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__surprised_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__surprised_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__surprised_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__surprised_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__surprised__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__surprised__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__surprised_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__surprised_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__surprised_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__surprised__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__surprised__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__surprised__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__surprised__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Aa(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__aa_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__aa_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__aa_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__aa_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__aa_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__aa_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__aa_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__aa_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__aa_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__aa__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__aa__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__aa_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__aa_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__aa_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__aa__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__aa__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__aa__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__aa__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Ih(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__ih_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__ih_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__ih_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__ih_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ih_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__ih_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__ih_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ih_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__ih_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__ih__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__ih__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__ih_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ih_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__ih_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__ih__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__ih__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__ih__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__ih__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Ou(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__ou_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__ou_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__ou_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__ou_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ou_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__ou_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__ou_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ou_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__ou_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__ou__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__ou__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__ou_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ou_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__ou_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__ou__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__ou__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__ou__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__ou__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Ee(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__ee_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__ee_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__ee_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__ee_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ee_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__ee_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__ee_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ee_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__ee_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__ee__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__ee__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__ee_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__ee_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__ee_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__ee__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__ee__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__ee__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__ee__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Oh(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__oh_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__oh_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__oh_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__oh_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__oh_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__oh_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__oh_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__oh_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__oh_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__oh__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__oh__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__oh_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__oh_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__oh_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__oh__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__oh__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__oh__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__oh__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Blink(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__blink_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__blink_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__blink_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__blink_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blink_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__blink_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__blink_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blink_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__blink_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__blink__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__blink__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__blink_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blink_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__blink_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__blink__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__blink__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__blink__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__blink__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_BlinkLeft(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__blinkLeft_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__blinkLeft_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__blinkLeft_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__blinkLeft_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blinkLeft_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__blinkLeft_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__blinkLeft_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blinkLeft_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__blinkLeft_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__blinkLeft__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__blinkLeft__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__blinkLeft_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blinkLeft_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__blinkLeft_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__blinkLeft__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__blinkLeft__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__blinkLeft__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__blinkLeft__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_BlinkRight(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__blinkRight_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__blinkRight_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__blinkRight_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__blinkRight_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blinkRight_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__blinkRight_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__blinkRight_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blinkRight_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__blinkRight_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__blinkRight__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__blinkRight__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__blinkRight_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__blinkRight_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__blinkRight_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__blinkRight__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__blinkRight__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__blinkRight__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__blinkRight__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_LookUp(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__lookUp_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__lookUp_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__lookUp_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__lookUp_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookUp_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__lookUp_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__lookUp_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookUp_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__lookUp_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__lookUp__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__lookUp__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__lookUp_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookUp_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__lookUp_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__lookUp__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__lookUp__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__lookUp__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__lookUp__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_LookDown(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__lookDown_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__lookDown_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__lookDown_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__lookDown_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookDown_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__lookDown_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__lookDown_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookDown_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__lookDown_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__lookDown__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__lookDown__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__lookDown_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookDown_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__lookDown_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__lookDown__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__lookDown__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__lookDown__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__lookDown__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_LookLeft(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__lookLeft_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__lookLeft_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__lookLeft_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__lookLeft_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookLeft_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__lookLeft_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__lookLeft_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookLeft_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__lookLeft_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__lookLeft__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__lookLeft__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__lookLeft_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookLeft_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__lookLeft_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__lookLeft__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__lookLeft__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__lookLeft__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__lookLeft__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_LookRight(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__lookRight_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__lookRight_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__lookRight_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__lookRight_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookRight_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__lookRight_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__lookRight_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookRight_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__lookRight_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__lookRight__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__lookRight__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__lookRight_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__lookRight_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__lookRight_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__lookRight__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__lookRight__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__lookRight__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__lookRight__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Expression __expressions__preset_Deserialize_Neutral(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__preset__neutral_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__preset__neutral_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__preset__neutral_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__preset__neutral_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__neutral_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__preset__neutral_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__preset__neutral_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__neutral_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__preset__neutral_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__preset__neutral__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__neutral__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__preset__neutral_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__preset__neutral_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__preset__neutral_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__preset__neutral__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__preset__neutral__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__preset__neutral__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__preset__neutral__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static Dictionary __expressions_Deserialize_Custom(JsonNode parsed) +{ + var value = new Dictionary(); + foreach(var kv in parsed.ObjectItems()) + { + value.Add(kv.Key.GetString(), __expressions_Deserialize_Custom_ITEM(kv.Value)); + } + return value; +} + +public static Expression __expressions_Deserialize_Custom_ITEM(JsonNode parsed) +{ + var value = new Expression(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="morphTargetBinds"){ + value.MorphTargetBinds = __expressions__custom_PROP_Deserialize_MorphTargetBinds(kv.Value); + continue; + } + + if(key=="materialColorBinds"){ + value.MaterialColorBinds = __expressions__custom_PROP_Deserialize_MaterialColorBinds(kv.Value); + continue; + } + + if(key=="textureTransformBinds"){ + value.TextureTransformBinds = __expressions__custom_PROP_Deserialize_TextureTransformBinds(kv.Value); + continue; + } + + if(key=="isBinary"){ + value.IsBinary = kv.Value.GetBoolean(); + continue; + } + + if(key=="overrideBlink"){ + value.OverrideBlink = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideLookAt"){ + value.OverrideLookAt = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + if(key=="overrideMouth"){ + value.OverrideMouth = (ExpressionOverrideType)Enum.Parse(typeof(ExpressionOverrideType), kv.Value.GetString(), true); + continue; + } + + } + return value; +} + +public static List __expressions__custom_PROP_Deserialize_MorphTargetBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__custom_PROP_Deserialize_MorphTargetBinds_ITEM(x)); + } + return value; +} + +public static MorphTargetBind __expressions__custom_PROP_Deserialize_MorphTargetBinds_ITEM(JsonNode parsed) +{ + var value = new MorphTargetBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="index"){ + value.Index = kv.Value.GetInt32(); + continue; + } + + if(key=="weight"){ + value.Weight = kv.Value.GetSingle(); + continue; + } + + } + return value; +} + +public static List __expressions__custom_PROP_Deserialize_MaterialColorBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__custom_PROP_Deserialize_MaterialColorBinds_ITEM(x)); + } + return value; +} + +public static MaterialColorBind __expressions__custom_PROP_Deserialize_MaterialColorBinds_ITEM(JsonNode parsed) +{ + var value = new MaterialColorBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="type"){ + value.Type = (MaterialColorType)Enum.Parse(typeof(MaterialColorType), kv.Value.GetString(), true); + continue; + } + + if(key=="targetValue"){ + value.TargetValue = __expressions__custom_PROP__materialColorBinds_ITEM_Deserialize_TargetValue(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__custom_PROP__materialColorBinds_ITEM_Deserialize_TargetValue(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static List __expressions__custom_PROP_Deserialize_TextureTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(__expressions__custom_PROP_Deserialize_TextureTransformBinds_ITEM(x)); + } + return value; +} + +public static TextureTransformBind __expressions__custom_PROP_Deserialize_TextureTransformBinds_ITEM(JsonNode parsed) +{ + var value = new TextureTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="material"){ + value.Material = kv.Value.GetInt32(); + continue; + } + + if(key=="scale"){ + value.Scale = __expressions__custom_PROP__textureTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="offset"){ + value.Offset = __expressions__custom_PROP__textureTransformBinds_ITEM_Deserialize_Offset(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __expressions__custom_PROP__textureTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __expressions__custom_PROP__textureTransformBinds_ITEM_Deserialize_Offset(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +} // GltfDeserializer +} // UniGLTF diff --git a/Assets/External/VRM10/Runtime/Format/Vrm/Deserializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Vrm/Deserializer.g.cs.meta new file mode 100644 index 000000000..f4df7bec2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Vrm/Deserializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73b683fed9dcc824c9c8254fe6296445 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Vrm/Format.g.cs b/Assets/External/VRM10/Runtime/Format/Vrm/Format.g.cs new file mode 100644 index 000000000..8b673b689 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Vrm/Format.g.cs @@ -0,0 +1,584 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; + + +namespace UniGLTF.Extensions.VRMC_vrm +{ + + public enum AvatarPermissionType + { + onlyAuthor, + onlySeparatelyLicensedPerson, + everyone, + + } + + public enum CommercialUsageType + { + personalNonProfit, + personalProfit, + corporation, + + } + + public enum CreditNotationType + { + required, + unnecessary, + + } + + public enum ModificationType + { + prohibited, + allowModification, + allowModificationRedistribution, + + } + + public class Meta + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The name of the model + public string Name; + + // The version of the model + public string Version; + + // Authors of the model + public List Authors; + + // An information that describes the copyright of the model + public string CopyrightInformation; + + // An information that describes the contact information of the author + public string ContactInformation; + + // References / original works of the model + public List References; + + // Third party licenses of the model, if required. You can use line breaks + public string ThirdPartyLicenses; + + // The index to the thumbnail image of the model in gltf.images + public int? ThumbnailImage; + + // A URL towards the license document this model refers to + public string LicenseUrl; + + // A person who can perform as an avatar with this model + public AvatarPermissionType AvatarPermission; + + // A flag that permits to use this model in excessively violent contents + public bool? AllowExcessivelyViolentUsage; + + // A flag that permits to use this model in excessively sexual contents + public bool? AllowExcessivelySexualUsage; + + // An option that permits to use this model in commercial products + public CommercialUsageType CommercialUsage; + + // A flag that permits to use this model in political or religious contents + public bool? AllowPoliticalOrReligiousUsage; + + // A flag that permits to use this model in contents contain anti-social activities or hate speeches + public bool? AllowAntisocialOrHateUsage; + + // An option that forces or abandons to display the credit of this model + public CreditNotationType CreditNotation; + + // A flag that permits to redistribute this model + public bool? AllowRedistribution; + + // An option that controls the condition to modify this model + public ModificationType Modification; + + // Describe the URL links of other license + public string OtherLicenseUrl; + } + + public class HumanBone + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Represents a single glTF node tied to this humanBone. + public int? Node; + } + + public class HumanBones + { + // Represents a single bone of a Humanoid. + public HumanBone Hips; + + // Represents a single bone of a Humanoid. + public HumanBone Spine; + + // Represents a single bone of a Humanoid. + public HumanBone Chest; + + // Represents a single bone of a Humanoid. + public HumanBone UpperChest; + + // Represents a single bone of a Humanoid. + public HumanBone Neck; + + // Represents a single bone of a Humanoid. + public HumanBone Head; + + // Represents a single bone of a Humanoid. + public HumanBone LeftEye; + + // Represents a single bone of a Humanoid. + public HumanBone RightEye; + + // Represents a single bone of a Humanoid. + public HumanBone Jaw; + + // Represents a single bone of a Humanoid. + public HumanBone LeftUpperLeg; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLowerLeg; + + // Represents a single bone of a Humanoid. + public HumanBone LeftFoot; + + // Represents a single bone of a Humanoid. + public HumanBone LeftToes; + + // Represents a single bone of a Humanoid. + public HumanBone RightUpperLeg; + + // Represents a single bone of a Humanoid. + public HumanBone RightLowerLeg; + + // Represents a single bone of a Humanoid. + public HumanBone RightFoot; + + // Represents a single bone of a Humanoid. + public HumanBone RightToes; + + // Represents a single bone of a Humanoid. + public HumanBone LeftShoulder; + + // Represents a single bone of a Humanoid. + public HumanBone LeftUpperArm; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLowerArm; + + // Represents a single bone of a Humanoid. + public HumanBone LeftHand; + + // Represents a single bone of a Humanoid. + public HumanBone RightShoulder; + + // Represents a single bone of a Humanoid. + public HumanBone RightUpperArm; + + // Represents a single bone of a Humanoid. + public HumanBone RightLowerArm; + + // Represents a single bone of a Humanoid. + public HumanBone RightHand; + + // Represents a single bone of a Humanoid. + public HumanBone LeftThumbMetacarpal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftThumbProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftThumbDistal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftIndexProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftIndexIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone LeftIndexDistal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftMiddleProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftMiddleIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone LeftMiddleDistal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftRingProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftRingIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone LeftRingDistal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLittleProximal; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLittleIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone LeftLittleDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightThumbMetacarpal; + + // Represents a single bone of a Humanoid. + public HumanBone RightThumbProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightThumbDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightIndexProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightIndexIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone RightIndexDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightMiddleProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightMiddleIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone RightMiddleDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightRingProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightRingIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone RightRingDistal; + + // Represents a single bone of a Humanoid. + public HumanBone RightLittleProximal; + + // Represents a single bone of a Humanoid. + public HumanBone RightLittleIntermediate; + + // Represents a single bone of a Humanoid. + public HumanBone RightLittleDistal; + } + + public class Humanoid + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Represents a set of humanBones of a humanoid. + public HumanBones HumanBones; + } + + public enum FirstPersonType + { + auto, + both, + thirdPersonOnly, + firstPersonOnly, + + } + + public class MeshAnnotation + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The index of the node that attached to target mesh. + public int? Node; + + // How the camera interprets the mesh. + public FirstPersonType Type; + } + + public class FirstPerson + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Mesh rendering annotation for cameras. + public List MeshAnnotations; + } + + public enum LookAtType + { + bone, + expression, + + } + + public class LookAtRangeMap + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Yaw and pitch angles ( degrees ) between the head bone forward vector and the eye gaze LookAt vector + public float? InputMaxValue; + + // Degree for type.bone, Weight for type.expressions + public float? OutputScale; + } + + public class LookAt + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The origin of LookAt. Position offset from the head bone + public float[] OffsetFromHeadBone; + + public LookAtType Type; + + // Horizontal inward movement. The left eye moves right. The right eye moves left. + public LookAtRangeMap RangeMapHorizontalInner; + + // Horizontal outward movement. The left eye moves left. The right eye moves right. + public LookAtRangeMap RangeMapHorizontalOuter; + + // Vertical downward movement. Both eyes move upwards + public LookAtRangeMap RangeMapVerticalDown; + + // Vertical upward movement. Both eyes move downwards + public LookAtRangeMap RangeMapVerticalUp; + } + + public class MorphTargetBind + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The index of the node that attached to target mesh. + public int? Node; + + // The index of the morph target in the mesh. + public int? Index; + + // The weight value of target morph target. + public float? Weight; + } + + public enum MaterialColorType + { + color, + emissionColor, + shadeColor, + matcapColor, + rimColor, + outlineColor, + + } + + public class MaterialColorBind + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // target material + public int? Material; + + public MaterialColorType Type; + + // target color + public float[] TargetValue; + } + + public class TextureTransformBind + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // target material + public int? Material; + + // uv scaling for TEXCOORD_0 + public float[] Scale; + + // uv offset for TEXCOORD_0 + public float[] Offset; + } + + public enum ExpressionOverrideType + { + none, + block, + blend, + + } + + public class Expression + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Specify a morph target + public List MorphTargetBinds; + + // Material color animation references + public List MaterialColorBinds; + + // Texture transform animation references + public List TextureTransformBinds; + + // A value greater than 0.5 is 1.0, otherwise 0.0 + public bool? IsBinary; + + // Override values of Blink expressions when this Expression is enabled + public ExpressionOverrideType OverrideBlink; + + // Override values of LookAt expressions when this Expression is enabled + public ExpressionOverrideType OverrideLookAt; + + // Override values of Mouth expressions when this Expression is enabled + public ExpressionOverrideType OverrideMouth; + } + + public class Preset + { + // Definition of expression by weighted animation + public Expression Happy; + + // Definition of expression by weighted animation + public Expression Angry; + + // Definition of expression by weighted animation + public Expression Sad; + + // Definition of expression by weighted animation + public Expression Relaxed; + + // Definition of expression by weighted animation + public Expression Surprised; + + // Definition of expression by weighted animation + public Expression Aa; + + // Definition of expression by weighted animation + public Expression Ih; + + // Definition of expression by weighted animation + public Expression Ou; + + // Definition of expression by weighted animation + public Expression Ee; + + // Definition of expression by weighted animation + public Expression Oh; + + // Definition of expression by weighted animation + public Expression Blink; + + // Definition of expression by weighted animation + public Expression BlinkLeft; + + // Definition of expression by weighted animation + public Expression BlinkRight; + + // Definition of expression by weighted animation + public Expression LookUp; + + // Definition of expression by weighted animation + public Expression LookDown; + + // Definition of expression by weighted animation + public Expression LookLeft; + + // Definition of expression by weighted animation + public Expression LookRight; + + // Definition of expression by weighted animation + public Expression Neutral; + } + + public class Expressions + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Preset expressions + public Preset Preset; + + // Custom expressions + public Dictionary Custom; + } + + public class VRMC_vrm + { + public const string ExtensionName = "VRMC_vrm"; + + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Specification version of VRMC_vrm + public string SpecVersion; + + // Meta informations of the VRM model + public Meta Meta; + + // Correspondence between nodes and human bones + public Humanoid Humanoid; + + // First-person perspective settings + public FirstPerson FirstPerson; + + // Eye gaze control + public LookAt LookAt; + + // Definition of expressions + public Expressions Expressions; + } +} diff --git a/Assets/External/VRM10/Runtime/Format/Vrm/Format.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Vrm/Format.g.cs.meta new file mode 100644 index 000000000..dac6eadf3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Vrm/Format.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f35cabeae5de7e428a213eb2fec396b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/Vrm/Serializer.g.cs b/Assets/External/VRM10/Runtime/Format/Vrm/Serializer.g.cs new file mode 100644 index 000000000..60112524f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Vrm/Serializer.g.cs @@ -0,0 +1,6418 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; +using System.Linq; +using UniJSON; + +namespace UniGLTF.Extensions.VRMC_vrm { + + static public class GltfSerializer + { + + public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_vrm extension) + { + if (dst is glTFExtensionImport) + { + throw new NotImplementedException(); + } + + if (!(dst is glTFExtensionExport extensions)) + { + extensions = new glTFExtensionExport(); + dst = extensions; + } + + var f = new JsonFormatter(); + Serialize(f, extension); + extensions.Add(VRMC_vrm.ExtensionName, f.GetStoreBytes()); + } + + +public static void Serialize(JsonFormatter f, VRMC_vrm value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.SpecVersion)){ + f.Key("specVersion"); + f.Value(value.SpecVersion); + } + + if(value.Meta!=null){ + f.Key("meta"); + Serialize_Meta(f, value.Meta); + } + + if(value.Humanoid!=null){ + f.Key("humanoid"); + Serialize_Humanoid(f, value.Humanoid); + } + + if(value.FirstPerson!=null){ + f.Key("firstPerson"); + Serialize_FirstPerson(f, value.FirstPerson); + } + + if(value.LookAt!=null){ + f.Key("lookAt"); + Serialize_LookAt(f, value.LookAt); + } + + if(value.Expressions!=null){ + f.Key("expressions"); + Serialize_Expressions(f, value.Expressions); + } + + f.EndMap(); +} + +public static void Serialize_Meta(JsonFormatter f, Meta value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(!string.IsNullOrEmpty(value.Name)){ + f.Key("name"); + f.Value(value.Name); + } + + if(!string.IsNullOrEmpty(value.Version)){ + f.Key("version"); + f.Value(value.Version); + } + + if(value.Authors!=null&&value.Authors.Count()>=1){ + f.Key("authors"); + __meta_Serialize_Authors(f, value.Authors); + } + + if(!string.IsNullOrEmpty(value.CopyrightInformation)){ + f.Key("copyrightInformation"); + f.Value(value.CopyrightInformation); + } + + if(!string.IsNullOrEmpty(value.ContactInformation)){ + f.Key("contactInformation"); + f.Value(value.ContactInformation); + } + + if(value.References!=null&&value.References.Count()>=1){ + f.Key("references"); + __meta_Serialize_References(f, value.References); + } + + if(!string.IsNullOrEmpty(value.ThirdPartyLicenses)){ + f.Key("thirdPartyLicenses"); + f.Value(value.ThirdPartyLicenses); + } + + if(value.ThumbnailImage.HasValue){ + f.Key("thumbnailImage"); + f.Value(value.ThumbnailImage.GetValueOrDefault()); + } + + if(!string.IsNullOrEmpty(value.LicenseUrl)){ + f.Key("licenseUrl"); + f.Value(value.LicenseUrl); + } + + if(true){ + f.Key("avatarPermission"); + f.Value(value.AvatarPermission.ToString()); + } + + if(value.AllowExcessivelyViolentUsage.HasValue){ + f.Key("allowExcessivelyViolentUsage"); + f.Value(value.AllowExcessivelyViolentUsage.GetValueOrDefault()); + } + + if(value.AllowExcessivelySexualUsage.HasValue){ + f.Key("allowExcessivelySexualUsage"); + f.Value(value.AllowExcessivelySexualUsage.GetValueOrDefault()); + } + + if(true){ + f.Key("commercialUsage"); + f.Value(value.CommercialUsage.ToString()); + } + + if(value.AllowPoliticalOrReligiousUsage.HasValue){ + f.Key("allowPoliticalOrReligiousUsage"); + f.Value(value.AllowPoliticalOrReligiousUsage.GetValueOrDefault()); + } + + if(value.AllowAntisocialOrHateUsage.HasValue){ + f.Key("allowAntisocialOrHateUsage"); + f.Value(value.AllowAntisocialOrHateUsage.GetValueOrDefault()); + } + + if(true){ + f.Key("creditNotation"); + f.Value(value.CreditNotation.ToString()); + } + + if(value.AllowRedistribution.HasValue){ + f.Key("allowRedistribution"); + f.Value(value.AllowRedistribution.GetValueOrDefault()); + } + + if(true){ + f.Key("modification"); + f.Value(value.Modification.ToString()); + } + + if(!string.IsNullOrEmpty(value.OtherLicenseUrl)){ + f.Key("otherLicenseUrl"); + f.Value(value.OtherLicenseUrl); + } + + f.EndMap(); +} + +public static void __meta_Serialize_Authors(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __meta_Serialize_References(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void Serialize_Humanoid(JsonFormatter f, Humanoid value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.HumanBones!=null){ + f.Key("humanBones"); + __humanoid_Serialize_HumanBones(f, value.HumanBones); + } + + f.EndMap(); +} + +public static void __humanoid_Serialize_HumanBones(JsonFormatter f, HumanBones value) +{ + f.BeginMap(); + + + if(value.Hips!=null){ + f.Key("hips"); + __humanoid__humanBones_Serialize_Hips(f, value.Hips); + } + + if(value.Spine!=null){ + f.Key("spine"); + __humanoid__humanBones_Serialize_Spine(f, value.Spine); + } + + if(value.Chest!=null){ + f.Key("chest"); + __humanoid__humanBones_Serialize_Chest(f, value.Chest); + } + + if(value.UpperChest!=null){ + f.Key("upperChest"); + __humanoid__humanBones_Serialize_UpperChest(f, value.UpperChest); + } + + if(value.Neck!=null){ + f.Key("neck"); + __humanoid__humanBones_Serialize_Neck(f, value.Neck); + } + + if(value.Head!=null){ + f.Key("head"); + __humanoid__humanBones_Serialize_Head(f, value.Head); + } + + if(value.LeftEye!=null){ + f.Key("leftEye"); + __humanoid__humanBones_Serialize_LeftEye(f, value.LeftEye); + } + + if(value.RightEye!=null){ + f.Key("rightEye"); + __humanoid__humanBones_Serialize_RightEye(f, value.RightEye); + } + + if(value.Jaw!=null){ + f.Key("jaw"); + __humanoid__humanBones_Serialize_Jaw(f, value.Jaw); + } + + if(value.LeftUpperLeg!=null){ + f.Key("leftUpperLeg"); + __humanoid__humanBones_Serialize_LeftUpperLeg(f, value.LeftUpperLeg); + } + + if(value.LeftLowerLeg!=null){ + f.Key("leftLowerLeg"); + __humanoid__humanBones_Serialize_LeftLowerLeg(f, value.LeftLowerLeg); + } + + if(value.LeftFoot!=null){ + f.Key("leftFoot"); + __humanoid__humanBones_Serialize_LeftFoot(f, value.LeftFoot); + } + + if(value.LeftToes!=null){ + f.Key("leftToes"); + __humanoid__humanBones_Serialize_LeftToes(f, value.LeftToes); + } + + if(value.RightUpperLeg!=null){ + f.Key("rightUpperLeg"); + __humanoid__humanBones_Serialize_RightUpperLeg(f, value.RightUpperLeg); + } + + if(value.RightLowerLeg!=null){ + f.Key("rightLowerLeg"); + __humanoid__humanBones_Serialize_RightLowerLeg(f, value.RightLowerLeg); + } + + if(value.RightFoot!=null){ + f.Key("rightFoot"); + __humanoid__humanBones_Serialize_RightFoot(f, value.RightFoot); + } + + if(value.RightToes!=null){ + f.Key("rightToes"); + __humanoid__humanBones_Serialize_RightToes(f, value.RightToes); + } + + if(value.LeftShoulder!=null){ + f.Key("leftShoulder"); + __humanoid__humanBones_Serialize_LeftShoulder(f, value.LeftShoulder); + } + + if(value.LeftUpperArm!=null){ + f.Key("leftUpperArm"); + __humanoid__humanBones_Serialize_LeftUpperArm(f, value.LeftUpperArm); + } + + if(value.LeftLowerArm!=null){ + f.Key("leftLowerArm"); + __humanoid__humanBones_Serialize_LeftLowerArm(f, value.LeftLowerArm); + } + + if(value.LeftHand!=null){ + f.Key("leftHand"); + __humanoid__humanBones_Serialize_LeftHand(f, value.LeftHand); + } + + if(value.RightShoulder!=null){ + f.Key("rightShoulder"); + __humanoid__humanBones_Serialize_RightShoulder(f, value.RightShoulder); + } + + if(value.RightUpperArm!=null){ + f.Key("rightUpperArm"); + __humanoid__humanBones_Serialize_RightUpperArm(f, value.RightUpperArm); + } + + if(value.RightLowerArm!=null){ + f.Key("rightLowerArm"); + __humanoid__humanBones_Serialize_RightLowerArm(f, value.RightLowerArm); + } + + if(value.RightHand!=null){ + f.Key("rightHand"); + __humanoid__humanBones_Serialize_RightHand(f, value.RightHand); + } + + if(value.LeftThumbMetacarpal!=null){ + f.Key("leftThumbMetacarpal"); + __humanoid__humanBones_Serialize_LeftThumbMetacarpal(f, value.LeftThumbMetacarpal); + } + + if(value.LeftThumbProximal!=null){ + f.Key("leftThumbProximal"); + __humanoid__humanBones_Serialize_LeftThumbProximal(f, value.LeftThumbProximal); + } + + if(value.LeftThumbDistal!=null){ + f.Key("leftThumbDistal"); + __humanoid__humanBones_Serialize_LeftThumbDistal(f, value.LeftThumbDistal); + } + + if(value.LeftIndexProximal!=null){ + f.Key("leftIndexProximal"); + __humanoid__humanBones_Serialize_LeftIndexProximal(f, value.LeftIndexProximal); + } + + if(value.LeftIndexIntermediate!=null){ + f.Key("leftIndexIntermediate"); + __humanoid__humanBones_Serialize_LeftIndexIntermediate(f, value.LeftIndexIntermediate); + } + + if(value.LeftIndexDistal!=null){ + f.Key("leftIndexDistal"); + __humanoid__humanBones_Serialize_LeftIndexDistal(f, value.LeftIndexDistal); + } + + if(value.LeftMiddleProximal!=null){ + f.Key("leftMiddleProximal"); + __humanoid__humanBones_Serialize_LeftMiddleProximal(f, value.LeftMiddleProximal); + } + + if(value.LeftMiddleIntermediate!=null){ + f.Key("leftMiddleIntermediate"); + __humanoid__humanBones_Serialize_LeftMiddleIntermediate(f, value.LeftMiddleIntermediate); + } + + if(value.LeftMiddleDistal!=null){ + f.Key("leftMiddleDistal"); + __humanoid__humanBones_Serialize_LeftMiddleDistal(f, value.LeftMiddleDistal); + } + + if(value.LeftRingProximal!=null){ + f.Key("leftRingProximal"); + __humanoid__humanBones_Serialize_LeftRingProximal(f, value.LeftRingProximal); + } + + if(value.LeftRingIntermediate!=null){ + f.Key("leftRingIntermediate"); + __humanoid__humanBones_Serialize_LeftRingIntermediate(f, value.LeftRingIntermediate); + } + + if(value.LeftRingDistal!=null){ + f.Key("leftRingDistal"); + __humanoid__humanBones_Serialize_LeftRingDistal(f, value.LeftRingDistal); + } + + if(value.LeftLittleProximal!=null){ + f.Key("leftLittleProximal"); + __humanoid__humanBones_Serialize_LeftLittleProximal(f, value.LeftLittleProximal); + } + + if(value.LeftLittleIntermediate!=null){ + f.Key("leftLittleIntermediate"); + __humanoid__humanBones_Serialize_LeftLittleIntermediate(f, value.LeftLittleIntermediate); + } + + if(value.LeftLittleDistal!=null){ + f.Key("leftLittleDistal"); + __humanoid__humanBones_Serialize_LeftLittleDistal(f, value.LeftLittleDistal); + } + + if(value.RightThumbMetacarpal!=null){ + f.Key("rightThumbMetacarpal"); + __humanoid__humanBones_Serialize_RightThumbMetacarpal(f, value.RightThumbMetacarpal); + } + + if(value.RightThumbProximal!=null){ + f.Key("rightThumbProximal"); + __humanoid__humanBones_Serialize_RightThumbProximal(f, value.RightThumbProximal); + } + + if(value.RightThumbDistal!=null){ + f.Key("rightThumbDistal"); + __humanoid__humanBones_Serialize_RightThumbDistal(f, value.RightThumbDistal); + } + + if(value.RightIndexProximal!=null){ + f.Key("rightIndexProximal"); + __humanoid__humanBones_Serialize_RightIndexProximal(f, value.RightIndexProximal); + } + + if(value.RightIndexIntermediate!=null){ + f.Key("rightIndexIntermediate"); + __humanoid__humanBones_Serialize_RightIndexIntermediate(f, value.RightIndexIntermediate); + } + + if(value.RightIndexDistal!=null){ + f.Key("rightIndexDistal"); + __humanoid__humanBones_Serialize_RightIndexDistal(f, value.RightIndexDistal); + } + + if(value.RightMiddleProximal!=null){ + f.Key("rightMiddleProximal"); + __humanoid__humanBones_Serialize_RightMiddleProximal(f, value.RightMiddleProximal); + } + + if(value.RightMiddleIntermediate!=null){ + f.Key("rightMiddleIntermediate"); + __humanoid__humanBones_Serialize_RightMiddleIntermediate(f, value.RightMiddleIntermediate); + } + + if(value.RightMiddleDistal!=null){ + f.Key("rightMiddleDistal"); + __humanoid__humanBones_Serialize_RightMiddleDistal(f, value.RightMiddleDistal); + } + + if(value.RightRingProximal!=null){ + f.Key("rightRingProximal"); + __humanoid__humanBones_Serialize_RightRingProximal(f, value.RightRingProximal); + } + + if(value.RightRingIntermediate!=null){ + f.Key("rightRingIntermediate"); + __humanoid__humanBones_Serialize_RightRingIntermediate(f, value.RightRingIntermediate); + } + + if(value.RightRingDistal!=null){ + f.Key("rightRingDistal"); + __humanoid__humanBones_Serialize_RightRingDistal(f, value.RightRingDistal); + } + + if(value.RightLittleProximal!=null){ + f.Key("rightLittleProximal"); + __humanoid__humanBones_Serialize_RightLittleProximal(f, value.RightLittleProximal); + } + + if(value.RightLittleIntermediate!=null){ + f.Key("rightLittleIntermediate"); + __humanoid__humanBones_Serialize_RightLittleIntermediate(f, value.RightLittleIntermediate); + } + + if(value.RightLittleDistal!=null){ + f.Key("rightLittleDistal"); + __humanoid__humanBones_Serialize_RightLittleDistal(f, value.RightLittleDistal); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Hips(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Spine(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Chest(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_UpperChest(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Neck(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Head(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftEye(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightEye(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_Jaw(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftUpperLeg(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLowerLeg(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftFoot(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftToes(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightUpperLeg(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLowerLeg(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightFoot(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightToes(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftShoulder(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftUpperArm(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLowerArm(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftHand(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightShoulder(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightUpperArm(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLowerArm(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightHand(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftThumbMetacarpal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftThumbProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftThumbDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftIndexProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftIndexIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftIndexDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftMiddleProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftMiddleIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftMiddleDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftRingProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftRingIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftRingDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLittleProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLittleIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_LeftLittleDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightThumbMetacarpal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightThumbProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightThumbDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightIndexProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightIndexIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightIndexDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightMiddleProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightMiddleIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightMiddleDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightRingProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightRingIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightRingDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLittleProximal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLittleIntermediate(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __humanoid__humanBones_Serialize_RightLittleDistal(JsonFormatter f, HumanBone value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_FirstPerson(JsonFormatter f, FirstPerson value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MeshAnnotations!=null&&value.MeshAnnotations.Count()>=1){ + f.Key("meshAnnotations"); + __firstPerson_Serialize_MeshAnnotations(f, value.MeshAnnotations); + } + + f.EndMap(); +} + +public static void __firstPerson_Serialize_MeshAnnotations(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __firstPerson_Serialize_MeshAnnotations_ITEM(f, item); + + } + f.EndList(); +} + +public static void __firstPerson_Serialize_MeshAnnotations_ITEM(JsonFormatter f, MeshAnnotation value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + f.EndMap(); +} + +public static void Serialize_LookAt(JsonFormatter f, LookAt value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.OffsetFromHeadBone!=null&&value.OffsetFromHeadBone.Count()>=3){ + f.Key("offsetFromHeadBone"); + __lookAt_Serialize_OffsetFromHeadBone(f, value.OffsetFromHeadBone); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.RangeMapHorizontalInner!=null){ + f.Key("rangeMapHorizontalInner"); + __lookAt_Serialize_RangeMapHorizontalInner(f, value.RangeMapHorizontalInner); + } + + if(value.RangeMapHorizontalOuter!=null){ + f.Key("rangeMapHorizontalOuter"); + __lookAt_Serialize_RangeMapHorizontalOuter(f, value.RangeMapHorizontalOuter); + } + + if(value.RangeMapVerticalDown!=null){ + f.Key("rangeMapVerticalDown"); + __lookAt_Serialize_RangeMapVerticalDown(f, value.RangeMapVerticalDown); + } + + if(value.RangeMapVerticalUp!=null){ + f.Key("rangeMapVerticalUp"); + __lookAt_Serialize_RangeMapVerticalUp(f, value.RangeMapVerticalUp); + } + + f.EndMap(); +} + +public static void __lookAt_Serialize_OffsetFromHeadBone(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __lookAt_Serialize_RangeMapHorizontalInner(JsonFormatter f, LookAtRangeMap value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.InputMaxValue.HasValue){ + f.Key("inputMaxValue"); + f.Value(value.InputMaxValue.GetValueOrDefault()); + } + + if(value.OutputScale.HasValue){ + f.Key("outputScale"); + f.Value(value.OutputScale.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __lookAt_Serialize_RangeMapHorizontalOuter(JsonFormatter f, LookAtRangeMap value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.InputMaxValue.HasValue){ + f.Key("inputMaxValue"); + f.Value(value.InputMaxValue.GetValueOrDefault()); + } + + if(value.OutputScale.HasValue){ + f.Key("outputScale"); + f.Value(value.OutputScale.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __lookAt_Serialize_RangeMapVerticalDown(JsonFormatter f, LookAtRangeMap value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.InputMaxValue.HasValue){ + f.Key("inputMaxValue"); + f.Value(value.InputMaxValue.GetValueOrDefault()); + } + + if(value.OutputScale.HasValue){ + f.Key("outputScale"); + f.Value(value.OutputScale.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __lookAt_Serialize_RangeMapVerticalUp(JsonFormatter f, LookAtRangeMap value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.InputMaxValue.HasValue){ + f.Key("inputMaxValue"); + f.Value(value.InputMaxValue.GetValueOrDefault()); + } + + if(value.OutputScale.HasValue){ + f.Key("outputScale"); + f.Value(value.OutputScale.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void Serialize_Expressions(JsonFormatter f, Expressions value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Preset!=null){ + f.Key("preset"); + __expressions_Serialize_Preset(f, value.Preset); + } + + if(value.Custom!=null&&value.Custom.Count()>0){ + f.Key("custom"); + __expressions_Serialize_Custom(f, value.Custom); + } + + f.EndMap(); +} + +public static void __expressions_Serialize_Preset(JsonFormatter f, Preset value) +{ + f.BeginMap(); + + + if(value.Happy!=null){ + f.Key("happy"); + __expressions__preset_Serialize_Happy(f, value.Happy); + } + + if(value.Angry!=null){ + f.Key("angry"); + __expressions__preset_Serialize_Angry(f, value.Angry); + } + + if(value.Sad!=null){ + f.Key("sad"); + __expressions__preset_Serialize_Sad(f, value.Sad); + } + + if(value.Relaxed!=null){ + f.Key("relaxed"); + __expressions__preset_Serialize_Relaxed(f, value.Relaxed); + } + + if(value.Surprised!=null){ + f.Key("surprised"); + __expressions__preset_Serialize_Surprised(f, value.Surprised); + } + + if(value.Aa!=null){ + f.Key("aa"); + __expressions__preset_Serialize_Aa(f, value.Aa); + } + + if(value.Ih!=null){ + f.Key("ih"); + __expressions__preset_Serialize_Ih(f, value.Ih); + } + + if(value.Ou!=null){ + f.Key("ou"); + __expressions__preset_Serialize_Ou(f, value.Ou); + } + + if(value.Ee!=null){ + f.Key("ee"); + __expressions__preset_Serialize_Ee(f, value.Ee); + } + + if(value.Oh!=null){ + f.Key("oh"); + __expressions__preset_Serialize_Oh(f, value.Oh); + } + + if(value.Blink!=null){ + f.Key("blink"); + __expressions__preset_Serialize_Blink(f, value.Blink); + } + + if(value.BlinkLeft!=null){ + f.Key("blinkLeft"); + __expressions__preset_Serialize_BlinkLeft(f, value.BlinkLeft); + } + + if(value.BlinkRight!=null){ + f.Key("blinkRight"); + __expressions__preset_Serialize_BlinkRight(f, value.BlinkRight); + } + + if(value.LookUp!=null){ + f.Key("lookUp"); + __expressions__preset_Serialize_LookUp(f, value.LookUp); + } + + if(value.LookDown!=null){ + f.Key("lookDown"); + __expressions__preset_Serialize_LookDown(f, value.LookDown); + } + + if(value.LookLeft!=null){ + f.Key("lookLeft"); + __expressions__preset_Serialize_LookLeft(f, value.LookLeft); + } + + if(value.LookRight!=null){ + f.Key("lookRight"); + __expressions__preset_Serialize_LookRight(f, value.LookRight); + } + + if(value.Neutral!=null){ + f.Key("neutral"); + __expressions__preset_Serialize_Neutral(f, value.Neutral); + } + + f.EndMap(); +} + +public static void __expressions__preset_Serialize_Happy(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__happy_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__happy_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__happy_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__happy_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__happy_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__happy_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__happy_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__happy_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__happy_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__happy__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__happy__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__happy_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__happy_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__happy_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__happy__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__happy__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__happy__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__happy__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Angry(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__angry_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__angry_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__angry_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__angry_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__angry_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__angry_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__angry_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__angry_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__angry_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__angry__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__angry__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__angry_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__angry_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__angry_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__angry__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__angry__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__angry__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__angry__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Sad(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__sad_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__sad_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__sad_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__sad_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__sad_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__sad_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__sad_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__sad_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__sad_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__sad__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__sad__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__sad_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__sad_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__sad_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__sad__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__sad__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__sad__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__sad__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Relaxed(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__relaxed_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__relaxed_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__relaxed_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__relaxed_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__relaxed_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__relaxed_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__relaxed_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__relaxed_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__relaxed_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__relaxed__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__relaxed__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__relaxed_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__relaxed_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__relaxed_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__relaxed__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__relaxed__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__relaxed__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__relaxed__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Surprised(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__surprised_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__surprised_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__surprised_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__surprised_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__surprised_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__surprised_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__surprised_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__surprised_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__surprised_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__surprised__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__surprised__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__surprised_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__surprised_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__surprised_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__surprised__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__surprised__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__surprised__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__surprised__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Aa(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__aa_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__aa_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__aa_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__aa_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__aa_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__aa_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__aa_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__aa_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__aa_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__aa__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__aa__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__aa_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__aa_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__aa_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__aa__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__aa__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__aa__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__aa__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Ih(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__ih_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__ih_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__ih_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__ih_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ih_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ih_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__ih_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ih_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ih_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__ih__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__ih__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__ih_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ih_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ih_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__ih__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__ih__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__ih__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__ih__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Ou(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__ou_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__ou_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__ou_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__ou_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ou_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ou_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__ou_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ou_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ou_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__ou__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__ou__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__ou_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ou_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ou_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__ou__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__ou__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__ou__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__ou__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Ee(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__ee_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__ee_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__ee_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__ee_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ee_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ee_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__ee_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ee_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ee_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__ee__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__ee__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__ee_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__ee_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__ee_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__ee__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__ee__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__ee__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__ee__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Oh(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__oh_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__oh_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__oh_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__oh_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__oh_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__oh_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__oh_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__oh_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__oh_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__oh__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__oh__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__oh_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__oh_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__oh_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__oh__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__oh__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__oh__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__oh__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Blink(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__blink_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__blink_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__blink_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__blink_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blink_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blink_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__blink_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blink_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blink_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__blink__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__blink__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__blink_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blink_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blink_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__blink__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__blink__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__blink__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__blink__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_BlinkLeft(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__blinkLeft_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__blinkLeft_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__blinkLeft_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__blinkLeft_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blinkLeft_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkLeft_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__blinkLeft_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blinkLeft_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkLeft_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__blinkLeft__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__blinkLeft__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkLeft_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blinkLeft_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkLeft_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__blinkLeft__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__blinkLeft__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__blinkLeft__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkLeft__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_BlinkRight(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__blinkRight_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__blinkRight_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__blinkRight_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__blinkRight_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blinkRight_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkRight_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__blinkRight_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blinkRight_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkRight_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__blinkRight__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__blinkRight__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkRight_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__blinkRight_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkRight_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__blinkRight__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__blinkRight__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__blinkRight__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__blinkRight__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_LookUp(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__lookUp_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__lookUp_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__lookUp_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookUp_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookUp_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookUp_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookUp_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookUp_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookUp_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__lookUp__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookUp__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookUp_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookUp_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookUp_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__lookUp__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__lookUp__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookUp__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookUp__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_LookDown(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__lookDown_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__lookDown_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__lookDown_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookDown_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookDown_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookDown_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookDown_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookDown_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookDown_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__lookDown__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookDown__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookDown_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookDown_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookDown_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__lookDown__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__lookDown__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookDown__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookDown__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_LookLeft(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__lookLeft_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__lookLeft_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__lookLeft_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookLeft_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookLeft_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookLeft_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookLeft_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookLeft_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookLeft_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__lookLeft__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookLeft__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookLeft_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookLeft_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookLeft_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__lookLeft__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__lookLeft__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookLeft__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookLeft__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_LookRight(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__lookRight_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__lookRight_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__lookRight_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookRight_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookRight_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookRight_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookRight_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookRight_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookRight_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__lookRight__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookRight__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookRight_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__lookRight_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookRight_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__lookRight__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__lookRight__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__lookRight__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__lookRight__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset_Serialize_Neutral(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__preset__neutral_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__preset__neutral_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__preset__neutral_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__preset__neutral_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__neutral_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__neutral_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__preset__neutral_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__neutral_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__neutral_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__preset__neutral__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__preset__neutral__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__neutral_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__preset__neutral_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__preset__neutral_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__preset__neutral__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__preset__neutral__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__preset__neutral__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__preset__neutral__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions_Serialize_Custom(JsonFormatter f, Dictionary value) +{ + f.BeginMap(); + + foreach(var kv in value) + { + f.Key(kv.Key); + __expressions_Serialize_Custom_ITEM(f, kv.Value); + + } + f.EndMap(); +} + +public static void __expressions_Serialize_Custom_ITEM(JsonFormatter f, Expression value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.MorphTargetBinds!=null&&value.MorphTargetBinds.Count()>=1){ + f.Key("morphTargetBinds"); + __expressions__custom_PROP_Serialize_MorphTargetBinds(f, value.MorphTargetBinds); + } + + if(value.MaterialColorBinds!=null&&value.MaterialColorBinds.Count()>=1){ + f.Key("materialColorBinds"); + __expressions__custom_PROP_Serialize_MaterialColorBinds(f, value.MaterialColorBinds); + } + + if(value.TextureTransformBinds!=null&&value.TextureTransformBinds.Count()>=1){ + f.Key("textureTransformBinds"); + __expressions__custom_PROP_Serialize_TextureTransformBinds(f, value.TextureTransformBinds); + } + + if(value.IsBinary.HasValue){ + f.Key("isBinary"); + f.Value(value.IsBinary.GetValueOrDefault()); + } + + if(true){ + f.Key("overrideBlink"); + f.Value(value.OverrideBlink.ToString()); + } + + if(true){ + f.Key("overrideLookAt"); + f.Value(value.OverrideLookAt.ToString()); + } + + if(true){ + f.Key("overrideMouth"); + f.Value(value.OverrideMouth.ToString()); + } + + f.EndMap(); +} + +public static void __expressions__custom_PROP_Serialize_MorphTargetBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__custom_PROP_Serialize_MorphTargetBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__custom_PROP_Serialize_MorphTargetBinds_ITEM(JsonFormatter f, MorphTargetBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Index.HasValue){ + f.Key("index"); + f.Value(value.Index.GetValueOrDefault()); + } + + if(value.Weight.HasValue){ + f.Key("weight"); + f.Value(value.Weight.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __expressions__custom_PROP_Serialize_MaterialColorBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__custom_PROP_Serialize_MaterialColorBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__custom_PROP_Serialize_MaterialColorBinds_ITEM(JsonFormatter f, MaterialColorBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(true){ + f.Key("type"); + f.Value(value.Type.ToString()); + } + + if(value.TargetValue!=null&&value.TargetValue.Count()>=4){ + f.Key("targetValue"); + __expressions__custom_PROP__materialColorBinds_ITEM_Serialize_TargetValue(f, value.TargetValue); + } + + f.EndMap(); +} + +public static void __expressions__custom_PROP__materialColorBinds_ITEM_Serialize_TargetValue(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__custom_PROP_Serialize_TextureTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + __expressions__custom_PROP_Serialize_TextureTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void __expressions__custom_PROP_Serialize_TextureTransformBinds_ITEM(JsonFormatter f, TextureTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Material.HasValue){ + f.Key("material"); + f.Value(value.Material.GetValueOrDefault()); + } + + if(value.Scale!=null&&value.Scale.Count()>=2){ + f.Key("scale"); + __expressions__custom_PROP__textureTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Offset!=null&&value.Offset.Count()>=2){ + f.Key("offset"); + __expressions__custom_PROP__textureTransformBinds_ITEM_Serialize_Offset(f, value.Offset); + } + + f.EndMap(); +} + +public static void __expressions__custom_PROP__textureTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __expressions__custom_PROP__textureTransformBinds_ITEM_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + + } // class +} // namespace diff --git a/Assets/External/VRM10/Runtime/Format/Vrm/Serializer.g.cs.meta b/Assets/External/VRM10/Runtime/Format/Vrm/Serializer.g.cs.meta new file mode 100644 index 000000000..d341b52ed --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/Vrm/Serializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 403738647bdb9aa498164cd295ff64d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones.meta b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones.meta new file mode 100644 index 000000000..32205523a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d41602604884abc8efd1db9e40d3ae7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneAttribute.cs b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneAttribute.cs new file mode 100644 index 000000000..f0a4747cd --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneAttribute.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public readonly struct Vrm10HumanoidBoneAttribute + { + public Vrm10HumanoidBones Bone { get; } + public bool IsRequired { get; } + public Vrm10HumanoidBones? ParentBone { get; } + public bool? NeedsParentBone { get; } + public HumanBodyBones UnityBone { get; } + + public Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones bone, bool isRequired, Vrm10HumanoidBones? parentBone, bool? needsParentBone, HumanBodyBones unityBone) + { + Bone = bone; + IsRequired = isRequired; + ParentBone = parentBone; + NeedsParentBone = needsParentBone; + UnityBone = unityBone; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneAttribute.cs.meta b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneAttribute.cs.meta new file mode 100644 index 000000000..c2e102754 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6176458f360143afa76a2500e1e3a968 +timeCreated: 1673690667 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneSpecification.cs b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneSpecification.cs new file mode 100644 index 000000000..80017eddf --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneSpecification.cs @@ -0,0 +1,111 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniVRM10 +{ + public sealed class Vrm10HumanoidBoneSpecification + { + /// + /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/humanoid.md + /// + private readonly List _specification = new List + { + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.Hips, true, null, null, HumanBodyBones.Hips), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.Spine, true, Vrm10HumanoidBones.Hips, null, HumanBodyBones.Spine), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.Chest, false, Vrm10HumanoidBones.Spine, null, HumanBodyBones.Chest), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.UpperChest, false, Vrm10HumanoidBones.Chest, true, HumanBodyBones.UpperChest), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.Neck, false, Vrm10HumanoidBones.UpperChest, false, HumanBodyBones.Neck), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.Head, true, Vrm10HumanoidBones.Neck, false, HumanBodyBones.Head), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftEye, false, Vrm10HumanoidBones.Head, null, HumanBodyBones.LeftEye), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightEye, false, Vrm10HumanoidBones.Head, null, HumanBodyBones.RightEye), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.Jaw, false, Vrm10HumanoidBones.Head, null, HumanBodyBones.Jaw), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftUpperLeg, true, Vrm10HumanoidBones.Hips, null, HumanBodyBones.LeftUpperLeg), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftLowerLeg, true, Vrm10HumanoidBones.LeftUpperLeg, null, HumanBodyBones.LeftLowerLeg), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftFoot, true, Vrm10HumanoidBones.LeftLowerLeg, null, HumanBodyBones.LeftFoot), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftToes, false, Vrm10HumanoidBones.LeftFoot, null, HumanBodyBones.LeftToes), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightUpperLeg, true, Vrm10HumanoidBones.Hips, null, HumanBodyBones.RightUpperLeg), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightLowerLeg, true, Vrm10HumanoidBones.RightUpperLeg, null, HumanBodyBones.RightLowerLeg), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightFoot, true, Vrm10HumanoidBones.RightLowerLeg, null, HumanBodyBones.RightFoot), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightToes, false, Vrm10HumanoidBones.RightFoot, null, HumanBodyBones.RightToes), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftShoulder, false, Vrm10HumanoidBones.UpperChest, false, HumanBodyBones.LeftShoulder), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftUpperArm, true, Vrm10HumanoidBones.LeftShoulder, false, HumanBodyBones.LeftUpperArm), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftLowerArm, true, Vrm10HumanoidBones.LeftUpperArm, null, HumanBodyBones.LeftLowerArm), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftHand, true, Vrm10HumanoidBones.LeftLowerArm, null, HumanBodyBones.LeftHand), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightShoulder, false, Vrm10HumanoidBones.UpperChest, false, HumanBodyBones.RightShoulder), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightUpperArm, true, Vrm10HumanoidBones.RightShoulder, false, HumanBodyBones.RightUpperArm), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightLowerArm, true, Vrm10HumanoidBones.RightUpperArm, null, HumanBodyBones.RightLowerArm), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightHand, true, Vrm10HumanoidBones.RightLowerArm, null, HumanBodyBones.RightHand), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftThumbMetacarpal, false, Vrm10HumanoidBones.LeftHand, null, HumanBodyBones.LeftThumbProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftThumbProximal, false, Vrm10HumanoidBones.LeftThumbMetacarpal, true, HumanBodyBones.LeftThumbIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftThumbDistal, false, Vrm10HumanoidBones.LeftThumbProximal, true, HumanBodyBones.LeftThumbDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftIndexProximal, false, Vrm10HumanoidBones.LeftHand, null, HumanBodyBones.LeftIndexProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftIndexIntermediate, false, Vrm10HumanoidBones.LeftIndexProximal, true, HumanBodyBones.LeftIndexIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftIndexDistal, false, Vrm10HumanoidBones.LeftIndexIntermediate, true, HumanBodyBones.LeftIndexDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftMiddleProximal, false, Vrm10HumanoidBones.LeftHand, null, HumanBodyBones.LeftMiddleProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftMiddleIntermediate, false, Vrm10HumanoidBones.LeftMiddleProximal, true, HumanBodyBones.LeftMiddleIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftMiddleDistal, false, Vrm10HumanoidBones.LeftMiddleIntermediate, true, HumanBodyBones.LeftMiddleDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftRingProximal, false, Vrm10HumanoidBones.LeftHand, null, HumanBodyBones.LeftRingProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftRingIntermediate, false, Vrm10HumanoidBones.LeftRingProximal, true, HumanBodyBones.LeftRingIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftRingDistal, false, Vrm10HumanoidBones.LeftRingIntermediate, true, HumanBodyBones.LeftRingDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftLittleProximal, false, Vrm10HumanoidBones.LeftHand, null, HumanBodyBones.LeftLittleProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftLittleIntermediate, false, Vrm10HumanoidBones.LeftLittleProximal, true, HumanBodyBones.LeftLittleIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.LeftLittleDistal, false, Vrm10HumanoidBones.LeftLittleIntermediate, true, HumanBodyBones.LeftLittleDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightThumbMetacarpal, false, Vrm10HumanoidBones.RightHand, null, HumanBodyBones.RightThumbProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightThumbProximal, false, Vrm10HumanoidBones.RightThumbMetacarpal, true, HumanBodyBones.RightThumbIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightThumbDistal, false, Vrm10HumanoidBones.RightThumbProximal, true, HumanBodyBones.RightThumbDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightIndexProximal, false, Vrm10HumanoidBones.RightHand, null, HumanBodyBones.RightIndexProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightIndexIntermediate, false, Vrm10HumanoidBones.RightIndexProximal, true, HumanBodyBones.RightIndexIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightIndexDistal, false, Vrm10HumanoidBones.RightIndexIntermediate, true, HumanBodyBones.RightIndexDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightMiddleProximal, false, Vrm10HumanoidBones.RightHand, null, HumanBodyBones.RightMiddleProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightMiddleIntermediate, false, Vrm10HumanoidBones.RightMiddleProximal, true, HumanBodyBones.RightMiddleIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightMiddleDistal, false, Vrm10HumanoidBones.RightMiddleIntermediate, true, HumanBodyBones.RightMiddleDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightRingProximal, false, Vrm10HumanoidBones.RightHand, null, HumanBodyBones.RightRingProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightRingIntermediate, false, Vrm10HumanoidBones.RightRingProximal, true, HumanBodyBones.RightRingIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightRingDistal, false, Vrm10HumanoidBones.RightRingIntermediate, true, HumanBodyBones.RightRingDistal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightLittleProximal, false, Vrm10HumanoidBones.RightHand, null, HumanBodyBones.RightLittleProximal), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightLittleIntermediate, false, Vrm10HumanoidBones.RightLittleProximal, true, HumanBodyBones.RightLittleIntermediate), + new Vrm10HumanoidBoneAttribute(Vrm10HumanoidBones.RightLittleDistal, false, Vrm10HumanoidBones.RightLittleIntermediate, true, HumanBodyBones.RightLittleDistal), + }; + + private readonly Dictionary _specDictionary; + private readonly Dictionary _toUnity; + private readonly Dictionary _fromUnity; + + private Vrm10HumanoidBoneSpecification() + { + _specDictionary = _specification.ToDictionary(x => x.Bone, x => x); + _toUnity = _specification.ToDictionary(x => x.Bone, x => x.UnityBone); + _fromUnity = _specification.ToDictionary(x => x.UnityBone, x => x.Bone); + } + + private static Vrm10HumanoidBoneSpecification _instance; + + private static Vrm10HumanoidBoneSpecification Instance + { + get + { + if (_instance == null) + { + _instance = new Vrm10HumanoidBoneSpecification(); + } + return _instance; + } + } + + public static Vrm10HumanoidBoneAttribute GetDefine(Vrm10HumanoidBones bone) + { + return Instance._specDictionary[bone]; + } + + public static HumanBodyBones ConvertToUnityBone(Vrm10HumanoidBones bone) + { + return Instance._toUnity[bone]; + } + + public static Vrm10HumanoidBones ConvertFromUnityBone(HumanBodyBones bone) + { + return Instance._fromUnity[bone]; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneSpecification.cs.meta b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneSpecification.cs.meta new file mode 100644 index 000000000..8363e8482 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBoneSpecification.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 70b2781f30154b7aa8a7d3235934c00f +timeCreated: 1673714163 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBones.cs b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBones.cs new file mode 100644 index 000000000..10bbabd08 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBones.cs @@ -0,0 +1,64 @@ +namespace UniVRM10 +{ + /// + /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/humanoid.md + /// + public enum Vrm10HumanoidBones + { + Hips = 0, + Spine, + Chest, + UpperChest, + Neck, + Head, + LeftEye, + RightEye, + Jaw, + LeftUpperLeg, + LeftLowerLeg, + LeftFoot, + LeftToes, + RightUpperLeg, + RightLowerLeg, + RightFoot, + RightToes, + LeftShoulder, + LeftUpperArm, + LeftLowerArm, + LeftHand, + RightShoulder, + RightUpperArm, + RightLowerArm, + RightHand, + LeftThumbMetacarpal, + LeftThumbProximal, + LeftThumbDistal, + LeftIndexProximal, + LeftIndexIntermediate, + LeftIndexDistal, + LeftMiddleProximal, + LeftMiddleIntermediate, + LeftMiddleDistal, + LeftRingProximal, + LeftRingIntermediate, + LeftRingDistal, + LeftLittleProximal, + LeftLittleIntermediate, + LeftLittleDistal, + RightThumbMetacarpal, + RightThumbProximal, + RightThumbDistal, + RightIndexProximal, + RightIndexIntermediate, + RightIndexDistal, + RightMiddleProximal, + RightMiddleIntermediate, + RightMiddleDistal, + RightRingProximal, + RightRingIntermediate, + RightRingDistal, + RightLittleProximal, + RightLittleIntermediate, + RightLittleDistal, + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBones.cs.meta b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBones.cs.meta new file mode 100644 index 000000000..7e1024dd1 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Format/VrmHumanoidBones/Vrm10HumanoidBones.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bbfd7fe4e8e94aa980418d1cb30163cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO.meta b/Assets/External/VRM10/Runtime/IO.meta new file mode 100644 index 000000000..543d49c01 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c428532d152f9674c8b71ba2b7e23046 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/ArrayExtensions.cs b/Assets/External/VRM10/Runtime/IO/ArrayExtensions.cs new file mode 100644 index 000000000..24fb337ff --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/ArrayExtensions.cs @@ -0,0 +1,33 @@ +using System; +using UnityEngine; + +namespace UniVRM10 +{ + public static class ArrayExtensions + { + public static Vector3 ToVector3(this float[] src, Vector3 defaultValue = default) + { + if (src.Length != 3) return defaultValue; + + var v = new Vector3(); + v.x = src[0]; + v.y = src[1]; + v.z = src[2]; + return v; + } + + public static Quaternion ToQuaternion(this float[] src) + { + if (src.Length != 4) return Quaternion.identity; + + var v = new Quaternion(src[0], src[1], src[2], src[3]); + return v; + } + + public static T Get(this ArraySegment self, int i) + { + var index = self.Offset + i; + return self.Array[index]; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/ArrayExtensions.cs.meta b/Assets/External/VRM10/Runtime/IO/ArrayExtensions.cs.meta new file mode 100644 index 000000000..bab0eef1f --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/ArrayExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c6a95a2c709aee47aa1bad5943c2aa7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/ExpressionExtensions.cs b/Assets/External/VRM10/Runtime/IO/ExpressionExtensions.cs new file mode 100644 index 000000000..189c60547 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/ExpressionExtensions.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using UniGLTF.Extensions.VRMC_vrm; +using UnityEngine; + +namespace UniVRM10 +{ + public static class ExpressionExtensions + { + public static UniVRM10.MorphTargetBinding Build10(this MorphTargetBind bind, GameObject root, Vrm10Importer.ModelMap loader, VrmLib.Model model) + { + var libNode = model.Nodes[bind.Node.Value]; + var node = loader.Nodes[libNode].transform; + var mesh = loader.Meshes[libNode.MeshGroup]; + var relativePath = node.RelativePathFrom(root.transform); + return new UniVRM10.MorphTargetBinding(relativePath, bind.Index.Value, bind.Weight.Value); + } + + public static UniVRM10.MaterialColorBinding? Build10(this MaterialColorBind bind, IReadOnlyList materials) + { + var value = new Vector4(bind.TargetValue[0], bind.TargetValue[1], bind.TargetValue[2], bind.TargetValue[3]); + var material = materials[bind.Material.Value].Asset; + + var binding = default(UniVRM10.MaterialColorBinding?); + if (material != null) + { + try + { + binding = new UniVRM10.MaterialColorBinding + { + MaterialName = material.name, // 名前で持つべき? + BindType = bind.Type, + TargetValue = value, + // BaseValue = material.GetColor(kv.Key), + }; + } + catch (Exception) + { + // do nothing + } + } + return binding; + } + + public static UniVRM10.MaterialUVBinding? Build10(this TextureTransformBind bind, IReadOnlyList materials) + { + var material = materials[bind.Material.Value].Asset; + + var binding = default(UniVRM10.MaterialUVBinding?); + if (material != null) + { + var (scale, offset) = UniGLTF.TextureTransform.VerticalFlipScaleOffset(new Vector2(bind.Scale[0], bind.Scale[1]), new Vector2(bind.Offset[0], bind.Offset[1])); + + try + { + binding = new UniVRM10.MaterialUVBinding + { + MaterialName = material.name, // 名前で持つべき + Scaling = scale, + Offset = offset, + }; + } + catch (Exception) + { + // do nothing + } + } + return binding; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/ExpressionExtensions.cs.meta b/Assets/External/VRM10/Runtime/IO/ExpressionExtensions.cs.meta new file mode 100644 index 000000000..7cb87e6f5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/ExpressionExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c93dae149b843ca46b028b4e4d845c89 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/IndexExtensions.cs b/Assets/External/VRM10/Runtime/IO/IndexExtensions.cs new file mode 100644 index 000000000..d305bd25d --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/IndexExtensions.cs @@ -0,0 +1,44 @@ +namespace UniVRM10 +{ + public static class IndexExtensions + { + public static bool TryGetValidIndex(this int value, int count, out int index) + { + if (value < 0) + { + index = -1; + return false; + } + if (value >= count) + { + index = -1; + return false; + } + + index = value; + return true; + } + + public static bool TryGetValidIndex(this int? value, int count, out int index) + { + if (!value.HasValue) + { + index = -1; + return false; + } + if (value < 0) + { + index = -1; + return false; + } + if (value >= count) + { + index = -1; + return false; + } + + index = value.Value; + return true; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/IndexExtensions.cs.meta b/Assets/External/VRM10/Runtime/IO/IndexExtensions.cs.meta new file mode 100644 index 000000000..cf2062b6f --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/IndexExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3db2e2e2c91b966408fc5ab9803292c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Material.meta b/Assets/External/VRM10/Runtime/IO/Material.meta new file mode 100644 index 000000000..d27e00987 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c6dd47f5c9a46a9a3b26b40a28a52b3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP.meta new file mode 100644 index 000000000..82bc3ef41 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ee4969a428884c25a89b5e5e6db72e14 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export.meta new file mode 100644 index 000000000..56bcb363b --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 48ae52bce69c4f68a97461a4f52ca46e +timeCreated: 1667544324 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/BuiltInVrm10MaterialExporter.cs b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/BuiltInVrm10MaterialExporter.cs new file mode 100644 index 000000000..9f24619d8 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/BuiltInVrm10MaterialExporter.cs @@ -0,0 +1,23 @@ +using UniGLTF; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + public class BuiltInVrm10MaterialExporter : IMaterialExporter + { + private readonly BuiltInGltfMaterialExporter _gltfExporter = new BuiltInGltfMaterialExporter(); + + public glTFMaterial ExportMaterial(Material m, ITextureExporter textureExporter, GltfExportSettings settings) + { + if (BuiltInVrm10MToonMaterialExporter.TryExportMaterialAsMToon(m, textureExporter, out var dst)) + { + return dst; + } + else + { + return _gltfExporter.ExportMaterial(m, textureExporter, settings); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/BuiltInVrm10MaterialExporter.cs.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/BuiltInVrm10MaterialExporter.cs.meta new file mode 100644 index 000000000..cb3f26adf --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/BuiltInVrm10MaterialExporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6eeec83f2a72884dae19571cf1d749b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials.meta new file mode 100644 index 000000000..76c0be0bf --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9471ebdc1b724bccaff0223a9d20070e +timeCreated: 1667544340 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials/BuiltInVrm10MToonMaterialExporter.cs b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials/BuiltInVrm10MToonMaterialExporter.cs new file mode 100644 index 000000000..93b5ebc1d --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials/BuiltInVrm10MToonMaterialExporter.cs @@ -0,0 +1,208 @@ +using System; +using UniGLTF; +using UniGLTF.Extensions.VRMC_materials_mtoon; +using UnityEngine; +using VRMShaders; +using VRMShaders.VRM10.MToon10.Runtime; +using ColorSpace = VRMShaders.ColorSpace; + +namespace UniVRM10 +{ + public static class BuiltInVrm10MToonMaterialExporter + { + public static bool TryExportMaterialAsMToon(Material src, ITextureExporter textureExporter, out glTFMaterial dst) + { + if (src.shader.name != MToon10Meta.UnityShaderName) + { + dst = null; + return false; + } + + // Get MToon10 Context + var context = new MToon10Context(src); + context.Validate(); + + // base material + dst = glTF_KHR_materials_unlit.CreateDefault(); + dst.name = src.name; + + // vrmc_materials_mtoon ext + var mtoon = new UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon(); + mtoon.SpecVersion = Vrm10Exporter.MTOON_SPEC_VERSION; + + // Rendering + dst.alphaMode = ExportAlphaMode(context.AlphaMode); + mtoon.TransparentWithZWrite = context.TransparentWithZWriteMode == MToon10TransparentWithZWriteMode.On; + dst.alphaCutoff = Mathf.Max(0, context.AlphaCutoff); + mtoon.RenderQueueOffsetNumber = context.RenderQueueOffsetNumber; + dst.doubleSided = context.DoubleSidedMode == MToon10DoubleSidedMode.On; + + // Lighting + dst.pbrMetallicRoughness = new glTFPbrMetallicRoughness(); + dst.pbrMetallicRoughness.baseColorFactor = context.BaseColorFactorSrgb.ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); + var baseColorTextureIndex = textureExporter.RegisterExportingAsSRgb(context.BaseColorTexture, context.AlphaMode != MToon10AlphaMode.Opaque); + if (baseColorTextureIndex != -1) + { + dst.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo + { + index = baseColorTextureIndex, + }; + } + mtoon.ShadeColorFactor = context.ShadeColorFactorSrgb.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear); + var shadeColorTextureIndex = textureExporter.RegisterExportingAsSRgb(context.ShadeColorTexture, needsAlpha: false); + if (shadeColorTextureIndex != -1) + { + mtoon.ShadeMultiplyTexture = new TextureInfo + { + Index = shadeColorTextureIndex, + }; + } + var normalTextureIndex = textureExporter.RegisterExportingAsNormal(context.NormalTexture); + if (normalTextureIndex != -1) + { + dst.normalTexture = new glTFMaterialNormalTextureInfo + { + index = normalTextureIndex, + scale = context.NormalTextureScale, + }; + } + mtoon.ShadingShiftFactor = context.ShadingShiftFactor; + var shadingShiftTextureIndex = textureExporter.RegisterExportingAsLinear(context.ShadingShiftTexture, needsAlpha: false); + if (shadingShiftTextureIndex != -1) + { + mtoon.ShadingShiftTexture = new ShadingShiftTextureInfo + { + Index = shadingShiftTextureIndex, + Scale = context.ShadingShiftTextureScale, + }; + } + mtoon.ShadingToonyFactor = context.ShadingToonyFactor; + + // GI + mtoon.GiEqualizationFactor = context.GiEqualizationFactor; + + // Emission + // Emissive factor is stored in Linear space + var emissiveFactor = context.EmissiveFactorLinear; + var maxColorComponent = emissiveFactor.maxColorComponent; + if (maxColorComponent > 1.0f) + { + UniGLTF.glTF_KHR_materials_emissive_strength.Serialize(ref dst.extensions, maxColorComponent); + emissiveFactor /= maxColorComponent; + } + dst.emissiveFactor = emissiveFactor.ToFloat3(ColorSpace.Linear, ColorSpace.Linear); + var emissiveTextureIndex = textureExporter.RegisterExportingAsSRgb(context.EmissiveTexture, needsAlpha: false); + if (emissiveTextureIndex != -1) + { + dst.emissiveTexture = new glTFMaterialEmissiveTextureInfo + { + index = emissiveTextureIndex, + }; + } + + // Rim Lighting + mtoon.MatcapFactor = context.MatcapColorFactorSrgb.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear); + var matcapTextureIndex = textureExporter.RegisterExportingAsSRgb(context.MatcapTexture, needsAlpha: false); + if (matcapTextureIndex != -1) + { + mtoon.MatcapTexture = new TextureInfo + { + Index = matcapTextureIndex, + }; + } + + mtoon.ParametricRimColorFactor = context.ParametricRimColorFactorSrgb.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear); + mtoon.ParametricRimFresnelPowerFactor = context.ParametricRimFresnelPowerFactor; + mtoon.ParametricRimLiftFactor = context.ParametricRimLiftFactor; + var rimMultiplyTextureIndex = textureExporter.RegisterExportingAsSRgb(context.RimMultiplyTexture, needsAlpha: false); + if (rimMultiplyTextureIndex != -1) + { + mtoon.RimMultiplyTexture = new TextureInfo + { + Index = rimMultiplyTextureIndex, + }; + } + mtoon.RimLightingMixFactor = context.RimLightingMixFactor; + + // Outline + mtoon.OutlineWidthMode = ExportOutlineWidthMode(context.OutlineWidthMode); + mtoon.OutlineWidthFactor = context.OutlineWidthFactor; + var outlineWidthMultiplyTextureIndex = textureExporter.RegisterExportingAsLinear(context.OutlineWidthMultiplyTexture, needsAlpha: false); + if (outlineWidthMultiplyTextureIndex != -1) + { + mtoon.OutlineWidthMultiplyTexture = new TextureInfo + { + Index = outlineWidthMultiplyTextureIndex, + }; + } + mtoon.OutlineColorFactor = context.OutlineColorFactorSrgb.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear); + mtoon.OutlineLightingMixFactor = context.OutlineLightingMixFactor; + + // UV Animation + var uvAnimationMaskTextureIndex = textureExporter.RegisterExportingAsLinear(context.UvAnimationMaskTexture, needsAlpha: false); + if (uvAnimationMaskTextureIndex != -1) + { + mtoon.UvAnimationMaskTexture = new TextureInfo + { + Index = uvAnimationMaskTextureIndex, + }; + } + mtoon.UvAnimationScrollXSpeedFactor = context.UvAnimationScrollXSpeedFactor; + { + // Coordinate Conversion + const float invertY = -1f; + mtoon.UvAnimationScrollYSpeedFactor = context.UvAnimationScrollYSpeedFactor * invertY; + } + // Speed unit Conversion + const float rotationPerSecToRadianPerSec = Mathf.PI * 2f; + mtoon.UvAnimationRotationSpeedFactor = context.UvAnimationRotationSpeedFactor * rotationPerSecToRadianPerSec; + + // Texture Transforms + var scale = context.TextureScale; + var offset = context.TextureOffset; + Vrm10MaterialExportUtils.ExportTextureTransform(dst.pbrMetallicRoughness.baseColorTexture, scale, offset); + Vrm10MaterialExportUtils.ExportTextureTransform(dst.emissiveTexture, scale, offset); + Vrm10MaterialExportUtils.ExportTextureTransform(dst.normalTexture, scale, offset); + Vrm10MaterialExportUtils.ExportTextureTransform(mtoon.ShadeMultiplyTexture, scale, offset); + Vrm10MaterialExportUtils.ExportTextureTransform(mtoon.ShadingShiftTexture, scale, offset); + Vrm10MaterialExportUtils.ExportTextureTransform(mtoon.MatcapTexture, scale, offset); + Vrm10MaterialExportUtils.ExportTextureTransform(mtoon.RimMultiplyTexture, scale, offset); + Vrm10MaterialExportUtils.ExportTextureTransform(mtoon.OutlineWidthMultiplyTexture, scale, offset); + Vrm10MaterialExportUtils.ExportTextureTransform(mtoon.UvAnimationMaskTexture, scale, offset); + + UniGLTF.Extensions.VRMC_materials_mtoon.GltfSerializer.SerializeTo(ref dst.extensions, mtoon); + + return true; + } + + private static string ExportAlphaMode(MToon10AlphaMode alphaMode) + { + switch (alphaMode) + { + case MToon10AlphaMode.Opaque: + return "OPAQUE"; + case MToon10AlphaMode.Cutout: + return "MASK"; + case MToon10AlphaMode.Transparent: + return "BLEND"; + default: + throw new ArgumentOutOfRangeException(nameof(alphaMode), alphaMode, null); + } + } + + private static OutlineWidthMode ExportOutlineWidthMode(MToon10OutlineMode mode) + { + switch (mode) + { + case MToon10OutlineMode.None: + return OutlineWidthMode.none; + case MToon10OutlineMode.World: + return OutlineWidthMode.worldCoordinates; + case MToon10OutlineMode.Screen: + return OutlineWidthMode.screenCoordinates; + default: + throw new ArgumentOutOfRangeException(nameof(mode), mode, null); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials/BuiltInVrm10MToonMaterialExporter.cs.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials/BuiltInVrm10MToonMaterialExporter.cs.meta new file mode 100644 index 000000000..f52f856b1 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials/BuiltInVrm10MToonMaterialExporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 83b9443cb6d94771a7e0090baefa80ee +timeCreated: 1620981552 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import.meta new file mode 100644 index 000000000..56170b0c3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b100c9d06dda49ed91afa6b2c2cebc06 +timeCreated: 1667544368 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/BuiltInVrm10MaterialDescriptorGenerator.cs b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/BuiltInVrm10MaterialDescriptorGenerator.cs new file mode 100644 index 000000000..4e947844b --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/BuiltInVrm10MaterialDescriptorGenerator.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using UniGLTF; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + public sealed class BuiltInVrm10MaterialDescriptorGenerator : IMaterialDescriptorGenerator + { + public MaterialDescriptor Get(GltfData data, int i) + { + // mtoon + if (BuiltInVrm10MToonMaterialImporter.TryCreateParam(data, i, out MaterialDescriptor matDesc)) return matDesc; + // unlit + if (BuiltInGltfUnlitMaterialImporter.TryCreateParam(data, i, out matDesc)) return matDesc; + // pbr + if (BuiltInGltfPbrMaterialImporter.TryCreateParam(data, i, out matDesc)) return matDesc; + + // fallback + if (Symbols.VRM_DEVELOP) + { + Debug.LogWarning($"material: {i} out of range. fallback"); + } + return new MaterialDescriptor( + GltfMaterialImportUtils.ImportMaterialName(i, null), + BuiltInGltfPbrMaterialImporter.Shader, + null, + new Dictionary(), + new Dictionary(), + new Dictionary(), + new Dictionary(), + new Action[]{}); + } + + public MaterialDescriptor GetGltfDefault() + { + return BuiltInGltfDefaultMaterialImporter.CreateParam(); + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/BuiltInVrm10MaterialDescriptorGenerator.cs.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/BuiltInVrm10MaterialDescriptorGenerator.cs.meta new file mode 100644 index 000000000..4065f3f76 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/BuiltInVrm10MaterialDescriptorGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb1910407057aeb49b63358cea33b09f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials.meta new file mode 100644 index 000000000..85fedab14 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0361e8fb0fb84326ada30f8c5cc7b665 +timeCreated: 1667544400 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs new file mode 100644 index 000000000..b7ba7a563 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs @@ -0,0 +1,300 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UniGLTF.Extensions.VRMC_materials_mtoon; +using UnityEngine; +using VRMShaders; +using VRMShaders.VRM10.MToon10.Runtime; +using ColorSpace = VRMShaders.ColorSpace; +using OutlineWidthMode = UniGLTF.Extensions.VRMC_materials_mtoon.OutlineWidthMode; + +namespace UniVRM10 +{ + /// + /// Convert MToon parameters from glTF specification to Unity implementation. + /// + public static class BuiltInVrm10MToonMaterialImporter + { + /// + /// VMRC_materials_mtoon の場合にマテリアル生成情報を作成する + /// + public static bool TryCreateParam(GltfData data, int i, out MaterialDescriptor matDesc) + { + var m = data.GLTF.materials[i]; + if (!UniGLTF.Extensions.VRMC_materials_mtoon.GltfDeserializer.TryGet(m.extensions, + out UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon mtoon)) + { + // Fallback to glTF, when MToon extension does not exist. + matDesc = default; + return false; + } + + // use material.name, because material name may renamed in GltfParser. + matDesc = new MaterialDescriptor( + m.name, + Shader.Find(MToon10Meta.UnityShaderName), + null, + Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2), + TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), + TryGetAllColors(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), + TryGetAllFloatArrays(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), + new Action[] + { + material => + { + // Set hidden properties, keywords from float properties. + new MToonValidator(material).Validate(); + } + }); + + return true; + } + + public static IEnumerable<(string key, Color value)> TryGetAllColors(glTFMaterial material, VRMC_materials_mtoon mToon) + { + const ColorSpace gltfColorSpace = ColorSpace.Linear; + + // Rendering + var baseColor = material?.pbrMetallicRoughness?.baseColorFactor?.ToColor4(gltfColorSpace, ColorSpace.sRGB); + if (baseColor.HasValue) + { + yield return (MToon10Prop.BaseColorFactor.ToUnityShaderLabName(), baseColor.Value); + } + + // Lighting + var shadeColor = mToon?.ShadeColorFactor?.ToColor3(gltfColorSpace, ColorSpace.sRGB); + if (shadeColor.HasValue) + { + yield return (MToon10Prop.ShadeColorFactor.ToUnityShaderLabName(), shadeColor.Value); + } + + // GI + + // Emission + // Emissive factor should be stored in Linear space + var emissionColor = material?.emissiveFactor?.ToColor3(gltfColorSpace, ColorSpace.Linear); + if (emissionColor.HasValue) + { + yield return (MToon10Prop.EmissiveFactor.ToUnityShaderLabName(), emissionColor.Value); + } + + // Matcap + var matcapColor = mToon?.MatcapFactor?.ToColor3(gltfColorSpace, ColorSpace.sRGB); + if (matcapColor.HasValue) + { + yield return (MToon10Prop.MatcapColorFactor.ToUnityShaderLabName(), matcapColor.Value); + } + + // Rim Lighting + var rimColor = mToon?.ParametricRimColorFactor?.ToColor3(gltfColorSpace, ColorSpace.sRGB); + if (rimColor.HasValue) + { + yield return (MToon10Prop.ParametricRimColorFactor.ToUnityShaderLabName(), rimColor.Value); + } + + // Outline + var outlineColor = mToon?.OutlineColorFactor?.ToColor3(gltfColorSpace, ColorSpace.sRGB); + if (outlineColor.HasValue) + { + yield return (MToon10Prop.OutlineColorFactor.ToUnityShaderLabName(), outlineColor.Value); + } + + // UV Animation + } + + public static IEnumerable<(string key, float value)> TryGetAllFloats(glTFMaterial material, VRMC_materials_mtoon mToon) + { + // Rendering + var alphaMode = GetMToon10AlphaMode(material); + { + yield return (MToon10Prop.AlphaMode.ToUnityShaderLabName(), (float)alphaMode); + } + + var transparentWithZWrite = GetMToon10TransparentWithZWriteMode(material, mToon); + { + yield return (MToon10Prop.TransparentWithZWrite.ToUnityShaderLabName(), (float)transparentWithZWrite); + } + + var cutoff = material?.alphaCutoff; + if (cutoff.HasValue) + { + yield return (MToon10Prop.AlphaCutoff.ToUnityShaderLabName(), cutoff.Value); + } + + var renderQueueOffset = mToon?.RenderQueueOffsetNumber; + if (renderQueueOffset.HasValue) + { + yield return (MToon10Prop.RenderQueueOffsetNumber.ToUnityShaderLabName(), (float)renderQueueOffset); + } + + var doubleSidedMode = GetMToon10DoubleSidedMode(material, mToon); + { + yield return (MToon10Prop.DoubleSided.ToUnityShaderLabName(), (float)doubleSidedMode); + } + + // Lighting + var normalScale = material?.normalTexture?.scale; + if (normalScale.HasValue) + { + yield return (MToon10Prop.NormalTextureScale.ToUnityShaderLabName(), normalScale.Value); + } + + var shadingShift = mToon?.ShadingShiftFactor; + if (shadingShift.HasValue) + { + yield return (MToon10Prop.ShadingShiftFactor.ToUnityShaderLabName(), shadingShift.Value); + } + + var shadingShiftTextureScale = mToon?.ShadingShiftTexture?.Scale; + if (shadingShiftTextureScale.HasValue) + { + yield return (MToon10Prop.ShadingShiftTextureScale.ToUnityShaderLabName(), shadingShiftTextureScale.Value); + } + + var shadingToony = mToon?.ShadingToonyFactor; + if (shadingToony.HasValue) + { + yield return (MToon10Prop.ShadingToonyFactor.ToUnityShaderLabName(), shadingToony.Value); + } + + // GI + var giEqualization = mToon?.GiEqualizationFactor; + if (giEqualization.HasValue) + { + yield return (MToon10Prop.GiEqualizationFactor.ToUnityShaderLabName(), giEqualization.Value); + } + + // Emission + + // Rim Lighting + var rimFresnelPower = mToon?.ParametricRimFresnelPowerFactor; + if (rimFresnelPower.HasValue) + { + yield return (MToon10Prop.ParametricRimFresnelPowerFactor.ToUnityShaderLabName(), rimFresnelPower.Value); + } + + var rimLift = mToon?.ParametricRimLiftFactor; + if (rimLift.HasValue) + { + yield return (MToon10Prop.ParametricRimLiftFactor.ToUnityShaderLabName(), rimLift.Value); + } + + var rimLightMix = mToon?.RimLightingMixFactor; + if (rimLightMix.HasValue) + { + yield return (MToon10Prop.RimLightingMixFactor.ToUnityShaderLabName(), rimLightMix.Value); + } + + // Outline + var outlineMode = GetMToon10OutlineWidthMode(material, mToon); + { + yield return (MToon10Prop.OutlineWidthMode.ToUnityShaderLabName(), (float)outlineMode); + } + + var outlineWidth = mToon?.OutlineWidthFactor; + if (outlineWidth.HasValue) + { + yield return (MToon10Prop.OutlineWidthFactor.ToUnityShaderLabName(), outlineWidth.Value); + } + + var outlineLightMix = mToon?.OutlineLightingMixFactor; + if (outlineLightMix.HasValue) + { + yield return (MToon10Prop.OutlineLightingMixFactor.ToUnityShaderLabName(), outlineLightMix.Value); + } + + // UV Animation + var uvAnimSpeedScrollX = mToon?.UvAnimationScrollXSpeedFactor; + if (uvAnimSpeedScrollX.HasValue) + { + yield return (MToon10Prop.UvAnimationScrollXSpeedFactor.ToUnityShaderLabName(), uvAnimSpeedScrollX.Value); + } + + var uvAnimSpeedScrollY = mToon?.UvAnimationScrollYSpeedFactor; + if (uvAnimSpeedScrollY.HasValue) + { + // UV coords conversion. + // glTF (top-left origin) to Unity (bottom-left origin) + const float invertY = -1f; + + yield return (MToon10Prop.UvAnimationScrollYSpeedFactor.ToUnityShaderLabName(), uvAnimSpeedScrollY.Value * invertY); + } + + var uvAnimSpeedRotation = mToon?.UvAnimationRotationSpeedFactor; + if (uvAnimSpeedRotation.HasValue) + { + // Speed unit Conversion + const float radianPerSecToRotationPerSec = 1f / (Mathf.PI * 2f); + yield return (MToon10Prop.UvAnimationRotationSpeedFactor.ToUnityShaderLabName(), uvAnimSpeedRotation.Value * radianPerSecToRotationPerSec); + } + + // UI + if (true /* TODO: mToon.IsAdvancedMode */) + { + yield return (MToon10Prop.EditorEditMode.ToUnityShaderLabName(), 1); + } + } + + public static IEnumerable<(string key, Vector4 value)> TryGetAllFloatArrays(glTFMaterial material, VRMC_materials_mtoon mToon) + { + yield break; + } + + private static MToon10AlphaMode GetMToon10AlphaMode(glTFMaterial material) + { + switch (material?.alphaMode) + { + case "OPAQUE": + return MToon10AlphaMode.Opaque; + case "MASK": + return MToon10AlphaMode.Cutout; + case "BLEND": + return MToon10AlphaMode.Transparent; + default: + Debug.LogWarning($"Invalid AlphaMode"); + return MToon10AlphaMode.Opaque; + } + } + + private static MToon10TransparentWithZWriteMode GetMToon10TransparentWithZWriteMode(glTFMaterial material, VRMC_materials_mtoon mtoon) + { + if (mtoon?.TransparentWithZWrite == true) + { + return MToon10TransparentWithZWriteMode.On; + } + else + { + return MToon10TransparentWithZWriteMode.Off; + } + } + private static MToon10DoubleSidedMode GetMToon10DoubleSidedMode(glTFMaterial material, VRMC_materials_mtoon mToon) + { + if (material?.doubleSided == true) + { + return MToon10DoubleSidedMode.On; + } + else + { + return MToon10DoubleSidedMode.Off; + } + } + + private static MToon10OutlineMode GetMToon10OutlineWidthMode(glTFMaterial material, VRMC_materials_mtoon mToon) + { + switch (mToon?.OutlineWidthMode) + { + case OutlineWidthMode.none: + return MToon10OutlineMode.None; + case OutlineWidthMode.worldCoordinates: + return MToon10OutlineMode.World; + case OutlineWidthMode.screenCoordinates: + return MToon10OutlineMode.Screen; + default: + // Invalid + Debug.LogWarning("Invalid outlineWidthMode"); + return MToon10OutlineMode.None; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs.meta b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs.meta new file mode 100644 index 000000000..aa49da4ff --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 01c1ac60c9a047b59ea52aaddb7a0d63 +timeCreated: 1620630516 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP.meta b/Assets/External/VRM10/Runtime/IO/Material/URP.meta new file mode 100644 index 000000000..36a00e993 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a0d1364c3beb8494f9b3ae9c0445ffa9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP/Import.meta b/Assets/External/VRM10/Runtime/IO/Material/URP/Import.meta new file mode 100644 index 000000000..ec9b3f18f --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP/Import.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 45fd659f340f450e97fd111184db0c9d +timeCreated: 1667544438 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials.meta b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials.meta new file mode 100644 index 000000000..2c542f476 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1987bdfe8c2df174abb9cf04caaaba15 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs new file mode 100644 index 000000000..1a690e060 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using UniGLTF; +using UnityEngine; +using VRMShaders; +using VRMShaders.VRM10.MToon10.Runtime; + +namespace UniVRM10 +{ + /// + /// Convert MToon parameters from glTF specification to Unity implementation.(for URP) + /// + public static class UrpVrm10MToonMaterialImporter + { + /// + /// VMRC_materials_mtoon の場合にマテリアル生成情報を作成する + /// + public static bool TryCreateParam(GltfData data, int i, out MaterialDescriptor matDesc) + { + var m = data.GLTF.materials[i]; + if (!UniGLTF.Extensions.VRMC_materials_mtoon.GltfDeserializer.TryGet(m.extensions, out var mtoon)) + { + // Fallback to glTF, when MToon extension does not exist. + matDesc = default; + return false; + } + + // use material.name, because material name may renamed in GltfParser. + matDesc = new MaterialDescriptor( + m.name, + Shader.Find(MToon10Meta.URPUnityShaderName), + null, + Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2), + BuiltInVrm10MToonMaterialImporter.TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), + BuiltInVrm10MToonMaterialImporter.TryGetAllColors(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), + BuiltInVrm10MToonMaterialImporter.TryGetAllFloatArrays(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), + new Action[] + { + material => + { + // Set hidden properties, keywords from float properties. + new MToonValidator(material).Validate(); + } + }); + + return true; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs.meta b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs.meta new file mode 100644 index 000000000..0714adc64 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 57d820ccc1ff7e2469f7fb5cc435bd5b +timeCreated: 1620630516 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP/Import/UrpVrm10MaterialDescriptorGenerator.cs b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/UrpVrm10MaterialDescriptorGenerator.cs new file mode 100644 index 000000000..d389d3117 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/UrpVrm10MaterialDescriptorGenerator.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using UniGLTF; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + public sealed class UrpVrm10MaterialDescriptorGenerator : IMaterialDescriptorGenerator + { + public MaterialDescriptor Get(GltfData data, int i) + { + // mtoon + if (UrpVrm10MToonMaterialImporter.TryCreateParam(data, i, out var matDesc)) return matDesc; + // unlit + if (BuiltInGltfUnlitMaterialImporter.TryCreateParam(data, i, out matDesc)) return matDesc; + // pbr + if (UrpGltfPbrMaterialImporter.TryCreateParam(data, i, out matDesc)) return matDesc; + + // fallback + Debug.LogWarning($"material: {i} out of range. fallback"); + return new MaterialDescriptor( + GltfMaterialImportUtils.ImportMaterialName(i, null), + UrpGltfPbrMaterialImporter.Shader, + null, + new Dictionary(), + new Dictionary(), + new Dictionary(), + new Dictionary(), + new Action[]{}); + } + + public MaterialDescriptor GetGltfDefault() + { + return UrpGltfDefaultMaterialImporter.CreateParam(); + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP/Import/UrpVrm10MaterialDescriptorGenerator.cs.meta b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/UrpVrm10MaterialDescriptorGenerator.cs.meta new file mode 100644 index 000000000..109c9c92b --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/UrpVrm10MaterialDescriptorGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 377d1bd166d5452408fc7772554715ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP/Import/VRM10RenderPipelineMaterialDescriptorGeneratorUtility.cs b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/VRM10RenderPipelineMaterialDescriptorGeneratorUtility.cs new file mode 100644 index 000000000..d030323f9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/VRM10RenderPipelineMaterialDescriptorGeneratorUtility.cs @@ -0,0 +1,20 @@ +using UniGLTF; + +namespace UniVRM10 +{ + public class Vrm10RenderPipelineMaterialDescriptorGeneratorDescriptorUtility : RenderPipelineMaterialDescriptorGeneratorUtility + { + public static IMaterialDescriptorGenerator GetValidVrm10MaterialDescriptorGenerator() + { + switch (GetRenderPipelineType()) + { + case RenderPipelineTypes.UniversalRenderPipeline: + return new UrpVrm10MaterialDescriptorGenerator(); + case RenderPipelineTypes.BuiltinRenderPipeline: + return new BuiltInVrm10MaterialDescriptorGenerator(); + } + + return null; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/URP/Import/VRM10RenderPipelineMaterialDescriptorGeneratorUtility.cs.meta b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/VRM10RenderPipelineMaterialDescriptorGeneratorUtility.cs.meta new file mode 100644 index 000000000..bf1629c84 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/URP/Import/VRM10RenderPipelineMaterialDescriptorGeneratorUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3e8bcf27c69d4fd39e97375f9627ed68 +timeCreated: 1690283374 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/Vrm10MaterialExportUtils.cs b/Assets/External/VRM10/Runtime/IO/Material/Vrm10MaterialExportUtils.cs new file mode 100644 index 000000000..979731b56 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/Vrm10MaterialExportUtils.cs @@ -0,0 +1,54 @@ +using UniGLTF; +using UniGLTF.Extensions.VRMC_materials_mtoon; +using UnityEngine; + +namespace UniVRM10 +{ + public static class Vrm10MaterialExportUtils + { + public static void ExportTextureTransform(glTFTextureInfo textureInfo, Vector2 unityScale, Vector2 unityOffset) + { + if (textureInfo == null) + { + return; + } + var scale = unityScale; + var offset = new Vector2(unityOffset.x, 1.0f - unityOffset.y - unityScale.y); + + glTF_KHR_texture_transform.Serialize(textureInfo, (offset.x, offset.y), (scale.x, scale.y)); + } + + public static void ExportTextureTransform(TextureInfo textureInfo, Vector2 unityScale, Vector2 unityOffset) + { + if (textureInfo == null) + { + return; + } + // Generate extension to empty holder. + var gltfTextureInfo = new EmptyGltfTextureInfo(); + ExportTextureTransform(gltfTextureInfo, unityScale, unityOffset); + + // Copy extension from empty holder. + textureInfo.Extensions = gltfTextureInfo.extensions; + } + + public static void ExportTextureTransform(ShadingShiftTextureInfo textureInfo, Vector2 unityScale, Vector2 unityOffset) + { + if (textureInfo == null) + { + return; + } + // Generate extension to empty holder. + var gltfTextureInfo = new EmptyGltfTextureInfo(); + ExportTextureTransform(gltfTextureInfo, unityScale, unityOffset); + + // Copy extension from empty holder. + textureInfo.Extensions = gltfTextureInfo.extensions; + } + + private sealed class EmptyGltfTextureInfo : glTFTextureInfo + { + + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Material/Vrm10MaterialExportUtils.cs.meta b/Assets/External/VRM10/Runtime/IO/Material/Vrm10MaterialExportUtils.cs.meta new file mode 100644 index 000000000..81a1124bc --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Material/Vrm10MaterialExportUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c246c4b2c35c4ff188cdd9e20c9c064e +timeCreated: 1667409003 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/MigrationData.cs b/Assets/External/VRM10/Runtime/IO/MigrationData.cs new file mode 100644 index 000000000..2dc4fb48e --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/MigrationData.cs @@ -0,0 +1,27 @@ +namespace UniVRM10 +{ + public class MigrationData + { + /// + /// マイグレーション失敗など + /// + public readonly string Message; + + /// + /// vrm0 からマイグレーションした場合に、vrm0 版の meta 情報 + /// + public readonly Migration.Vrm0Meta OriginalMetaBeforeMigration; + + /// + /// Migration した結果のバイト列(デバッグ用) + /// + public readonly byte[] MigratedBytes; + + public MigrationData(string msg, Migration.Vrm0Meta meta = default, byte[] bytes = default) + { + Message = msg; + OriginalMetaBeforeMigration = meta; + MigratedBytes = bytes; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/MigrationData.cs.meta b/Assets/External/VRM10/Runtime/IO/MigrationData.cs.meta new file mode 100644 index 000000000..e00997231 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/MigrationData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86d0f8ee9681a2e43b959952e51810cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Model.meta b/Assets/External/VRM10/Runtime/IO/Model.meta new file mode 100644 index 000000000..e91cfb000 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 18a0f7c989f911547aa4b75abb583b4c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Model/CopyIndicesJob.cs b/Assets/External/VRM10/Runtime/IO/Model/CopyIndicesJob.cs new file mode 100644 index 000000000..757083812 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/CopyIndicesJob.cs @@ -0,0 +1,120 @@ +using Unity.Collections; +using Unity.Jobs; + +#if ENABLE_VRM10_BURST +using Unity.Burst; +#endif + +namespace UniVRM10 +{ + /// + /// インデックス配列を、オフセットを加えながら複製するJob郡 + /// MEMO: ushortを考慮することをやめればかなりシンプルに書ける + /// + internal struct CopyIndicesJobs + { + /// + /// unsigned int -> unsigned int + /// +#if ENABLE_VRM10_BURST + [BurstCompile] +#endif + public struct UInt2UInt : IJobParallelFor + { + private readonly uint _vertexOffset; + + [ReadOnly] private readonly NativeSlice _source; + [WriteOnly] private NativeSlice _destination; + + public UInt2UInt(uint vertexOffset, NativeSlice source, NativeSlice destination) + { + _vertexOffset = vertexOffset; + _source = source; + _destination = destination; + } + + public void Execute(int index) + { + _destination[index] = _source[index] + _vertexOffset; + } + } + + /// + /// unsigned short -> unsigned int + /// +#if ENABLE_VRM10_BURST + [BurstCompile] +#endif + public struct Ushort2Uint : IJobParallelFor + { + private readonly uint _vertexOffset; + + [ReadOnly] private readonly NativeSlice _source; + [WriteOnly] private NativeSlice _destination; + + public Ushort2Uint(uint vertexOffset, NativeSlice source, NativeSlice destination) + { + _vertexOffset = vertexOffset; + _source = source; + _destination = destination; + } + + public void Execute(int index) + { + _destination[index] = _source[index] + _vertexOffset; + } + } + + /// + /// unsigned short -> unsigned short + /// +#if ENABLE_VRM10_BURST + [BurstCompile] +#endif + public struct Ushort2Ushort : IJobParallelFor + { + private readonly ushort _vertexOffset; + + [ReadOnly] private readonly NativeSlice _source; + [WriteOnly] private NativeSlice _destination; + + public Ushort2Ushort(ushort vertexOffset, NativeSlice source, NativeSlice destination) + { + _vertexOffset = vertexOffset; + _source = source; + _destination = destination; + } + + public void Execute(int index) + { + _destination[index] = (ushort)(_source[index] + _vertexOffset); + } + } + + /// + /// unsigned int -> unsigned short + /// +#if ENABLE_VRM10_BURST + [BurstCompile] +#endif + public struct Uint2Ushort : IJobParallelFor + { + private readonly ushort _vertexOffset; + + [ReadOnly] private readonly NativeSlice _source; + [WriteOnly] private NativeSlice _destination; + + public Uint2Ushort(ushort vertexOffset, NativeSlice source, NativeSlice destination) + { + _vertexOffset = vertexOffset; + _source = source; + _destination = destination; + } + + public void Execute(int index) + { + _destination[index] = (ushort)(_source[index] + _vertexOffset); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/CopyIndicesJob.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/CopyIndicesJob.cs.meta new file mode 100644 index 000000000..454e4dc5a --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/CopyIndicesJob.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3c6a7113ee13415e9b8c1063a683f3f8 +timeCreated: 1637033014 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/InterleaveMeshVerticesJob.cs b/Assets/External/VRM10/Runtime/IO/Model/InterleaveMeshVerticesJob.cs new file mode 100644 index 000000000..c70fbcecb --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/InterleaveMeshVerticesJob.cs @@ -0,0 +1,93 @@ +using UniGLTF; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; +using UnityEngine; + +#if ENABLE_VRM10_BURST +using Unity.Burst; +#endif + +namespace UniVRM10 +{ + /// + /// 渡されたバッファを一つのバッファにインターリーブするJob + /// +#if ENABLE_VRM10_BURST + [BurstCompile] +#endif + internal struct InterleaveMeshVerticesJob : IJobParallelFor + { + [WriteOnly] + private NativeSlice _vertices0; + + [WriteOnly] + private NativeSlice _vertices1; + + [WriteOnly] + private NativeSlice _vertices2; + + [ReadOnly] + private readonly NativeSlice _positions; + + // default値を許容する + [ReadOnly, NativeDisableContainerSafetyRestriction] + private readonly NativeSlice _normals; + + [ReadOnly, NativeDisableContainerSafetyRestriction] + private readonly NativeSlice _texCoords; + + [ReadOnly, NativeDisableContainerSafetyRestriction] + private readonly NativeSlice _colors; + + [ReadOnly, NativeDisableContainerSafetyRestriction] + private readonly NativeSlice _weights; + + [ReadOnly, NativeDisableContainerSafetyRestriction] + private readonly NativeSlice _joints; + + public InterleaveMeshVerticesJob( + NativeSlice vertices0, + NativeSlice vertices1, + NativeSlice vertices2, + NativeSlice positions, + NativeSlice normals = default, + NativeSlice texCoords = default, + NativeSlice colors = default, + NativeSlice weights = default, + NativeSlice joints = default) + { + _vertices0 = vertices0; + _vertices1 = vertices1; + _vertices2 = vertices2; + _positions = positions; + _normals = normals; + _texCoords = texCoords; + _colors = colors; + _weights = weights; + _joints = joints; + } + + public void Execute(int index) + { + _vertices0[index] = new MeshVertex0( + _positions[index], + _normals.Length > 0 ? _normals[index] : Vector3.zero + ); + _vertices1[index] = new MeshVertex1( + _texCoords.Length > 0 ? _texCoords[index] : Vector2.zero, + _colors.Length > 0 ? _colors[index] : Color.white + ); + _vertices2[index] = new MeshVertex2( + _joints.Length > 0 ? _joints[index].Joint0 : (ushort)0, + _joints.Length > 0 ? _joints[index].Joint1 : (ushort)0, + _joints.Length > 0 ? _joints[index].Joint2 : (ushort)0, + _joints.Length > 0 ? _joints[index].Joint3 : (ushort)0, + _weights.Length > 0 ? _weights[index].x : 0, + _weights.Length > 0 ? _weights[index].y : 0, + _weights.Length > 0 ? _weights[index].z : 0, + _weights.Length > 0 ? _weights[index].w : 0 + ); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/InterleaveMeshVerticesJob.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/InterleaveMeshVerticesJob.cs.meta new file mode 100644 index 000000000..6a54c7ebc --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/InterleaveMeshVerticesJob.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 01d2fcab0a3941fa9cf2e4f1a641105b +timeCreated: 1636688648 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshImporterDivided.cs b/Assets/External/VRM10/Runtime/IO/Model/MeshImporterDivided.cs new file mode 100644 index 000000000..bed21b391 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshImporterDivided.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using Unity.Collections; +using Unity.Jobs; +using UnityEngine; +using UnityEngine.Profiling; +using UnityEngine.Rendering; +using VrmLib; +using Mesh = UnityEngine.Mesh; + +namespace UniVRM10 +{ + public static class MeshImporterDivided + { + public static Mesh LoadDivided(MeshGroup meshGroup) + { + Profiler.BeginSample("MeshImporterDivided.LoadDivided"); + + var vertexCount = meshGroup.Meshes.Sum(mesh => mesh.VertexBuffer.Count); + var indexCount = meshGroup.Meshes.Sum(mesh => mesh.IndexBuffer.Count); + + var resultMesh = new Mesh(); + + // 頂点バッファ・BindPoseを構築して更新 + UpdateVerticesAndBindPose(meshGroup, vertexCount, resultMesh); + + // インデックスバッファを構築して更新 + UpdateIndices(meshGroup, vertexCount, indexCount, resultMesh); + + // SubMeshを更新 + resultMesh.subMeshCount = meshGroup.Meshes.Count; + var indexOffset = 0; + for (var i = 0; i < meshGroup.Meshes.Count; ++i) + { + var mesh = meshGroup.Meshes[i]; + resultMesh.SetSubMesh(i, new SubMeshDescriptor(indexOffset, mesh.IndexBuffer.Count)); + indexOffset += mesh.IndexBuffer.Count; + } + + // 各種データを再構築 + resultMesh.RecalculateBounds(); + resultMesh.RecalculateTangents(); + if (meshGroup.Meshes.Any(mesh => mesh.VertexBuffer.Normals == null)) + { + resultMesh.RecalculateNormals(); + } + + // BlendShapeを更新 + var blendShapeCount = meshGroup.Meshes[0].MorphTargets.Count; + + for (var i = 0; i < blendShapeCount; ++i) + { + var positionsCount = 0; + var normalsCount = 0; + foreach (var mesh in meshGroup.Meshes) + { + var morphTarget = mesh.MorphTargets[i]; + positionsCount += morphTarget.VertexBuffer.Positions.Count; + normalsCount += morphTarget.VertexBuffer.Normals?.Count ?? morphTarget.VertexBuffer.Count; + } + + using (var blendShapePositions = new NativeArray(positionsCount, Allocator.Temp)) + using (var blendShapeNormals = new NativeArray(normalsCount, Allocator.Temp)) + { + + var blendShapePositionOffset = 0; + var blendShapeNormalOffset = 0; + foreach (var mesh in meshGroup.Meshes) + { + var morphTarget = mesh.MorphTargets[i]; + + + NativeArray.Copy( + morphTarget.VertexBuffer.Positions.Bytes.Reinterpret(1), + blendShapePositions.GetSubArray(blendShapePositionOffset, morphTarget.VertexBuffer.Positions.Count)); + + if (morphTarget.VertexBuffer.Normals != null) + { + // nullならdefault(0)のまま + NativeArray.Copy( + morphTarget.VertexBuffer.Normals.Bytes.Reinterpret(1), + blendShapeNormals.GetSubArray(blendShapeNormalOffset, morphTarget.VertexBuffer.Normals.Count)); + } + + blendShapePositionOffset += morphTarget.VertexBuffer.Positions.Count; + blendShapeNormalOffset += morphTarget.VertexBuffer.Normals?.Count ?? morphTarget.VertexBuffer.Count; + } + + resultMesh.AddBlendShapeFrame(meshGroup.Meshes[0].MorphTargets[i].Name, + 100.0f, + blendShapePositions.ToArray(), + blendShapeNormals.ToArray(), + null); + } + } + + Profiler.EndSample(); + + return resultMesh; + } + + /// + /// インデックスバッファを更新する + /// MEMO: 出力に対するushortを考慮することをやめればかなりシンプルに書ける + /// + private static void UpdateIndices(MeshGroup meshGroup, int vertexCount, int indexCount, Mesh resultMesh) + { + Profiler.BeginSample("MeshImporterDivided.UpdateIndices"); + + JobHandle jobHandle = default; + + var disposables = new List(); + + // + // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_accessor_componenttype + // + if (vertexCount < ushort.MaxValue) + { + // vertex buffer への index が ushort に収まる + var indices = new NativeArray(indexCount, Allocator.TempJob); + disposables.Add(indices); + var indexOffset = 0; + var vertexOffset = 0; + foreach (var mesh in meshGroup.Meshes) + { + switch (mesh.IndexBuffer.ComponentType) + { + case AccessorValueType.BYTE: + case AccessorValueType.UNSIGNED_BYTE: + case AccessorValueType.FLOAT: + throw new NotImplementedException($"{mesh.IndexBuffer.ComponentType}"); + + case AccessorValueType.SHORT: + case AccessorValueType.UNSIGNED_SHORT: + { + // unsigned short -> unsigned short + var source = mesh.IndexBuffer.Bytes.Reinterpret(1); + jobHandle = new CopyIndicesJobs.Ushort2Ushort( + (ushort)vertexOffset, + new NativeSlice(source), + new NativeSlice(indices, indexOffset, mesh.IndexBuffer.Count)) + .Schedule(mesh.IndexBuffer.Count, 1, jobHandle); + break; + } + + case AccessorValueType.UNSIGNED_INT: + { + // unsigned int -> unsigned short + var source = mesh.IndexBuffer.Bytes.Reinterpret(1); + jobHandle = new CopyIndicesJobs.Uint2Ushort( + (ushort)vertexOffset, + source, + new NativeSlice(indices, indexOffset, mesh.IndexBuffer.Count)) + .Schedule(mesh.IndexBuffer.Count, 1, jobHandle); + break; + } + + default: + throw new ArgumentException($"unknown index buffer type: {mesh.IndexBuffer.ComponentType}"); + } + + vertexOffset += mesh.VertexBuffer.Count; + indexOffset += mesh.IndexBuffer.Count; + } + + jobHandle.Complete(); + + resultMesh.SetIndexBufferParams(indexCount, IndexFormat.UInt16); + resultMesh.SetIndexBufferData(indices, 0, 0, indexCount); + } + else + { + // vertex buffer への index が ushort を超える + var indices = new NativeArray(indexCount, Allocator.TempJob); + disposables.Add(indices); + var indexOffset = 0; + var vertexOffset = 0; + foreach (var mesh in meshGroup.Meshes) + { + switch (mesh.IndexBuffer.ComponentType) + { + case AccessorValueType.BYTE: + case AccessorValueType.UNSIGNED_BYTE: + case AccessorValueType.FLOAT: + throw new NotImplementedException($"{mesh.IndexBuffer.ComponentType}"); + + case AccessorValueType.SHORT: + case AccessorValueType.UNSIGNED_SHORT: + { + // unsigned short -> unsigned int + var source = mesh.IndexBuffer.Bytes.Reinterpret(1); + jobHandle = new CopyIndicesJobs.Ushort2Uint( + (uint)vertexOffset, + source, + new NativeSlice(indices, indexOffset, mesh.IndexBuffer.Count)) + .Schedule(mesh.IndexBuffer.Count, 1, jobHandle); + break; + } + + case AccessorValueType.UNSIGNED_INT: + { + // unsigned int -> unsigned int + var source = mesh.IndexBuffer.Bytes.Reinterpret(1); + jobHandle = new CopyIndicesJobs.UInt2UInt( + (uint)vertexOffset, + source, + new NativeSlice(indices, indexOffset, mesh.IndexBuffer.Count)) + .Schedule(mesh.IndexBuffer.Count, 1, jobHandle); + break; + } + + default: + throw new ArgumentException($"unknown index buffer type: {mesh.IndexBuffer.ComponentType}"); + } + + vertexOffset += mesh.VertexBuffer.Count; + indexOffset += mesh.IndexBuffer.Count; + } + + jobHandle.Complete(); + + resultMesh.SetIndexBufferParams(indexCount, IndexFormat.UInt32); + resultMesh.SetIndexBufferData(indices, 0, 0, indexCount); + } + + foreach (var disposable in disposables) + { + disposable.Dispose(); + } + + Profiler.EndSample(); + } + + /// + /// メッシュの頂点情報の更新を行う際、MainThreadが空くため、その間にBindPoseの更新も行う + /// + private static void UpdateVerticesAndBindPose( + MeshGroup meshGroup, + int vertexCount, + Mesh resultMesh) + { + Profiler.BeginSample("MeshImporterDivided.UpdateVerticesAndBindPose"); + + var disposables = new List(); + + // JobのSchedule + var vertices0 = new NativeArray(vertexCount, Allocator.TempJob); + var vertices1 = new NativeArray(vertexCount, Allocator.TempJob); + var vertices2 = new NativeArray(vertexCount, Allocator.TempJob); + disposables.Add(vertices0); + disposables.Add(vertices1); + disposables.Add(vertices2); + + var indexOffset = 0; + JobHandle interleaveVertexJob = default; + + foreach (var mesh in meshGroup.Meshes) + { + var positions = mesh.VertexBuffer.Positions.Bytes.Reinterpret(1); + var normals = mesh.VertexBuffer.Normals?.Bytes.Reinterpret(1) ?? default; + var texCoords = mesh.VertexBuffer.TexCoords?.Bytes.Reinterpret(1) ?? default; + var weights = mesh.VertexBuffer.Weights?.GetAsVector4Array() ?? default; + var joints = mesh.VertexBuffer.Joints?.GetAsSkinJointsArray() ?? default; + + interleaveVertexJob = new InterleaveMeshVerticesJob( + new NativeSlice(vertices0, indexOffset, mesh.VertexBuffer.Count), + new NativeSlice(vertices1, indexOffset, mesh.VertexBuffer.Count), + new NativeSlice(vertices2, indexOffset, mesh.VertexBuffer.Count), + positions, + normals, + texCoords, + default, + weights, + joints) + .Schedule(mesh.VertexBuffer.Count, 1, interleaveVertexJob); + indexOffset += mesh.VertexBuffer.Count; + } + + JobHandle.ScheduleBatchedJobs(); + + // 並行してBindposeの更新を行う + if (meshGroup.Skin != null) + { + resultMesh.bindposes = meshGroup.Skin.InverseMatrices.GetSpan().ToArray(); + } + + // Jobを完了 + interleaveVertexJob.Complete(); + + // VertexBufferを設定 + MeshVertexUtility.SetVertexBufferParamsToMesh(resultMesh, vertexCount); + resultMesh.SetVertexBufferData(vertices0, 0, 0, vertexCount); + resultMesh.SetVertexBufferData(vertices1, 0, 0, vertexCount, 1); + resultMesh.SetVertexBufferData(vertices2, 0, 0, vertexCount, 2); + + // 各種バッファを破棄 + foreach (var disposable in disposables) + { + disposable.Dispose(); + } + + Profiler.EndSample(); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshImporterDivided.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/MeshImporterDivided.cs.meta new file mode 100644 index 000000000..db03ec4ff --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshImporterDivided.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad9d3d36855421b4b980aeaedcb3c2a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshImporterShared.cs b/Assets/External/VRM10/Runtime/IO/Model/MeshImporterShared.cs new file mode 100644 index 000000000..76c8b6019 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshImporterShared.cs @@ -0,0 +1,150 @@ +using System; +using UniGLTF; +using Unity.Collections; +using Unity.Jobs; +using UnityEngine; +using UnityEngine.Profiling; +using UnityEngine.Rendering; +using VrmLib; +using Mesh = UnityEngine.Mesh; + +namespace UniVRM10 +{ + public static class MeshImporterShared + { + /// + /// VrmLib.Mesh => UnityEngine.Mesh + /// + /// + /// + /// + public static Mesh LoadSharedMesh(VrmLib.Mesh src, Skin skin = null) + { + Profiler.BeginSample("MeshImporterShared.LoadSharedMesh"); + var mesh = new Mesh(); + + var positions = src.VertexBuffer.Positions.Bytes.Reinterpret(1); + var normals = src.VertexBuffer.Normals?.Bytes.Reinterpret(1) ?? default; + var texCoords = src.VertexBuffer.TexCoords?.Bytes.Reinterpret(1) ?? default; + NativeArray colors = default; + if (src.VertexBuffer.Colors is BufferAccessor colorBuffer) + { + if (colorBuffer.ComponentType == AccessorValueType.FLOAT && colorBuffer.AccessorType == AccessorVectorType.VEC4) + { + colors = colorBuffer.Bytes.Reinterpret(1); + } + else + { + Debug.LogWarning($"COLOR_0: {colorBuffer.ComponentType}.{colorBuffer.AccessorType} not supported. skip."); + } + } + var weights = src.VertexBuffer.Weights?.GetAsVector4Array() ?? default; + var joints = src.VertexBuffer.Joints?.GetAsSkinJointsArray() ?? default; + + using (var vertices0 = new NativeArray(positions.Length, Allocator.TempJob)) + using (var vertices1 = new NativeArray(positions.Length, Allocator.TempJob)) + using (var vertices2 = new NativeArray(positions.Length, Allocator.TempJob)) + { + // JobとBindPoseの更新を並行して行う + var jobHandle = + new InterleaveMeshVerticesJob( + vertices0, + vertices1, + vertices2, + positions, + normals, + texCoords, + colors, + weights, + joints + ) + .Schedule(vertices0.Length, 1); + JobHandle.ScheduleBatchedJobs(); + + // BindPoseを更新 + if (weights.IsCreated && joints.IsCreated) + { + if (weights.Length != positions.Length || joints.Length != positions.Length) + { + throw new ArgumentException(); + } + + if (skin != null) + { + mesh.bindposes = skin.InverseMatrices.GetSpan().ToArray(); + } + } + + // Jobを完了 + jobHandle.Complete(); + + // 頂点を更新 + MeshVertexUtility.SetVertexBufferParamsToMesh(mesh, vertices0.Length); + mesh.SetVertexBufferData(vertices0, 0, 0, vertices0.Length); + mesh.SetVertexBufferData(vertices1, 0, 0, vertices0.Length, 1); + mesh.SetVertexBufferData(vertices2, 0, 0, vertices0.Length, 2); + + // 出力のNativeArrayを開放 + } + + // Indexを更新 + switch (src.IndexBuffer.ComponentType) + { + case AccessorValueType.UNSIGNED_BYTE: + { + var intIndices = src.IndexBuffer.GetAsIntArray(); + mesh.SetIndexBufferParams(intIndices.Length, IndexFormat.UInt32); + mesh.SetIndexBufferData(intIndices, 0, 0, intIndices.Length); + break; + } + case AccessorValueType.UNSIGNED_SHORT: + { + var shortIndices = src.IndexBuffer.Bytes.Reinterpret(1); + mesh.SetIndexBufferParams(shortIndices.Length, IndexFormat.UInt16); + mesh.SetIndexBufferData(shortIndices, 0, 0, shortIndices.Length); + break; + } + case AccessorValueType.UNSIGNED_INT: + { + var intIndices = src.IndexBuffer.Bytes.Reinterpret(1); + mesh.SetIndexBufferParams(intIndices.Length, IndexFormat.UInt32); + mesh.SetIndexBufferData(intIndices, 0, 0, intIndices.Length); + break; + } + default: + throw new NotImplementedException(); + } + + // SubMeshを更新 + mesh.subMeshCount = src.Submeshes.Count; + for (var i = 0; i < src.Submeshes.Count; ++i) + { + var subMesh = src.Submeshes[i]; + mesh.SetSubMesh(i, new SubMeshDescriptor(subMesh.Offset, subMesh.DrawCount)); + } + + // MorphTargetを更新 + foreach (var morphTarget in src.MorphTargets) + { + var morphTargetPositions = + morphTarget.VertexBuffer.Positions != null + ? morphTarget.VertexBuffer.Positions.GetSpan().ToArray() + : new Vector3[mesh.vertexCount] // dummy + ; + mesh.AddBlendShapeFrame(morphTarget.Name, 100.0f, morphTargetPositions, null, null); + } + + // 各種パラメーターを再計算 + mesh.RecalculateBounds(); + mesh.RecalculateTangents(); + if (src.VertexBuffer.Normals == null) + { + mesh.RecalculateNormals(); + } + + Profiler.EndSample(); + + return mesh; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshImporterShared.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/MeshImporterShared.cs.meta new file mode 100644 index 000000000..f66f6f755 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshImporterShared.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b89fda8f5e4dc994f8e91c7d1e473c35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshReader.cs b/Assets/External/VRM10/Runtime/IO/Model/MeshReader.cs new file mode 100644 index 000000000..cd99b6896 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshReader.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using VrmLib; + +namespace UniVRM10 +{ + /// + /// GLTF -> VrmLib.MeshGroup + /// + public static class MeshReader + { + /// + /// VertexBufferはひとつでIndexBufferの参照が異なる + /// + /// VertexBuffer + /// +----------------------------------+ + /// | | + /// +----------------------------------+ + /// A A A + /// | | | + /// +---------+--------+--------+ + /// | submesh0|submesh1|submesh2| + /// +---------+--------+--------+ + /// IndexBuffer + /// + static Mesh SharedBufferFromGltf(this glTFMesh x, Vrm10ImportData storage) + { + // 先頭を使う + return FromGltf(storage, x, x.primitives[0], true); + } + + /// + /// IndexBuffer毎に異なるVertexBufferを参照する + /// + /// VertexBuffer + /// +--------+ +--------+ +--------+ + /// |0 | |1 | |2 | + /// +--------+ +--------+ +--------+ + /// A A A + /// | | | + /// +---------+--------+--------+ + /// | submesh0|submesh1|submesh2| + /// +---------+--------+--------+ + /// IndexBuffer + /// + static Mesh FromGltf(this glTFPrimitives primitive, Vrm10ImportData storage, glTFMesh x) + { + return FromGltf(storage, x, primitive, false); + } + + static Mesh FromGltf(Vrm10ImportData storage, glTFMesh x, glTFPrimitives primitive, bool isShared) + { + var mesh = new Mesh((TopologyType)primitive.mode) + { + VertexBuffer = primitive.attributes.FromGltf(storage) + }; + + if (isShared) + { + // create joined index buffer + mesh.IndexBuffer = storage.CreateAccessor(x.primitives.Select(y => y.indices).ToArray()); + } + else + { + mesh.IndexBuffer = storage.CreateAccessor(primitive.indices); + } + + if (mesh.IndexBuffer == null) + { + var indices = Enumerable.Range(0, mesh.VertexBuffer.Count).ToArray(); + var na = storage.Data.NativeArrayManager.CreateNativeArray(indices); + mesh.IndexBuffer = new BufferAccessor(storage.Data.NativeArrayManager, na.Reinterpret(4), AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, na.Length); + } + + { + gltf_mesh_extras_targetNames.TryGet(x, out List targetNames); + + for (int i = 0; i < primitive.targets.Count; ++i) + { + var gltfTarget = primitive.targets[i]; + + string targetName = null; + { + targetName = targetNames[i]; + } + var target = new MorphTarget(targetName) + { + VertexBuffer = gltfTarget.FromGltf(storage) + }; + + // validate count + foreach (var kv in target.VertexBuffer) + { + if (kv.Value.Count != mesh.VertexBuffer.Count) + { + throw new Exception(); + } + } + + mesh.MorphTargets.Add(target); + } + } + + return mesh; + } + + static VertexBuffer FromGltf(this glTFAttributes attributes, + Vrm10ImportData storage) + { + var b = new VertexBuffer(); + + if (storage.TryCreateAccessor(attributes.POSITION, out BufferAccessor position)) + { + b.Add(VertexBuffer.PositionKey, position); + } + else + { + // position required + throw new Exception(); + } + + if (storage.TryCreateAccessor(attributes.NORMAL, out BufferAccessor normal)) b.Add(VertexBuffer.NormalKey, normal); + if (storage.TryCreateAccessor(attributes.COLOR_0, out BufferAccessor color)) b.Add(VertexBuffer.ColorKey, color); + if (storage.TryCreateAccessor(attributes.TEXCOORD_0, out BufferAccessor tex0)) b.Add(VertexBuffer.TexCoordKey, tex0); + if (storage.TryCreateAccessor(attributes.TEXCOORD_1, out BufferAccessor tex1)) b.Add(VertexBuffer.TexCoordKey2, tex1); + // if(storage.TryCreateAccessor(attributes.TANGENT, out BufferAccessor tangent))b.Add(VertexBuffer.TangentKey, tangent); + if (storage.TryCreateAccessor(attributes.WEIGHTS_0, out BufferAccessor weights)) b.Add(VertexBuffer.WeightKey, weights); + if (storage.TryCreateAccessor(attributes.JOINTS_0, out BufferAccessor joints)) b.Add(VertexBuffer.JointKey, joints); + + return b; + } + + static VertexBuffer FromGltf(this gltfMorphTarget target, Vrm10ImportData storage) + { + var b = new VertexBuffer(); + storage.CreateBufferAccessorAndAdd(target.POSITION, b, VertexBuffer.PositionKey); + storage.CreateBufferAccessorAndAdd(target.NORMAL, b, VertexBuffer.NormalKey); + storage.CreateBufferAccessorAndAdd(target.TANGENT, b, VertexBuffer.TangentKey); + return b; + } + + static bool HasSameVertexBuffer(this glTFPrimitives lhs, glTFPrimitives rhs) + { + if (lhs.attributes.POSITION != rhs.attributes.POSITION) return false; + if (lhs.attributes.NORMAL != rhs.attributes.NORMAL) return false; + if (lhs.attributes.TEXCOORD_0 != rhs.attributes.TEXCOORD_0) return false; + if (lhs.attributes.TEXCOORD_1 != rhs.attributes.TEXCOORD_1) return false; + if (lhs.attributes.COLOR_0 != rhs.attributes.COLOR_0) return false; + if (lhs.attributes.WEIGHTS_0 != rhs.attributes.WEIGHTS_0) return false; + if (lhs.attributes.JOINTS_0 != rhs.attributes.JOINTS_0) return false; + return true; + } + + static bool AllPrimitivesHasSameVertexBuffer(this glTFMesh m) + { + if (m.primitives.Count <= 1) + { + return true; + } + + var first = m.primitives[0]; + for (int i = 1; i < m.primitives.Count; ++i) + { + if (!first.HasSameVertexBuffer(m.primitives[i])) + { + return false; + } + } + + return true; + } + + public static MeshGroup FromGltf(this glTFMesh x, Vrm10ImportData storage) + { + var group = new MeshGroup(x.name); + + if (x.primitives.Count == 1) + { + var primitive = x.primitives[0]; + var mesh = primitive.FromGltf(storage, x); + var materialIndex = primitive.material; + + mesh.Submeshes.Add( + new Submesh(0, mesh.IndexBuffer.Count, materialIndex)); + + group.Meshes.Add(mesh); + } + else if (!x.AllPrimitivesHasSameVertexBuffer()) + { + int offset = 0; + foreach (var primitive in x.primitives) + { + var mesh = primitive.FromGltf(storage, x); + var materialIndex = primitive.material; + + mesh.Submeshes.Add( + new Submesh(offset, mesh.IndexBuffer.Count, materialIndex)); + offset += mesh.IndexBuffer.Count; + + group.Meshes.Add(mesh); + } + } + else + { + // + // obsolete + // + // for VRM + + var mesh = x.SharedBufferFromGltf(storage); + int offset = 0; + foreach (var primitive in x.primitives) + { + var materialIndex = primitive.material; + var count = storage.Gltf.accessors[primitive.indices].count; + mesh.Submeshes.Add( + new Submesh(offset, count, materialIndex)); + offset += count; + } + + group.Meshes.Add(mesh); + } + + return group; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshReader.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/MeshReader.cs.meta new file mode 100644 index 000000000..192545061 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f4647a633dfc844eb1b8e7563addba2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshVertex0.cs b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex0.cs new file mode 100644 index 000000000..601b8d282 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex0.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Stream0用のインターリーブされたメッシュの頂点情報を表す構造体 + /// そのままGPUにアップロードされる + /// + [Serializable, StructLayout(LayoutKind.Sequential)] + internal readonly struct MeshVertex0 + { + private readonly Vector3 _position; + private readonly Vector3 _normal; + + public MeshVertex0( + Vector3 position, + Vector3 normal) + { + _position = position; + _normal = normal; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshVertex0.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex0.cs.meta new file mode 100644 index 000000000..0e80ae0bd --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex0.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 78c70746c10e46bc97de0a7afedb23c7 +timeCreated: 1636625951 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshVertex1.cs b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex1.cs new file mode 100644 index 000000000..a5a6ec174 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex1.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Stream1用のインターリーブされたメッシュの頂点情報を表す構造体 + /// そのままGPUにアップロードされる + /// + [Serializable, StructLayout(LayoutKind.Sequential)] + internal readonly struct MeshVertex1 + { + private readonly Color _color; + private readonly Vector2 _texCoord; + + public MeshVertex1( + Vector2 texCoord, + Color color) + { + _texCoord = texCoord; + _color = color; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshVertex1.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex1.cs.meta new file mode 100644 index 000000000..4bf8cf72a --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex1.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0ec609c13465473984b73fc5fed0ab17 +timeCreated: 1663140746 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshVertex2.cs b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex2.cs new file mode 100644 index 000000000..b71f2d1cd --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex2.cs @@ -0,0 +1,42 @@ +using System; +using System.Runtime.InteropServices; + +namespace UniVRM10 +{ + /// + /// Stream2用のインターリーブされたメッシュの頂点情報を表す構造体 + /// そのままGPUにアップロードされる + /// + [Serializable, StructLayout(LayoutKind.Sequential)] + internal readonly struct MeshVertex2 + { + private readonly float _boneWeight0; + private readonly float _boneWeight1; + private readonly float _boneWeight2; + private readonly float _boneWeight3; + private readonly ushort _boneIndex0; + private readonly ushort _boneIndex1; + private readonly ushort _boneIndex2; + private readonly ushort _boneIndex3; + + public MeshVertex2( + ushort boneIndex0, + ushort boneIndex1, + ushort boneIndex2, + ushort boneIndex3, + float boneWeight0, + float boneWeight1, + float boneWeight2, + float boneWeight3) + { + _boneIndex0 = boneIndex0; + _boneIndex1 = boneIndex1; + _boneIndex2 = boneIndex2; + _boneIndex3 = boneIndex3; + _boneWeight0 = boneWeight0; + _boneWeight1 = boneWeight1; + _boneWeight2 = boneWeight2; + _boneWeight3 = boneWeight3; + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshVertex2.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex2.cs.meta new file mode 100644 index 000000000..b37acc85c --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshVertex2.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9f359472cfd14db28982f4db837a7aaf +timeCreated: 1663140985 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshVertexUtility.cs b/Assets/External/VRM10/Runtime/IO/Model/MeshVertexUtility.cs new file mode 100644 index 000000000..eba8c1be3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshVertexUtility.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using UnityEngine.Rendering; + +namespace UniVRM10 +{ + internal static class MeshVertexUtility + { + public static void SetVertexBufferParamsToMesh(Mesh mesh, int length) + { + mesh.SetVertexBufferParams(length, new VertexAttributeDescriptor[] + { + new VertexAttributeDescriptor(VertexAttribute.Position, stream: 0), + new VertexAttributeDescriptor(VertexAttribute.Normal, stream: 0), + new VertexAttributeDescriptor(VertexAttribute.Color, dimension: 4, stream: 1), + new VertexAttributeDescriptor(VertexAttribute.TexCoord0, dimension: 2, stream: 1), + new VertexAttributeDescriptor(VertexAttribute.BlendWeight, dimension: 4, stream: 2), + new VertexAttributeDescriptor(VertexAttribute.BlendIndices, VertexAttributeFormat.UInt16, 4, 2), + }); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshVertexUtility.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/MeshVertexUtility.cs.meta new file mode 100644 index 000000000..5b661bbfa --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshVertexUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d041a5d5b4c5412896a316b98ae1677c +timeCreated: 1663143719 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshWriter.cs b/Assets/External/VRM10/Runtime/IO/Model/MeshWriter.cs new file mode 100644 index 000000000..063607b67 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshWriter.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using Unity.Collections; +using VrmLib; + +namespace UniVRM10 +{ + /// + /// VrmLib.MeshGroup => GLTF + /// + public static class MeshWriter + { + /// + /// https://github.com/vrm-c/UniVRM/issues/800 + /// + /// SubMesh 単位に分割する。 + /// SubMesh を Gltf の Primitive に対応させる。 + /// + /// + /// + /// + /// + /// + static IEnumerable ExportMeshDivided(this VrmLib.Mesh mesh, List materials, + ExportingGltfData writer, ExportArgs option) + { + var usedIndices = new List(); + var meshIndices = mesh.IndexBuffer.GetAsIntArray(); + var positions = mesh.VertexBuffer.Positions.GetSpan().ToArray(); + var normals = mesh.VertexBuffer.Normals.GetSpan().ToArray(); + var uv = mesh.VertexBuffer.TexCoords.GetSpan().ToArray(); + var hasSkin = mesh.VertexBuffer.Weights != null; + var weights = mesh.VertexBuffer.Weights?.GetSpan().ToArray(); + var joints = mesh.VertexBuffer.Joints?.GetSpan().ToArray(); + Func getJointIndex = default; + if (hasSkin) + { + getJointIndex = i => + { + return i; + }; + } + + foreach (var submesh in mesh.Submeshes) + { + var indices = meshIndices.GetSubArray(submesh.Offset, submesh.DrawCount).ToArray(); + var hash = new HashSet(indices); + + // mesh + // index の順に attributes を蓄える + var buffer = new MeshExportUtil.VertexBuffer(indices.Length, getJointIndex); + usedIndices.Clear(); + for (int k = 0; k < positions.Length; ++k) + { + if (hash.Contains(k)) + { + // indices から参照される頂点だけを蓄える + usedIndices.Add(k); + buffer.PushVertex(k, positions[k], normals[k], uv[k]); + if (getJointIndex != null) + { + var j = joints[k]; + var w = weights[k]; + var boneWeight = new UnityEngine.BoneWeight + { + boneIndex0 = j.Joint0, + boneIndex1 = j.Joint1, + boneIndex2 = j.Joint2, + boneIndex3 = j.Joint3, + weight0 = w.x, + weight1 = w.y, + weight2 = w.z, + weight3 = w.w, + }; + buffer.PushBoneWeight(boneWeight); + } + } + } + var materialIndex = submesh.Material; + var gltfPrimitive = buffer.ToGltfPrimitive(writer, materialIndex, indices); + + // blendShape + for (int j = 0; j < mesh.MorphTargets.Count; ++j) + { + var blendShape = new MeshExportUtil.BlendShapeBuffer(usedIndices.Count); + + // index の順に attributes を蓄える + var morph = mesh.MorphTargets[j]; + var blendShapePositions = morph.VertexBuffer.Positions.GetSpan(); + NativeArray? blendShapeNormals = default; + if (morph.VertexBuffer.Normals != null) + { + blendShapeNormals = morph.VertexBuffer.Normals.GetSpan(); + } + int l = 0; + foreach (var k in usedIndices) + { + blendShape.Set(l++, + blendShapePositions[k], + blendShapeNormals.HasValue ? blendShapeNormals.Value[k] : UnityEngine.Vector3.zero + ); + } + + gltfPrimitive.targets.Add(blendShape.ToGltf(writer, !option.removeMorphNormal, option.sparse)); + } + + yield return gltfPrimitive; + } + } + + /// + /// ModelExporter.Export で作られた Model.MeshGroups[*] を GLTF 化する + /// + /// + /// + /// + /// + /// + public static glTFMesh ExportMeshGroup(this MeshGroup src, List materials, ExportingGltfData writer, ExportArgs option) + { + var gltfMesh = new glTFMesh + { + name = src.Name + }; + + if (src.Meshes.Count != 1) + { + throw new NotImplementedException(); + } + + foreach (var prim in src.Meshes[0].ExportMeshDivided(materials, writer, option)) + { + gltfMesh.primitives.Add(prim); + } + + var targetNames = src.Meshes[0].MorphTargets.Select(x => x.Name).ToArray(); + gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames, BlendShapeTargetNameLocationFlags.Mesh); + + return gltfMesh; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Model/MeshWriter.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/MeshWriter.cs.meta new file mode 100644 index 000000000..7cec628aa --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/MeshWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f71759cba771a95449d96df3fa37b115 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Model/ModelExporter.cs b/Assets/External/VRM10/Runtime/IO/Model/ModelExporter.cs new file mode 100644 index 000000000..dd9e3d044 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/ModelExporter.cs @@ -0,0 +1,355 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using UniGLTF; +using UniGLTF.Utils; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// UnityEngine.GameObject hierarchy => GLTF.Nodes, GLTF.Meshes, GLTF.Skins + /// + public class ModelExporter + { + public VrmLib.Model Model; + + public Dictionary Nodes = new Dictionary(); + public List Materials = new List(); + public Dictionary Meshes = new Dictionary(); + + /// + /// GameObject to VrmLib.Model + /// + /// + /// + public VrmLib.Model Export(INativeArrayManager arrayManager, GameObject root) + { + Model = new VrmLib.Model(VrmLib.Coordinates.Unity); + + _Export(arrayManager, root); + + // humanoid + { + var humanoid = root.GetComponent(); + if (humanoid is null) + { + humanoid = root.AddComponent(); + humanoid.AssignBonesFromAnimator(); + } + + foreach (HumanBodyBones humanBoneType in CachedEnum.GetValues()) + { + var transform = humanoid.GetBoneTransform(humanBoneType); + if (transform != null && Nodes.TryGetValue(transform.gameObject, out VrmLib.Node node)) + { + switch (humanBoneType) + { + // https://github.com/vrm-c/vrm-specification/issues/380 + case HumanBodyBones.LeftThumbProximal: node.HumanoidBone = VrmLib.HumanoidBones.leftThumbMetacarpal; break; + case HumanBodyBones.LeftThumbIntermediate: node.HumanoidBone = VrmLib.HumanoidBones.leftThumbProximal; break; + case HumanBodyBones.RightThumbProximal: node.HumanoidBone = VrmLib.HumanoidBones.rightThumbMetacarpal; break; + case HumanBodyBones.RightThumbIntermediate: node.HumanoidBone = VrmLib.HumanoidBones.rightThumbProximal; break; + default: node.HumanoidBone = (VrmLib.HumanoidBones)Enum.Parse(typeof(VrmLib.HumanoidBones), humanBoneType.ToString(), true); break; + } + } + } + } + + return Model; + } + + /// + /// 頂点と面が存在する Mesh のみをエクスポート可能とする + /// + static bool MeshCanExport(UnityEngine.Mesh mesh) + { + if (mesh == null) + { + Debug.LogWarning("mesh is null"); + return false; + } + if (mesh.vertexCount == 0) + { + Debug.LogWarning($"{mesh}: no vertices"); + return false; + } + if (mesh.triangles == null) + { + Debug.LogWarning($"{mesh}: no triangles"); + return false; + } + if (mesh.triangles.Length == 0) + { + Debug.LogWarning($"{mesh}: no triangles"); + return false; + } + return true; + } + + VrmLib.Model _Export(INativeArrayManager arrayManager, GameObject root) + { + if (Model == null) + { + Model = new VrmLib.Model(VrmLib.Coordinates.Unity); + } + + // node + { + Model.Root.Name = root.name; + CreateNodes(root.transform, Model.Root, Nodes); + Model.Nodes = Nodes + .Where(x => x.Value != Model.Root) + .Select(x => x.Value).ToList(); + } + + // material and textures + var rendererComponents = root.GetComponentsInChildren(); + { + foreach (var renderer in rendererComponents) + { + var materials = renderer.sharedMaterials; // avoid copy + foreach (var material in materials) + { + if (Materials.Contains(material)) + { + continue; + } + + Model.Materials.Add(material); + Materials.Add(material); + } + } + } + + // mesh + { + foreach (var renderer in rendererComponents) + { + if (renderer is SkinnedMeshRenderer skinnedMeshRenderer) + { + if (MeshCanExport(skinnedMeshRenderer.sharedMesh)) + { + var mesh = CreateMesh(arrayManager, skinnedMeshRenderer.sharedMesh, skinnedMeshRenderer, Materials); + var skin = CreateSkin(arrayManager, skinnedMeshRenderer, Nodes, root); + if (skin != null) + { + // blendshape only で skinning が無いやつがある + mesh.Skin = skin; + Model.Skins.Add(mesh.Skin); + } + Model.MeshGroups.Add(mesh); + Nodes[renderer.gameObject].MeshGroup = mesh; + Meshes.Add(skinnedMeshRenderer.sharedMesh, mesh); + } + } + else if (renderer is MeshRenderer meshRenderer) + { + var filter = meshRenderer.gameObject.GetComponent(); + if (filter != null && MeshCanExport(filter.sharedMesh)) + { + var mesh = CreateMesh(arrayManager, filter.sharedMesh, meshRenderer, Materials); + Model.MeshGroups.Add(mesh); + Nodes[renderer.gameObject].MeshGroup = mesh; + if (!Meshes.ContainsKey(filter.sharedMesh)) + { + Meshes.Add(filter.sharedMesh, mesh); + } + } + } + } + } + + return Model; + } + + private static void CreateNodes( + Transform parentTransform, + VrmLib.Node parentNode, + Dictionary nodes) + { + // parentNode.SetMatrix(parentTransform.localToWorldMatrix.ToNumericsMatrix4x4(), false); + parentNode.LocalTranslation = parentTransform.localPosition; + parentNode.LocalRotation = parentTransform.localRotation; + parentNode.LocalScaling = parentTransform.localScale; + nodes.Add(parentTransform.gameObject, parentNode); + + foreach (Transform child in parentTransform) + { + var childNode = new VrmLib.Node(child.gameObject.name); + CreateNodes(child, childNode, nodes); + parentNode.Add(childNode); + } + } + + private static Transform GetTransformFromRelativePath(Transform root, Queue relativePath) + { + var name = relativePath.Dequeue(); + foreach (Transform node in root) + { + if (node.gameObject.name == name) + { + if (relativePath.Count == 0) + { + return node; + } + else + { + return GetTransformFromRelativePath(node, relativePath); + } + } + } + + return null; + } + + private static VrmLib.MeshGroup CreateMesh(INativeArrayManager arrayManager, UnityEngine.Mesh mesh, Renderer renderer, List materials) + { + var meshGroup = new VrmLib.MeshGroup(mesh.name); + var vrmMesh = new VrmLib.Mesh(); + vrmMesh.VertexBuffer = new VrmLib.VertexBuffer(); + vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(arrayManager, mesh.vertices)); + + if (mesh.boneWeights.Length == mesh.vertexCount) + { + vrmMesh.VertexBuffer.Add( + VrmLib.VertexBuffer.WeightKey, + ToBufferAccessor(arrayManager, mesh.boneWeights.Select(x => + new Vector4(x.weight0, x.weight1, x.weight2, x.weight3)).ToArray() + )); + vrmMesh.VertexBuffer.Add( + VrmLib.VertexBuffer.JointKey, + ToBufferAccessor(arrayManager, mesh.boneWeights.Select(x => + new SkinJoints((ushort)x.boneIndex0, (ushort)x.boneIndex1, (ushort)x.boneIndex2, (ushort)x.boneIndex3)).ToArray() + )); + } + if (mesh.uv.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.TexCoordKey, ToBufferAccessor(arrayManager, mesh.uv)); + if (mesh.normals.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.NormalKey, ToBufferAccessor(arrayManager, mesh.normals)); + if (mesh.colors.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.ColorKey, ToBufferAccessor(arrayManager, mesh.colors)); + vrmMesh.IndexBuffer = ToBufferAccessor(arrayManager, mesh.triangles); + + int offset = 0; + for (int i = 0; i < mesh.subMeshCount; i++) + { +#if UNITY_2019 + var subMesh = mesh.GetSubMesh(i); + try + { + vrmMesh.Submeshes.Add(new VrmLib.Submesh(offset, subMesh.indexCount, materials.IndexOf(renderer.sharedMaterials[i]))); + } + catch (Exception ex) + { + Debug.LogError(ex); + } + offset += subMesh.indexCount; +#else + var triangles = mesh.GetTriangles(i); + try + { + vrmMesh.Submeshes.Add(new VrmLib.Submesh(offset, triangles.Length, materials.IndexOf(renderer.sharedMaterials[i]))); + } + catch (Exception ex) + { + Debug.LogError(ex); + } + offset += triangles.Length; +#endif + } + + for (int i = 0; i < mesh.blendShapeCount; i++) + { + var blendShapeVertices = mesh.vertices; + var usePosition = blendShapeVertices != null && blendShapeVertices.Length > 0; + + var blendShapeNormals = mesh.normals; + var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length; + // var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length && !exportOnlyBlendShapePosition; + + var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray(); + //var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length; + // var useTangent = false; + + var frameCount = mesh.GetBlendShapeFrameCount(i); + mesh.GetBlendShapeFrameVertices(i, frameCount - 1, blendShapeVertices, blendShapeNormals, null); + + if (usePosition) + { + var morphTarget = new VrmLib.MorphTarget(mesh.GetBlendShapeName(i)); + morphTarget.VertexBuffer = new VrmLib.VertexBuffer(); + morphTarget.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(arrayManager, blendShapeVertices)); + vrmMesh.MorphTargets.Add(morphTarget); + } + } + + meshGroup.Meshes.Add(vrmMesh); + return meshGroup; + } + + private static VrmLib.Skin CreateSkin(INativeArrayManager arrayManager, + SkinnedMeshRenderer skinnedMeshRenderer, + Dictionary nodes, + GameObject root) + { + if (skinnedMeshRenderer.bones == null || skinnedMeshRenderer.bones.Length == 0) + { + return null; + } + + var skin = new VrmLib.Skin(); + skin.InverseMatrices = ToBufferAccessor(arrayManager, skinnedMeshRenderer.sharedMesh.bindposes); + if (skinnedMeshRenderer.rootBone != null) + { + skin.Root = nodes[skinnedMeshRenderer.rootBone.gameObject]; + } + + skin.Joints = skinnedMeshRenderer.bones.Select(x => nodes[x.gameObject]).ToList(); + return skin; + } + + private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, SkinJoints[] values) + { + return ToBufferAccessor(arrayManager, values, AccessorValueType.UNSIGNED_SHORT, AccessorVectorType.VEC4); + } + + private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Color[] colors) + { + return ToBufferAccessor(arrayManager, colors, AccessorValueType.FLOAT, AccessorVectorType.VEC4); + } + + private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Vector4[] vectors) + { + return ToBufferAccessor(arrayManager, vectors, AccessorValueType.FLOAT, AccessorVectorType.VEC4); + } + + private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Vector3[] vectors) + { + return ToBufferAccessor(arrayManager, vectors, AccessorValueType.FLOAT, AccessorVectorType.VEC3); + } + + private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Vector2[] vectors) + { + return ToBufferAccessor(arrayManager, vectors, AccessorValueType.FLOAT, AccessorVectorType.VEC2); + } + + private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, int[] scalars) + { + return ToBufferAccessor(arrayManager, scalars, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR); + } + + private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Matrix4x4[] matrixes) + { + return ToBufferAccessor(arrayManager, matrixes, AccessorValueType.FLOAT, AccessorVectorType.MAT4); + } + + private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, T[] value, AccessorValueType valueType, AccessorVectorType vectorType) where T : struct + { + return new BufferAccessor(arrayManager, + arrayManager.CreateNativeArray(value).Reinterpret(Marshal.SizeOf()), + valueType, + vectorType, + value.Length + ); + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Model/ModelExporter.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/ModelExporter.cs.meta new file mode 100644 index 000000000..56f9b9e26 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/ModelExporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 096d30ddf9b2aee4f96746f05610d75f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Model/ModelReader.cs b/Assets/External/VRM10/Runtime/IO/Model/ModelReader.cs new file mode 100644 index 000000000..d03c2d3be --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/ModelReader.cs @@ -0,0 +1,136 @@ +using System; +using System.IO; +using System.Linq; +using VrmLib; + +namespace UniVRM10 +{ + /// + /// GLTF => VrmLib.Model + /// + public static class ModelReader + { + static Model Load(Vrm10ImportData storage, string rootName, Coordinates coords) + { + if (storage == null) + { + return null; + } + + var model = new Model(coords) + { + AssetVersion = storage.AssetVersion, + AssetGenerator = storage.AssetGenerator, + AssetCopyright = storage.AssetCopyright, + AssetMinVersion = storage.AssetMinVersion, + Coordinates = coords, + }; + + // node + model.Root.Name = rootName; + for (var i = 0; i < storage.NodeCount; ++i) + { + var node = storage.CreateNode(i); + model.Nodes.Add(node); + } + for (var i = 0; i < model.Nodes.Count; ++i) + { + var parent = model.Nodes[i]; + foreach (var j in storage.GetChildNodeIndices(i)) + { + var child = model.Nodes[j]; + parent.Add(child); + } + } + foreach (var x in model.Nodes) + { + if (x.Parent == null) + { + model.Root.Add(x); + } + } + + // skin + model.Skins.AddRange(Enumerable.Range(0, storage.SkinCount).Select(x => storage.CreateSkin(x, model.Nodes))); + + // mesh + model.MeshGroups.AddRange(Enumerable.Range(0, storage.MeshCount).Select(x => storage.CreateMesh(x))); + + // skin + for (int i = 0; i < storage.NodeCount; ++i) + { + var (meshIndex, skinIndex) = storage.GetNodeMeshSkin(i); + if (meshIndex >= 0 && meshIndex < model.MeshGroups.Count) + { + var node = model.Nodes[i]; + var mesh = model.MeshGroups[meshIndex]; + node.MeshGroup = mesh; + if (skinIndex >= 0 && skinIndex < model.Skins.Count) + { + var skin = model.Skins[skinIndex]; + mesh.Skin = skin; + } + } + } + + // boneWeight の付与 + foreach (var meshGroup in model.MeshGroups) + { + if (meshGroup.Skin == null && meshGroup.Meshes.Any(mesh => mesh.MorphTargets.Count > 0)) + { + // Skinning が無くて MorphTarget が有る場合に実施する + var nodes = model.Nodes.Where(node => node.MeshGroup == meshGroup).ToArray(); + if (nodes.Length != 1) + { + // throw new NotImplementedException(); + // このメッシュが複数のノードから共有されている場合は、 + // 個別に Skin を作成する必要があり、 + // 異なる bindPoses が必要になるため mesh の複製が必要になる! + // 稀にあるかもしれない。 + continue; + } + var node = nodes[0]; + + // add bone weight + foreach (var mesh in meshGroup.Meshes) + { + // all (1, 0, 0, 0) + var weights = storage.Data.NativeArrayManager.CreateNativeArray(mesh.VertexBuffer.Count); + for (int i = 0; i < weights.Length; ++i) + { + weights[i] = new UnityEngine.Vector4(1, 0, 0, 0); + } + mesh.VertexBuffer.Add(VertexBuffer.WeightKey, new UniGLTF.BufferAccessor(storage.Data.NativeArrayManager, weights.Reinterpret(16), UniGLTF.AccessorValueType.FLOAT, UniGLTF.AccessorVectorType.VEC4, weights.Length)); + + // all zero + var joints = storage.Data.NativeArrayManager.CreateNativeArray(mesh.VertexBuffer.Count); + mesh.VertexBuffer.Add(VertexBuffer.JointKey, new UniGLTF.BufferAccessor(storage.Data.NativeArrayManager, joints.Reinterpret(8), UniGLTF.AccessorValueType.UNSIGNED_SHORT, UniGLTF.AccessorVectorType.VEC4, joints.Length)); + } + + // bind matrix + var bindMatrices = storage.Data.NativeArrayManager.CreateNativeArray(1); + bindMatrices[0] = node.Matrix.inverse; + + // skinning + meshGroup.Skin = new Skin + { + GltfIndex = -1, + Joints = new System.Collections.Generic.List { node }, + Root = node, + InverseMatrices = new UniGLTF.BufferAccessor(storage.Data.NativeArrayManager, bindMatrices.Reinterpret(64), UniGLTF.AccessorValueType.FLOAT, UniGLTF.AccessorVectorType.MAT4, bindMatrices.Length), + }; + } + } + + return model; + } + + public static Model Read(UniGLTF.GltfData data, Coordinates? coords = default) + { + var storage = new Vrm10ImportData(data); + var model = Load(storage, Path.GetFileName(data.TargetPath), coords.GetValueOrDefault(Coordinates.Vrm1)); + model.ConvertCoordinate(Coordinates.Unity); + return model; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Model/ModelReader.cs.meta b/Assets/External/VRM10/Runtime/IO/Model/ModelReader.cs.meta new file mode 100644 index 000000000..f9a24df05 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Model/ModelReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb219f8797f990649a7531dbb96d3305 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Texture.meta b/Assets/External/VRM10/Runtime/IO/Texture.meta new file mode 100644 index 000000000..742b5460d --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Texture.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7fe27001b96146d3bbc53044ff91b536 +timeCreated: 1620374936 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs b/Assets/External/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs new file mode 100644 index 000000000..9dbba8a44 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using UniGLTF; +using UniGLTF.Extensions.VRMC_materials_mtoon; +using UnityEngine; +using VRMShaders; +using VRMShaders.VRM10.MToon10.Runtime; + +namespace UniVRM10 +{ + public static class Vrm10MToonTextureImporter + { + public static IEnumerable<(string key, (SubAssetKey, TextureDescriptor))> EnumerateAllTextures(GltfData data, glTFMaterial material, VRMC_materials_mtoon mToon) + { + if (TryGetBaseColorTexture(data, material, out var key, out var desc)) + { + yield return (MToon10Prop.BaseColorTexture.ToUnityShaderLabName(), (key, desc)); + } + + if (TryGetEmissiveTexture(data, material, out key, out desc)) + { + yield return (MToon10Prop.EmissiveTexture.ToUnityShaderLabName(), (key, desc)); + } + + if (TryGetNormalTexture(data, material, out key, out desc)) + { + yield return (MToon10Prop.NormalTexture.ToUnityShaderLabName(), (key, desc)); + } + + if (TryGetShadeMultiplyTexture(data, mToon, out key, out desc)) + { + yield return (MToon10Prop.ShadeColorTexture.ToUnityShaderLabName(), (key, desc)); + } + + if (TryGetShadingShiftTexture(data, mToon, out key, out desc)) + { + yield return (MToon10Prop.ShadingShiftTexture.ToUnityShaderLabName(), (key, desc)); + } + + if (TryGetMatcapTexture(data, mToon, out key, out desc)) + { + yield return (MToon10Prop.MatcapTexture.ToUnityShaderLabName(), (key, desc)); + } + + if (TryGetRimMultiplyTexture(data, mToon, out key, out desc)) + { + yield return (MToon10Prop.RimMultiplyTexture.ToUnityShaderLabName(), (key, desc)); + } + + if (TryGetOutlineWidthMultiplyTexture(data, mToon, out key, out desc)) + { + yield return (MToon10Prop.OutlineWidthMultiplyTexture.ToUnityShaderLabName(), (key, desc)); + } + + if (TryGetUvAnimationMaskTexture(data, mToon, out key, out desc)) + { + yield return (MToon10Prop.UvAnimationMaskTexture.ToUnityShaderLabName(), (key, desc)); + } + } + + private static bool TryGetBaseColorTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) + { + try + { + return GltfPbrTextureImporter.TryBaseColorTexture(data, src, out key, out desc); + } + catch (NullReferenceException) + { + key = default; + desc = default; + return false; + } + catch (ArgumentOutOfRangeException) + { + key = default; + desc = default; + return false; + } + } + + private static bool TryGetEmissiveTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) + { + try + { + return GltfPbrTextureImporter.TryEmissiveTexture(data, src, out key, out desc); + } + catch (NullReferenceException) + { + key = default; + desc = default; + return false; + } + catch (ArgumentOutOfRangeException) + { + key = default; + desc = default; + return false; + } + + } + + private static bool TryGetNormalTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) + { + try + { + return GltfPbrTextureImporter.TryNormalTexture(data, src, out key, out desc); + } + catch (NullReferenceException) + { + key = default; + desc = default; + return false; + } + catch (ArgumentOutOfRangeException) + { + key = default; + desc = default; + return false; + } + } + + private static bool TryGetShadeMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) + { + return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.ShadeMultiplyTexture), out key, out desc); + } + + private static bool TryGetShadingShiftTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) + { + return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.ShadingShiftTexture), out key, out desc); + } + + private static bool TryGetMatcapTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) + { + return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.MatcapTexture), out key, out desc); + } + + private static bool TryGetRimMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) + { + return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.RimMultiplyTexture), out key, out desc); + } + + private static bool TryGetOutlineWidthMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) + { + return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.OutlineWidthMultiplyTexture), out key, out desc); + } + + private static bool TryGetUvAnimationMaskTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) + { + return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.UvAnimationMaskTexture), out key, out desc); + } + + private static bool TryGetSRGBTexture(GltfData data, Vrm10TextureInfo info, out SubAssetKey key, out TextureDescriptor desc) + { + try + { + var (offset, scale) = GetTextureOffsetAndScale(info); + return GltfTextureImporter.TryCreateSrgb(data, info.index, offset, scale, out key, out desc); + } + catch (NullReferenceException) + { + key = default; + desc = default; + return false; + } + catch (ArgumentOutOfRangeException) + { + key = default; + desc = default; + return false; + } + } + private static bool TryGetLinearTexture(GltfData data, Vrm10TextureInfo info, out SubAssetKey key, out TextureDescriptor desc) + { + try + { + var (offset, scale) = GetTextureOffsetAndScale(info); + return GltfTextureImporter.TryCreateLinear(data, info.index, offset, scale, out key, out desc); + } + catch (NullReferenceException) + { + key = default; + desc = default; + return false; + } + catch (ArgumentOutOfRangeException) + { + key = default; + desc = default; + return false; + } + } + + private static (Vector2, Vector2) GetTextureOffsetAndScale(Vrm10TextureInfo textureInfo) + { + if (glTF_KHR_texture_transform.TryGet(textureInfo, out var textureTransform)) + { + return GltfTextureImporter.GetTextureOffsetAndScale(textureTransform); + } + return (new Vector2(0, 0), new Vector2(1, 1)); + } + + /// + /// MToon 定義内の TextureInfo を glTFTextureInfo として扱う入れ物 + /// + private sealed class Vrm10TextureInfo : glTFTextureInfo + { + public Vrm10TextureInfo(TextureInfo info) + { + if (info == null) return; + + index = info.Index ?? -1; + texCoord = info.TexCoord ?? -1; + extensions = info.Extensions as glTFExtension; + extras = info.Extras as glTFExtension; + } + + public Vrm10TextureInfo(ShadingShiftTextureInfo info) + { + if (info == null) return; + + index = info.Index ?? -1; + texCoord = info.TexCoord ?? -1; + extensions = info.Extensions as glTFExtension; + extras = info.Extras as glTFExtension; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs.meta b/Assets/External/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs.meta new file mode 100644 index 000000000..42eafa208 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1384da3bd22c4c4cb39c59d57b9c419a +timeCreated: 1620387929 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Texture/Vrm10TextureDescriptorGenerator.cs b/Assets/External/VRM10/Runtime/IO/Texture/Vrm10TextureDescriptorGenerator.cs new file mode 100644 index 000000000..7a6db9e79 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Texture/Vrm10TextureDescriptorGenerator.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using UniGLTF; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + public sealed class Vrm10TextureDescriptorGenerator : ITextureDescriptorGenerator + { + public const string UniqueThumbnailName = "thumbnail__VRM10"; + + private readonly GltfData m_data; + private TextureDescriptorSet _textureDescriptorSet; + + public Vrm10TextureDescriptorGenerator(GltfData data) + { + m_data = data; + } + + public TextureDescriptorSet Get() + { + if (_textureDescriptorSet == null) + { + _textureDescriptorSet = new TextureDescriptorSet(); + foreach (var (_, param) in EnumerateAllTextures(m_data)) + { + _textureDescriptorSet.Add(param); + } + } + return _textureDescriptorSet; + } + + /// + /// glTF 全体で使うテクスチャーを列挙する + /// + private static IEnumerable<(SubAssetKey, TextureDescriptor)> EnumerateAllTextures(GltfData data) + { + if (!UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(data.GLTF.extensions, out UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm)) + { + throw new System.Exception("not vrm"); + } + + // Textures referenced by Materials. + for (var materialIdx = 0; materialIdx < data.GLTF.materials.Count; ++materialIdx) + { + var m = data.GLTF.materials[materialIdx]; + if (UniGLTF.Extensions.VRMC_materials_mtoon.GltfDeserializer.TryGet(m.extensions, out var mToon)) + { + foreach (var (_, tex) in Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mToon)) + { + yield return tex; + } + } + else + { + // Fallback to glTF PBR & glTF Unlit + foreach (var tex in GltfPbrTextureImporter.EnumerateAllTextures(data, materialIdx)) + { + yield return tex; + } + } + } + + // Thumbnail Texture referenced by VRM Meta. + if (TryGetMetaThumbnailTextureImportParam(data, vrm, out (SubAssetKey key, TextureDescriptor) thumbnail)) + { + yield return thumbnail; + } + } + + /// + /// VRM-1 の thumbnail テクスチャー。gltf.textures ではなく gltf.images の参照であることに注意(sampler等の設定が無い) + /// + public static bool TryGetMetaThumbnailTextureImportParam(GltfData data, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, out (SubAssetKey, TextureDescriptor) value) + { + if (vrm?.Meta?.ThumbnailImage == null) + { + value = default; + return false; + } + var thumbnailImage = vrm.Meta.ThumbnailImage; + if (!thumbnailImage.HasValue) + { + value = default; + return false; + } + var imageIndex = thumbnailImage.Value; + if (imageIndex < 0 || imageIndex >= data.GLTF.images.Count) + { + value = default; + return false; + } + + var gltfImage = data.GLTF.images[imageIndex]; + + // data.GLTF.textures は前処理によりユニーク性がある + // unique な名前を振り出す + var used = new HashSet(data.GLTF.textures.Select(x => x.name)); + var uniqueName = GlbLowLevelParser.FixNameUnique(used, UniqueThumbnailName); + + value = GltfTextureImporter.CreateSrgbFromOnlyImage(data, imageIndex, uniqueName, gltfImage.uri); + return true; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Texture/Vrm10TextureDescriptorGenerator.cs.meta b/Assets/External/VRM10/Runtime/IO/Texture/Vrm10TextureDescriptorGenerator.cs.meta new file mode 100644 index 000000000..2b3beb931 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Texture/Vrm10TextureDescriptorGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7763318be4064ecba712dcc012dd1cb1 +timeCreated: 1620374912 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/UnityExtension.cs b/Assets/External/VRM10/Runtime/IO/UnityExtension.cs new file mode 100644 index 000000000..2cb803a0b --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/UnityExtension.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace UniVRM10 +{ + public static class UnityExtension + { + public static float[] ToFloat3(this Vector3 value) + { + return new[] { value.x, value.y, value.z }; + } + + public static float[] ToFloat4(this Quaternion value) + { + return new float[] { value.x, value.y, value.z, value.w }; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/UnityExtension.cs.meta b/Assets/External/VRM10/Runtime/IO/UnityExtension.cs.meta new file mode 100644 index 000000000..53aba7905 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/UnityExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65d06a069acdcb642b8dde60f250e5e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10.cs b/Assets/External/VRM10/Runtime/IO/Vrm10.cs new file mode 100644 index 000000000..73904892f --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10.cs @@ -0,0 +1,342 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using UniGLTF; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + /// + /// High-level VRM-1.0 loading API. + /// + public static class Vrm10 + { + /// + /// You can receive the thumbnail texture and the meta information. + /// `vrm10Meta` will be available if the model was vrm-1.0. + /// `vrm0Meta` will be available if the model was vrm-0.x. + /// + public delegate void VrmMetaInformationCallback(Texture2D thumbnail, UniGLTF.Extensions.VRMC_vrm.Meta vrm10Meta, Migration.Vrm0Meta vrm0Meta); + + /// + /// Load the VRM file from the path. + /// + /// You should call this on Unity main thread. + /// This will throw Exceptions (include OperationCanceledException). + /// + /// vrm file path + /// if true, this loader can load the vrm-0.x model as vrm-1.0 model with migration. + /// the flag of generating the control rig provides bone manipulation unified between models. + /// if true, show meshes when loaded. + /// this loader use specified await strategy. + /// this loader use specified texture deserialization strategy. + /// this loader use specified material generation strategy. + /// return callback that notify meta information before loading. + /// CancellationToken + /// vrm-1.0 instance. Maybe return null if unexpected error was raised. + public static async Task LoadPathAsync( + string path, + bool canLoadVrm0X = true, + ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate, + bool showMeshes = true, + IAwaitCaller awaitCaller = null, + ITextureDeserializer textureDeserializer = null, + IMaterialDescriptorGenerator materialGenerator = null, + VrmMetaInformationCallback vrmMetaInformationCallback = null, + CancellationToken ct = default) + { + if (awaitCaller == null) + { + awaitCaller = Application.isPlaying + ? (IAwaitCaller)new RuntimeOnlyAwaitCaller() + : (IAwaitCaller)new ImmediateCaller(); + } + + return await LoadAsync( + path, + System.IO.File.ReadAllBytes(path), + canLoadVrm0X, + controlRigGenerationOption, + showMeshes, + awaitCaller, + textureDeserializer, + materialGenerator, + vrmMetaInformationCallback, + ct); + } + + /// + /// Load the VRM file from the binary. + /// + /// You should call this on Unity main thread. + /// This will throw Exceptions (include OperationCanceledException). + /// + /// vrm file data + /// if true, this loader can load the vrm-0.x model as vrm-1.0 model with migration. + /// the flag of generating the control rig provides bone manipulation unified between models. + /// if true, show meshes when loaded. + /// this loader use specified await strategy. + /// this loader use specified texture deserialization strategy. + /// this loader use specified material generation strategy. + /// return callback that notify meta information before loading. + /// CancellationToken + /// vrm-1.0 instance. Maybe return null if unexpected error was raised. + public static async Task LoadBytesAsync( + byte[] bytes, + bool canLoadVrm0X = true, + ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate, + bool showMeshes = true, + IAwaitCaller awaitCaller = null, + ITextureDeserializer textureDeserializer = null, + IMaterialDescriptorGenerator materialGenerator = null, + VrmMetaInformationCallback vrmMetaInformationCallback = null, + CancellationToken ct = default) + { + if (awaitCaller == null) + { + awaitCaller = Application.isPlaying + ? (IAwaitCaller)new RuntimeOnlyAwaitCaller() + : (IAwaitCaller)new ImmediateCaller(); + } + + return await LoadAsync( + string.Empty, + bytes, + canLoadVrm0X, + controlRigGenerationOption, + showMeshes, + awaitCaller, + textureDeserializer, + materialGenerator, + vrmMetaInformationCallback, + ct); + } + + private static async Task LoadAsync( + string name, + byte[] bytes, + bool canLoadVrm0X, + ControlRigGenerationOption controlRigGenerationOption, + bool showMeshes, + IAwaitCaller awaitCaller, + ITextureDeserializer textureDeserializer, + IMaterialDescriptorGenerator materialGenerator, + VrmMetaInformationCallback vrmMetaInformationCallback, + CancellationToken ct) + { + ct.ThrowIfCancellationRequested(); + if (awaitCaller == null) + { + throw new ArgumentNullException(); + } + + using (var gltfData = new GlbLowLevelParser(name, bytes).Parse()) + { + // 1. Try loading as vrm-1.0 + var instance = await TryLoadingAsVrm10Async( + gltfData, + controlRigGenerationOption, + showMeshes, + awaitCaller, + textureDeserializer, + materialGenerator, + vrmMetaInformationCallback, + ct); + if (instance != null) + { + if (ct.IsCancellationRequested) + { + UnityObjectDestroyer.DestroyRuntimeOrEditor(instance.gameObject); + ct.ThrowIfCancellationRequested(); + } + return instance; + } + + // 2. Stop loading if not allowed migration. + if (!canLoadVrm0X) + { + throw new Exception($"Failed to load as VRM 1.0: {name}"); + } + + // 3. Try migration from vrm-0.x into vrm-1.0 + var migratedInstance = await TryMigratingFromVrm0XAsync( + gltfData, + controlRigGenerationOption, + showMeshes, + awaitCaller, + textureDeserializer, + materialGenerator, + vrmMetaInformationCallback, + ct); + if (migratedInstance != null) + { + if (ct.IsCancellationRequested) + { + UnityObjectDestroyer.DestroyRuntimeOrEditor(migratedInstance.gameObject); + ct.ThrowIfCancellationRequested(); + } + return migratedInstance; + } + + // 4. Failed loading. + throw new Exception($"Failed to load: {name}"); + } + } + + private static async Task TryLoadingAsVrm10Async( + GltfData gltfData, + ControlRigGenerationOption controlRigGenerationOption, + bool showMeshes, + IAwaitCaller awaitCaller, + ITextureDeserializer textureDeserializer, + IMaterialDescriptorGenerator materialGenerator, + VrmMetaInformationCallback vrmMetaInformationCallback, + CancellationToken ct) + { + ct.ThrowIfCancellationRequested(); + if (awaitCaller == null) + { + throw new ArgumentNullException(); + } + + var vrm10Data = await awaitCaller.Run(() => Vrm10Data.Parse(gltfData)); + ct.ThrowIfCancellationRequested(); + + if (vrm10Data == null) + { + // NOTE: Failed to parse as VRM 1.0. + return null; + } + + return await LoadVrm10DataAsync( + vrm10Data, + null, + controlRigGenerationOption, + showMeshes, + awaitCaller, + textureDeserializer, + materialGenerator, + vrmMetaInformationCallback, + ct); + } + + private static async Task TryMigratingFromVrm0XAsync( + GltfData gltfData, + ControlRigGenerationOption controlRigGenerationOption, + bool showMeshes, + IAwaitCaller awaitCaller, + ITextureDeserializer textureDeserializer, + IMaterialDescriptorGenerator materialGenerator, + VrmMetaInformationCallback vrmMetaInformationCallback, + CancellationToken ct) + { + ct.ThrowIfCancellationRequested(); + if (awaitCaller == null) + { + throw new ArgumentNullException(); + } + + Vrm10Data migratedVrm10Data = default; + MigrationData migrationData = default; + using (var migratedGltfData = await awaitCaller.Run(() => Vrm10Data.Migrate(gltfData, out migratedVrm10Data, out migrationData))) + { + ct.ThrowIfCancellationRequested(); + + if (migratedVrm10Data == null) + { + throw new Exception(migrationData?.Message ?? "Failed to migrate."); + } + + var migratedVrm10Instance = await LoadVrm10DataAsync( + migratedVrm10Data, + migrationData, + controlRigGenerationOption, + showMeshes, + awaitCaller, + textureDeserializer, + materialGenerator, + vrmMetaInformationCallback, + ct); + if (migratedVrm10Instance == null) + { + throw new Exception(migrationData?.Message ?? "Failed to load migrated."); + } + return migratedVrm10Instance; + } + } + + private static async Task LoadVrm10DataAsync( + Vrm10Data vrm10Data, + MigrationData migrationData, + ControlRigGenerationOption controlRigGenerationOption, + bool showMeshes, + IAwaitCaller awaitCaller, + ITextureDeserializer textureDeserializer, + IMaterialDescriptorGenerator materialGenerator, + VrmMetaInformationCallback vrmMetaInformationCallback, + CancellationToken ct) + { + ct.ThrowIfCancellationRequested(); + if (awaitCaller == null) + { + throw new ArgumentNullException(); + } + + if (vrm10Data == null) + { + throw new ArgumentNullException(nameof(vrm10Data)); + } + + using (var loader = new Vrm10Importer( + vrm10Data, + textureDeserializer: textureDeserializer, + materialGenerator: materialGenerator, + useControlRig: controlRigGenerationOption != ControlRigGenerationOption.None)) + { + // 1. Load meta information if callback was available. + if (vrmMetaInformationCallback != null) + { + var thumbnail = await loader.LoadVrmThumbnailAsync(); + if (migrationData != null) + { + vrmMetaInformationCallback(thumbnail, default, migrationData.OriginalMetaBeforeMigration); + } + else + { + vrmMetaInformationCallback(thumbnail, vrm10Data.VrmExtension.Meta, default); + } + } + + // 2. Load + // NOTE: Current Vrm10Importer.LoadAsync implementation CAN'T ABORT. + var gltfInstance = await loader.LoadAsync(awaitCaller); + if (gltfInstance == null) + { + throw new Exception("Failed to load by unknown reason."); + } + + var vrm10Instance = gltfInstance.GetComponent(); + if (vrm10Instance == null) + { + gltfInstance.Dispose(); + throw new Exception("Failed to load as VRM by unknown reason."); + } + + if (ct.IsCancellationRequested) + { + // NOTE: Destroy before showing meshes if canceled. + gltfInstance.Dispose(); + ct.ThrowIfCancellationRequested(); + } + + if (showMeshes) + { + gltfInstance.ShowMeshes(); + } + return vrm10Instance; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10.cs.meta b/Assets/External/VRM10/Runtime/IO/Vrm10.cs.meta new file mode 100644 index 000000000..35ccb4aa7 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f72a5b1ead7de6a4f8797b5537e2ecfc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10Data.cs b/Assets/External/VRM10/Runtime/IO/Vrm10Data.cs new file mode 100644 index 000000000..f2a29f429 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10Data.cs @@ -0,0 +1,133 @@ +using System; +using System.IO; +using System.Linq; +using UniGLTF; +using UniGLTF.Extensions.VRMC_vrm; +using UniJSON; +using UnityEngine; + +namespace UniVRM10 +{ + public class Vrm10Data + { + public GltfData Data { get; } + public UniGLTF.Extensions.VRMC_vrm.VRMC_vrm VrmExtension { get; } + + Vrm10Data(GltfData data, VRMC_vrm vrm) + { + Data = data; + VrmExtension = vrm; + } + + /// + /// VRM-1.0 拡張を取得する。 + /// + /// + /// 失敗したら null が返る + public static Vrm10Data Parse(GltfData data) + { + if (!UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(data.GLTF.extensions, out var vrm)) + { + return null; + } + return new Vrm10Data(data, vrm); + } + + /// + /// + /// + /// + /// + /// + /// Migrated GltfData if succeeded. Must Dispose + public static GltfData Migrate(GltfData data, out Vrm10Data vrm1Data, out MigrationData migration) + { + var json = data.Json.ParseAsJson(); + if (!json.TryGet("extensions", out JsonNode extensions)) + { + vrm1Data = default; + migration = new MigrationData("gltf: no extensions"); + return null; + } + + if (!extensions.TryGet("VRM", out JsonNode vrm0)) + { + vrm1Data = default; + migration = new MigrationData("gltf: no vrm0"); + return null; + } + + // found vrm0 + var oldMeta = Migration.Vrm0Meta.FromJsonBytes(json); + if (oldMeta == null) + { + throw new NullReferenceException("oldMeta"); + } + + // try migrate... + byte[] migrated = null; + try + { + migrated = MigrationVrm.Migrate(data); + if (migrated == null) + { + vrm1Data = default; + migration = new MigrationData("Found vrm0. But fail to migrate", oldMeta); + return null; + } + } + catch (MigrationException ex) + { + // migration 失敗 + vrm1Data = default; + migration = new MigrationData(ex.ToString(), oldMeta); + return null; + } + catch (Exception ex) + { + // その他のエラー + vrm1Data = default; + migration = new MigrationData(ex.ToString(), oldMeta); + return null; + } + + byte[] debugCopy = null; + if (VRMShaders.Symbols.VRM_DEVELOP) + { + // load 時の右手左手座標変換でバッファが破壊的変更されるので、コピーを作っている + debugCopy = migrated.Select(x => x).ToArray(); + } + + // マイグレーション結果をパースする + var migratedData = new GlbLowLevelParser(data.TargetPath, migrated).Parse(); + try + { + if (!UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(migratedData.GLTF.extensions, out VRMC_vrm vrm)) + { + // migration した結果のパースに失敗した ! + vrm1Data = default; + migration = new MigrationData("vrm0: migrate but error ?", oldMeta, migrated); + // 破棄 + migratedData.Dispose(); + return null; + } + + { + // success. 非null値が返るのはここだけ。 + vrm1Data = new Vrm10Data(migratedData, vrm); + migration = new MigrationData("vrm0: migrated", oldMeta, debugCopy); + return migratedData; + } + } + catch (Exception ex) + { + Debug.LogWarning(ex); + vrm1Data = default; + migration = new MigrationData(ex.Message); + // 破棄 + migratedData.Dispose(); + return null; + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10Data.cs.meta b/Assets/External/VRM10/Runtime/IO/Vrm10Data.cs.meta new file mode 100644 index 000000000..0f2c437cf --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10Data.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3f895ff50d723e42b14bc126f90387e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10Exception.cs b/Assets/External/VRM10/Runtime/IO/Vrm10Exception.cs new file mode 100644 index 000000000..b9aff3bcd --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10Exception.cs @@ -0,0 +1,16 @@ +using System; + +namespace UniVRM10 +{ + public class Vrm10Exception : Exception + { + public Vrm10Exception(string msg) : base(msg) + { } + } + + public class Vrm10NoExtensionException : Vrm10Exception + { + public Vrm10NoExtensionException(string msg) : base(msg) + { } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10Exception.cs.meta b/Assets/External/VRM10/Runtime/IO/Vrm10Exception.cs.meta new file mode 100644 index 000000000..753965759 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10Exception.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9f647d546d16914d941ce33e1f83ff6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/External/VRM10/Runtime/IO/Vrm10Exporter.cs new file mode 100644 index 000000000..e77ce7eae --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -0,0 +1,796 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UnityEngine; +using VrmLib; +using VRMShaders; + + +namespace UniVRM10 +{ + public class Vrm10Exporter : IDisposable + { + public const string VRM_SPEC_VERSION = "1.0"; + public const string SPRINGBONE_SPEC_VERSION = "1.0"; + public const string NODE_CONSTRAINT_SPEC_VERSION = "1.0"; + public const string MTOON_SPEC_VERSION = "1.0"; + + public const string LICENSE_URL_JA = "https://vrm.dev/licenses/1.0/"; + public const string LICENSE_URL_EN = "https://vrm.dev/licenses/1.0/en/"; + + public readonly ExportingGltfData Storage = new ExportingGltfData(); + + public readonly string VrmExtensionName = "VRMC_vrm"; + + ITextureSerializer m_textureSerializer; + TextureExporter m_textureExporter; + + GltfExportSettings m_settings; + + public Vrm10Exporter(ITextureSerializer textureSerializer, GltfExportSettings settings) + { + m_settings = settings; + + if (textureSerializer == null) + { + throw new ArgumentException(nameof(textureSerializer)); + } + + Storage.Gltf.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName); + Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm.ExtensionName); + Storage.Gltf.extensionsUsed.Add(glTF_KHR_materials_unlit.ExtensionName); + Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon.ExtensionName); + Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_springBone.VRMC_springBone.ExtensionName); + Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint.ExtensionName); + + m_textureSerializer = textureSerializer; + m_textureExporter = new TextureExporter(m_textureSerializer); + } + + public void Dispose() + { + m_textureExporter.Dispose(); + } + + public static glTFAssets ExportAsset(Model model) + { + var asset = new glTFAssets(); + if (!string.IsNullOrEmpty(model.AssetVersion)) asset.version = model.AssetVersion; + if (!string.IsNullOrEmpty(model.AssetMinVersion)) asset.minVersion = model.AssetMinVersion; + if (!string.IsNullOrEmpty(model.AssetGenerator)) asset.generator = model.AssetGenerator; + if (!string.IsNullOrEmpty(model.AssetCopyright)) asset.copyright = model.AssetCopyright; + return asset; + } + + public static IEnumerable ExportMeshes(List groups, List materials, ExportingGltfData data, ExportArgs option) + { + foreach (var group in groups) + { + yield return group.ExportMeshGroup(materials, data, option); + } + } + + public static IEnumerable<(glTFNode, glTFSkin)> ExportNodes(INativeArrayManager arrayManager, List nodes, List groups, ExportingGltfData data, ExportArgs option) + { + foreach (var node in nodes) + { + var gltfNode = new glTFNode + { + name = node.Name, + }; + glTFSkin gltfSkin = default; + + gltfNode.translation = node.LocalTranslation.ToFloat3(); + gltfNode.rotation = node.LocalRotation.ToFloat4(); + gltfNode.scale = node.LocalScaling.ToFloat3(); + + if (node.MeshGroup != null) + { + gltfNode.mesh = groups.IndexOfThrow(node.MeshGroup); + var skin = node.MeshGroup.Skin; + if (skin != null) + { + gltfSkin = new glTFSkin() + { + joints = skin.Joints.Select(joint => nodes.IndexOfThrow(joint)).ToArray() + }; + if (skin.InverseMatrices == null) + { + skin.CalcInverseMatrices(arrayManager); + } + if (skin.InverseMatrices != null) + { + gltfSkin.inverseBindMatrices = skin.InverseMatrices.AddAccessorTo(data, 0, option.sparse); + } + if (skin.Root != null) + { + gltfSkin.skeleton = nodes.IndexOf(skin.Root); + } + } + } + + gltfNode.children = node.Children.Select(child => nodes.IndexOfThrow(child)).ToArray(); + + yield return (gltfNode, gltfSkin); + } + } + + /// + /// revere X + /// + /// + /// + static float[] ReverseX(Vector3 v) + { + return new float[] { -v.x, v.y, v.z }; + } + + /// + /// 必要な容量を計算 + /// (sparseは考慮してないので大きめ) + static int CalcReserveBytes(Model model) + { + int reserveBytes = 0; + // mesh + foreach (var g in model.MeshGroups) + { + foreach (var mesh in g.Meshes) + { + // 頂点バッファ + reserveBytes += mesh.IndexBuffer.ByteLength; + foreach (var kv in mesh.VertexBuffer) + { + reserveBytes += kv.Value.ByteLength; + } + // morph + foreach (var morph in mesh.MorphTargets) + { + foreach (var kv in morph.VertexBuffer) + { + reserveBytes += kv.Value.ByteLength; + } + } + } + } + return reserveBytes; + } + + static IEnumerable ExportMaterials(Model model, ITextureExporter textureExporter, GltfExportSettings settings) + { + var materialExporter = new BuiltInVrm10MaterialExporter(); + foreach (Material material in model.Materials) + { + yield return materialExporter.ExportMaterial(material, textureExporter, settings); + } + } + + public void Export(GameObject root, Model model, ModelExporter converter, ExportArgs option, VRM10ObjectMeta vrmMeta = null) + { + Storage.Gltf.asset = ExportAsset(model); + + Storage.Reserve(CalcReserveBytes(model)); + + foreach (var material in ExportMaterials(model, m_textureExporter, m_settings)) + { + Storage.Gltf.materials.Add(material); + } + + foreach (var mesh in ExportMeshes(model.MeshGroups, model.Materials, Storage, option)) + { + Storage.Gltf.meshes.Add(mesh); + } + + using (var arrayManager = new NativeArrayManager()) + { + foreach (var (node, skin) in ExportNodes(arrayManager, model.Nodes, model.MeshGroups, Storage, option)) + { + Storage.Gltf.nodes.Add(node); + if (skin != null) + { + var skinIndex = Storage.Gltf.skins.Count; + Storage.Gltf.skins.Add(skin); + node.skin = skinIndex; + } + } + } + Storage.Gltf.scenes.Add(new gltfScene() + { + nodes = model.Root.Children.Select(child => model.Nodes.IndexOfThrow(child)).ToArray() + }); + + var (vrm, vrmSpringBone, thumbnailTextureIndex) = ExportVrm(root, model, converter, vrmMeta, Storage.Gltf.nodes, m_textureExporter); + + // Extension で Texture が増える場合があるので最後に呼ぶ + var exportedTextures = m_textureExporter.Export(); + for (var exportedTextureIdx = 0; exportedTextureIdx < exportedTextures.Count; ++exportedTextureIdx) + { + var (unityTexture, texColorSpace) = exportedTextures[exportedTextureIdx]; + GltfTextureExporter.PushGltfTexture(Storage, unityTexture, texColorSpace, m_textureSerializer); + } + + if (thumbnailTextureIndex.HasValue) + { + vrm.Meta.ThumbnailImage = Storage.Gltf.textures[thumbnailTextureIndex.Value].source; + } + + UniGLTF.Extensions.VRMC_vrm.GltfSerializer.SerializeTo(ref Storage.Gltf.extensions, vrm); + + if (vrmSpringBone != null) + { + UniGLTF.Extensions.VRMC_springBone.GltfSerializer.SerializeTo(ref Storage.Gltf.extensions, vrmSpringBone); + } + + // Fix Duplicated name + gltfExporter.FixName(Storage.Gltf); + } + + + /// + /// VRMコンポーネントのエクスポート + /// + /// + /// + /// + /// + /// + /// + /// + /// + (UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, + UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone, + int? thumbnailIndex) ExportVrm(GameObject root, Model model, ModelExporter converter, + VRM10ObjectMeta vrmMeta, List nodes, ITextureExporter textureExporter) + { + var vrmController = root?.GetComponent(); + + if (vrmMeta == null) + { + if (vrmController?.Vrm?.Meta == null) + { + throw new NullReferenceException("metaObject is null"); + } + vrmMeta = vrmController.Vrm.Meta; + } + + var vrm = new UniGLTF.Extensions.VRMC_vrm.VRMC_vrm + { + SpecVersion = VRM_SPEC_VERSION, + Humanoid = new UniGLTF.Extensions.VRMC_vrm.Humanoid + { + HumanBones = new UniGLTF.Extensions.VRMC_vrm.HumanBones + { + }, + }, + Meta = new UniGLTF.Extensions.VRMC_vrm.Meta + { + LicenseUrl = LICENSE_URL_JA, + AllowExcessivelySexualUsage = false, + AllowExcessivelyViolentUsage = false, + AllowPoliticalOrReligiousUsage = false, + AllowRedistribution = false, + }, + }; + + // + // required + // + ExportHumanoid(vrm, model); + var thumbnailTextureIndex = ExportMeta(vrm, vrmMeta, textureExporter); + + // + // optional + // + UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrmSpringBone = default; + if (vrmController != null) + { + ExportExpression(vrm, vrmController, model, converter); + ExportLookAt(vrm, vrmController); + ExportFirstPerson(vrm, vrmController, model, converter); + + vrmSpringBone = ExportSpringBone(vrmController, model, converter); + ExportConstraints(vrmController, model, converter, nodes); + } + + return (vrm, vrmSpringBone, thumbnailTextureIndex); + } + + static UniGLTF.Extensions.VRMC_springBone.ColliderShape ExportShape(VRM10SpringBoneCollider z) + { + var shape = new UniGLTF.Extensions.VRMC_springBone.ColliderShape(); + switch (z.ColliderType) + { + case VRM10SpringBoneColliderTypes.Sphere: + { + shape.Sphere = new UniGLTF.Extensions.VRMC_springBone.ColliderShapeSphere + { + Radius = z.Radius, + Offset = ReverseX(z.Offset), + }; + break; + } + + case VRM10SpringBoneColliderTypes.Capsule: + { + shape.Capsule = new UniGLTF.Extensions.VRMC_springBone.ColliderShapeCapsule + { + Radius = z.Radius, + Offset = ReverseX(z.Offset), + Tail = ReverseX(z.Tail), + }; + break; + } + } + return shape; + } + + static UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint ExportJoint(VRM10SpringBoneJoint y, Func getIndexFromTransform) + { + var joint = new UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint + { + Node = getIndexFromTransform(y.transform), + HitRadius = y.m_jointRadius, + DragForce = y.m_dragForce, + Stiffness = y.m_stiffnessForce, + GravityDir = ReverseX(y.m_gravityDir), + GravityPower = y.m_gravityPower, + }; + return joint; + } + + static UniGLTF.Extensions.VRMC_springBone.VRMC_springBone ExportSpringBone(Vrm10Instance controller, Model model, ModelExporter converter) + { + var colliders = controller.GetComponentsInChildren(); + + // if colliders, collider groups and springs don't exist, don't export the extension + if ( + colliders.Length == 0 && + controller.SpringBone.ColliderGroups.Count == 0 && + controller.SpringBone.Springs.Count == 0 + ) + { + return null; + } + + var springBone = new UniGLTF.Extensions.VRMC_springBone.VRMC_springBone + { + SpecVersion = SPRINGBONE_SPEC_VERSION, + Colliders = new List(), + ColliderGroups = new List(), + Springs = new List(), + }; + + // colliders + Func getNodeIndexFromTransform = t => + { + var node = converter.Nodes[t.gameObject]; + return model.Nodes.IndexOf(node); + }; + + foreach (var c in colliders) + { + springBone.Colliders.Add(new UniGLTF.Extensions.VRMC_springBone.Collider + { + Node = getNodeIndexFromTransform(c.transform), + Shape = ExportShape(c), + }); + } + + // colliderGroups + foreach (var x in controller.SpringBone.ColliderGroups) + { + springBone.ColliderGroups.Add(new UniGLTF.Extensions.VRMC_springBone.ColliderGroup + { + Colliders = x.Colliders.Select(y => Array.IndexOf(colliders, y)).ToArray(), + }); + } + + // springs + foreach (var x in controller.SpringBone.Springs) + { + var spring = new UniGLTF.Extensions.VRMC_springBone.Spring + { + Name = x.Name, + Joints = x.Joints.Select(y => ExportJoint(y, getNodeIndexFromTransform)).ToList(), + ColliderGroups = x.ColliderGroups.Select(y => controller.SpringBone.ColliderGroups.IndexOf(y)).ToArray(), + }; + + if (x.Center != null) + { + var center = model.Nodes.IndexOf(converter.Nodes[x.Center.gameObject]); + if (center != -1) + { + spring.Center = center; + } + } + + springBone.Springs.Add(spring); + } + + return springBone; + } + + static void ExportConstraints(Vrm10Instance vrmController, Model model, ModelExporter converter, List nodes) + { + var constraints = vrmController.GetComponentsInChildren(); + foreach (var constraint in constraints) + { + var vrmConstraint = new UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint + { + SpecVersion = NODE_CONSTRAINT_SPEC_VERSION, + Constraint = new UniGLTF.Extensions.VRMC_node_constraint.Constraint + { + }, + }; + + switch (constraint) + { + case Vrm10AimConstraint aimConstraint: + vrmConstraint.Constraint.Aim = new UniGLTF.Extensions.VRMC_node_constraint.AimConstraint + { + Source = model.Nodes.IndexOf(converter.Nodes[aimConstraint.Source.gameObject]), + Weight = aimConstraint.Weight, + AimAxis = Vrm10ConstraintUtil.ReverseX(aimConstraint.AimAxis), + }; + break; + + case Vrm10RollConstraint rollConstraint: + vrmConstraint.Constraint.Roll = new UniGLTF.Extensions.VRMC_node_constraint.RollConstraint + { + Source = model.Nodes.IndexOf(converter.Nodes[rollConstraint.Source.gameObject]), + Weight = rollConstraint.Weight, + RollAxis = rollConstraint.RollAxis, + }; + break; + + case Vrm10RotationConstraint rotationConstraint: + vrmConstraint.Constraint.Rotation = new UniGLTF.Extensions.VRMC_node_constraint.RotationConstraint + { + Source = model.Nodes.IndexOf(converter.Nodes[rotationConstraint.Source.gameObject]), + Weight = rotationConstraint.Weight, + }; + break; + + default: + throw new NotImplementedException(); + } + + // serialize to gltfNode + var node = converter.Nodes[constraint.ConstraintTarget]; + var nodeIndex = model.Nodes.IndexOf(node); + var gltfNode = nodes[nodeIndex]; + UniGLTF.Extensions.VRMC_node_constraint.GltfSerializer.SerializeTo(ref gltfNode.extensions, vrmConstraint); + } + } + + static bool[] ToArray(AxisMask mask) + { + return new bool[] + { + mask.HasFlag(AxisMask.X), + mask.HasFlag(AxisMask.Y), + mask.HasFlag(AxisMask.Z), + }; + } + + + static UniGLTF.Extensions.VRMC_vrm.MeshAnnotation ExportMeshAnnotation(RendererFirstPersonFlags flags, Transform root, Func getIndex) + { + return new UniGLTF.Extensions.VRMC_vrm.MeshAnnotation + { + Node = getIndex(flags.GetRenderer(root)), + Type = flags.FirstPersonFlag, + }; + } + + void ExportFirstPerson(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController, Model model, ModelExporter converter) + { + if (!(vrmController?.Vrm?.FirstPerson is VRM10ObjectFirstPerson firstPerson)) + { + return; + } + + vrm.FirstPerson = new UniGLTF.Extensions.VRMC_vrm.FirstPerson + { + MeshAnnotations = new List(), + }; + Func getIndex = r => + { + var node = converter.Nodes[r.gameObject]; + return model.Nodes.IndexOf(node); + }; + foreach (var f in firstPerson.Renderers) + { + vrm.FirstPerson.MeshAnnotations.Add(ExportMeshAnnotation(f, vrmController.transform, getIndex)); + } + } + + static UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap ExportLookAtRangeMap(CurveMapper mapper) + { + return new UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap + { + InputMaxValue = mapper.CurveXRangeDegree, + OutputScale = mapper.CurveYRangeDegree, + }; + } + + static void ExportLookAt(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController) + { + if (!(vrmController?.Vrm?.LookAt is VRM10ObjectLookAt lookAt)) + { + return; + } + + vrm.LookAt = new UniGLTF.Extensions.VRMC_vrm.LookAt + { + Type = lookAt.LookAtType, + OffsetFromHeadBone = lookAt.OffsetFromHead.ReverseX().ToFloat3(), + RangeMapHorizontalInner = ExportLookAtRangeMap(lookAt.HorizontalInner), + RangeMapHorizontalOuter = ExportLookAtRangeMap(lookAt.HorizontalOuter), + RangeMapVerticalDown = ExportLookAtRangeMap(lookAt.VerticalDown), + RangeMapVerticalUp = ExportLookAtRangeMap(lookAt.VerticalUp), + }; + } + + static UniGLTF.Extensions.VRMC_vrm.MorphTargetBind ExportMorphTargetBinding(MorphTargetBinding binding, Func getIndex) + { + return new UniGLTF.Extensions.VRMC_vrm.MorphTargetBind + { + Node = getIndex(binding.RelativePath), + Index = binding.Index, + Weight = binding.Weight, + }; + } + + static UniGLTF.Extensions.VRMC_vrm.MaterialColorBind ExportMaterialColorBinding(MaterialColorBinding binding, Func getIndex) + { + return new UniGLTF.Extensions.VRMC_vrm.MaterialColorBind + { + Material = getIndex(binding.MaterialName), + Type = binding.BindType, + TargetValue = new float[] { binding.TargetValue.x, binding.TargetValue.y, binding.TargetValue.z, binding.TargetValue.w }, + }; + } + + static UniGLTF.Extensions.VRMC_vrm.TextureTransformBind ExportTextureTransformBinding(MaterialUVBinding binding, Func getIndex) + { + var (scale, offset) = TextureTransform.VerticalFlipScaleOffset(binding.Scaling, binding.Offset); + return new UniGLTF.Extensions.VRMC_vrm.TextureTransformBind + { + Material = getIndex(binding.MaterialName), + Offset = new float[] { offset.x, offset.y }, + Scale = new float[] { scale.x, scale.y }, + }; + } + + static UniGLTF.Extensions.VRMC_vrm.Expression ExportExpression(VRM10Expression e, Vrm10Instance vrmController, Model model, ModelExporter converter) + { + if (e == null) + { + return null; + } + + Func getIndexFromRelativePath = relativePath => + { + var rendererNode = vrmController.transform.GetFromPath(relativePath); + var node = converter.Nodes[rendererNode.gameObject]; + return model.Nodes.IndexOf(node); + }; + + var vrmExpression = new UniGLTF.Extensions.VRMC_vrm.Expression + { + // Preset = e.Preset, + // Name = e.ExpressionName, + IsBinary = e.IsBinary, + OverrideBlink = e.OverrideBlink, + OverrideLookAt = e.OverrideLookAt, + OverrideMouth = e.OverrideMouth, + MorphTargetBinds = new List(), + MaterialColorBinds = new List(), + TextureTransformBinds = new List(), + }; + Func getIndexFromMaterialName = materialName => + { + for (int i = 0; i < model.Materials.Count; ++i) + { + var m = model.Materials[i] as Material; + if (m.name == materialName) + { + return i; + } + } + throw new KeyNotFoundException(); + }; + + foreach (var b in e.MorphTargetBindings) + { + try + { + vrmExpression.MorphTargetBinds.Add(ExportMorphTargetBinding(b, getIndexFromRelativePath)); + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } + } + foreach (var b in e.MaterialColorBindings) + { + try + { + vrmExpression.MaterialColorBinds.Add(ExportMaterialColorBinding(b, getIndexFromMaterialName)); + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } + } + foreach (var b in e.MaterialUVBindings) + { + try + { + vrmExpression.TextureTransformBinds.Add(ExportTextureTransformBinding(b, getIndexFromMaterialName)); + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } + } + return vrmExpression; + } + + static void ExportExpression(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController, Model model, ModelExporter converter) + { + if (vrmController?.Vrm?.Expression?.Clips == null) + { + return; + } + + vrm.Expressions = new UniGLTF.Extensions.VRMC_vrm.Expressions + { + Preset = new UniGLTF.Extensions.VRMC_vrm.Preset + { + Happy = ExportExpression(vrmController.Vrm.Expression.Happy, vrmController, model, converter), + Angry = ExportExpression(vrmController.Vrm.Expression.Angry, vrmController, model, converter), + Sad = ExportExpression(vrmController.Vrm.Expression.Sad, vrmController, model, converter), + Relaxed = ExportExpression(vrmController.Vrm.Expression.Relaxed, vrmController, model, converter), + Surprised = ExportExpression(vrmController.Vrm.Expression.Surprised, vrmController, model, converter), + Aa = ExportExpression(vrmController.Vrm.Expression.Aa, vrmController, model, converter), + Ih = ExportExpression(vrmController.Vrm.Expression.Ih, vrmController, model, converter), + Ou = ExportExpression(vrmController.Vrm.Expression.Ou, vrmController, model, converter), + Ee = ExportExpression(vrmController.Vrm.Expression.Ee, vrmController, model, converter), + Oh = ExportExpression(vrmController.Vrm.Expression.Oh, vrmController, model, converter), + Blink = ExportExpression(vrmController.Vrm.Expression.Blink, vrmController, model, converter), + BlinkLeft = ExportExpression(vrmController.Vrm.Expression.BlinkLeft, vrmController, model, converter), + BlinkRight = ExportExpression(vrmController.Vrm.Expression.BlinkRight, vrmController, model, converter), + LookUp = ExportExpression(vrmController.Vrm.Expression.LookUp, vrmController, model, converter), + LookDown = ExportExpression(vrmController.Vrm.Expression.LookDown, vrmController, model, converter), + LookLeft = ExportExpression(vrmController.Vrm.Expression.LookLeft, vrmController, model, converter), + LookRight = ExportExpression(vrmController.Vrm.Expression.LookRight, vrmController, model, converter), + Neutral = ExportExpression(vrmController.Vrm.Expression.Neutral, vrmController, model, converter), + }, + Custom = vrmController.Vrm.Expression.CustomClips.ToDictionary(c => c.name, c => ExportExpression(c, vrmController, model, converter)), + }; + } + + public static int? ExportMeta(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10ObjectMeta meta, ITextureExporter textureExporter) + { + vrm.Meta.Name = meta.Name; + vrm.Meta.Version = meta.Version; + vrm.Meta.Authors = meta.Authors.ToList(); + vrm.Meta.CopyrightInformation = meta.CopyrightInformation; + vrm.Meta.ContactInformation = meta.ContactInformation; + vrm.Meta.References = meta.References.ToList(); + vrm.Meta.ThirdPartyLicenses = meta.ThirdPartyLicenses; + vrm.Meta.AvatarPermission = meta.AvatarPermission; + vrm.Meta.AllowExcessivelyViolentUsage = meta.ViolentUsage; + vrm.Meta.AllowExcessivelySexualUsage = meta.SexualUsage; + vrm.Meta.CommercialUsage = meta.CommercialUsage; + vrm.Meta.AllowPoliticalOrReligiousUsage = meta.PoliticalOrReligiousUsage; + vrm.Meta.AllowAntisocialOrHateUsage = meta.AntisocialOrHateUsage; + vrm.Meta.CreditNotation = meta.CreditNotation; + vrm.Meta.AllowRedistribution = meta.Redistribution; + vrm.Meta.Modification = meta.Modification; + vrm.Meta.OtherLicenseUrl = meta.OtherLicenseUrl; + int? thumbnailTextureIndex = default; + if (meta.Thumbnail != null) + { + thumbnailTextureIndex = textureExporter.RegisterExportingAsSRgb(meta.Thumbnail, needsAlpha: true); + } + return thumbnailTextureIndex; + } + + static void ExportHumanoid(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Model model) + { + // humanoid + for (int i = 0; i < model.Nodes.Count; ++i) + { + var bone = model.Nodes[i]; + switch (bone.HumanoidBone) + { + case HumanoidBones.hips: vrm.Humanoid.HumanBones.Hips = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.spine: vrm.Humanoid.HumanBones.Spine = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.chest: vrm.Humanoid.HumanBones.Chest = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.upperChest: vrm.Humanoid.HumanBones.UpperChest = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.neck: vrm.Humanoid.HumanBones.Neck = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.head: vrm.Humanoid.HumanBones.Head = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftEye: vrm.Humanoid.HumanBones.LeftEye = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightEye: vrm.Humanoid.HumanBones.RightEye = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.jaw: vrm.Humanoid.HumanBones.Jaw = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftUpperLeg: vrm.Humanoid.HumanBones.LeftUpperLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftLowerLeg: vrm.Humanoid.HumanBones.LeftLowerLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftFoot: vrm.Humanoid.HumanBones.LeftFoot = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftToes: vrm.Humanoid.HumanBones.LeftToes = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightUpperLeg: vrm.Humanoid.HumanBones.RightUpperLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightLowerLeg: vrm.Humanoid.HumanBones.RightLowerLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightFoot: vrm.Humanoid.HumanBones.RightFoot = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightToes: vrm.Humanoid.HumanBones.RightToes = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftShoulder: vrm.Humanoid.HumanBones.LeftShoulder = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftUpperArm: vrm.Humanoid.HumanBones.LeftUpperArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftLowerArm: vrm.Humanoid.HumanBones.LeftLowerArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftHand: vrm.Humanoid.HumanBones.LeftHand = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightShoulder: vrm.Humanoid.HumanBones.RightShoulder = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightUpperArm: vrm.Humanoid.HumanBones.RightUpperArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightLowerArm: vrm.Humanoid.HumanBones.RightLowerArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightHand: vrm.Humanoid.HumanBones.RightHand = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftThumbMetacarpal: vrm.Humanoid.HumanBones.LeftThumbMetacarpal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftThumbProximal: vrm.Humanoid.HumanBones.LeftThumbProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftThumbDistal: vrm.Humanoid.HumanBones.LeftThumbDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftIndexProximal: vrm.Humanoid.HumanBones.LeftIndexProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftIndexIntermediate: vrm.Humanoid.HumanBones.LeftIndexIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftIndexDistal: vrm.Humanoid.HumanBones.LeftIndexDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftMiddleProximal: vrm.Humanoid.HumanBones.LeftMiddleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftMiddleIntermediate: vrm.Humanoid.HumanBones.LeftMiddleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftMiddleDistal: vrm.Humanoid.HumanBones.LeftMiddleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftRingProximal: vrm.Humanoid.HumanBones.LeftRingProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftRingIntermediate: vrm.Humanoid.HumanBones.LeftRingIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftRingDistal: vrm.Humanoid.HumanBones.LeftRingDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftLittleProximal: vrm.Humanoid.HumanBones.LeftLittleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftLittleIntermediate: vrm.Humanoid.HumanBones.LeftLittleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.leftLittleDistal: vrm.Humanoid.HumanBones.LeftLittleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightThumbMetacarpal: vrm.Humanoid.HumanBones.RightThumbMetacarpal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightThumbProximal: vrm.Humanoid.HumanBones.RightThumbProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightThumbDistal: vrm.Humanoid.HumanBones.RightThumbDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightIndexProximal: vrm.Humanoid.HumanBones.RightIndexProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightIndexIntermediate: vrm.Humanoid.HumanBones.RightIndexIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightIndexDistal: vrm.Humanoid.HumanBones.RightIndexDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightMiddleProximal: vrm.Humanoid.HumanBones.RightMiddleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightMiddleIntermediate: vrm.Humanoid.HumanBones.RightMiddleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightMiddleDistal: vrm.Humanoid.HumanBones.RightMiddleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightRingProximal: vrm.Humanoid.HumanBones.RightRingProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightRingIntermediate: vrm.Humanoid.HumanBones.RightRingIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightRingDistal: vrm.Humanoid.HumanBones.RightRingDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightLittleProximal: vrm.Humanoid.HumanBones.RightLittleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightLittleIntermediate: vrm.Humanoid.HumanBones.RightLittleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.rightLittleDistal: vrm.Humanoid.HumanBones.RightLittleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + } + } + } + + /// + /// 便利関数 + /// + /// + /// + /// + public static byte[] Export(GameObject go, ITextureSerializer textureSerializer = null, VRM10ObjectMeta vrmMeta = null) + { + using (var arrayManager = new NativeArrayManager()) + { + // ヒエラルキーからジオメトリーを収集 + var converter = new UniVRM10.ModelExporter(); + var model = converter.Export(arrayManager, go); + + // 右手系に変換 + model.ConvertCoordinate(VrmLib.Coordinates.Vrm1); + + // Model と go から VRM-1.0 にExport + var exporter10 = new Vrm10Exporter(textureSerializer ?? new RuntimeTextureSerializer(), new GltfExportSettings()); + var option = new VrmLib.ExportArgs + { + }; + exporter10.Export(go, model, converter, option, vrmMeta); + return exporter10.Storage.ToGlbBytes(); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10Exporter.cs.meta b/Assets/External/VRM10/Runtime/IO/Vrm10Exporter.cs.meta new file mode 100644 index 000000000..b6b2f39a6 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10Exporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9831d54a2432bd841a4b9352e47b2d83 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10ImportData.cs b/Assets/External/VRM10/Runtime/IO/Vrm10ImportData.cs new file mode 100644 index 000000000..640eb30b3 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10ImportData.cs @@ -0,0 +1,481 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices; +using UniGLTF; +using VrmLib; +using System.Collections.Generic; +using UniGLTF.Utils; +using Unity.Collections; +using UnityEngine; + +namespace UniVRM10 +{ + public class Vrm10ImportData + { + UniGLTF.GltfData m_data; + public UniGLTF.GltfData Data => m_data; + + public UniGLTF.glTF Gltf => m_data.GLTF; + public string AssetVersion => Gltf.asset.version; + + public string AssetMinVersion => Gltf.asset.minVersion; + + public string AssetGenerator => Gltf.asset.generator; + + public string AssetCopyright => Gltf.asset.copyright; + + public int NodeCount => Gltf.nodes.Count; + + public int TextureCount => Gltf.textures.Count; + + public int SkinCount => Gltf.skins.Count; + + public int MeshCount => Gltf.meshes.Count; + + public UniGLTF.Extensions.VRMC_vrm.VRMC_vrm gltfVrm; + + public UniGLTF.Extensions.VRMC_springBone.VRMC_springBone gltfVrmSpringBone; + + /// + /// for import + /// + /// + /// + public Vrm10ImportData(UniGLTF.GltfData data) + { + m_data = data; + + if (UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(Gltf.extensions, + out UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm)) + { + gltfVrm = vrm; + } + + if (UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.TryGet(Gltf.extensions, + out UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone)) + { + gltfVrmSpringBone = springBone; + } + } + + public NativeArray GetBufferBytes(UniGLTF.glTFBuffer buffer) + { + int index = Gltf.buffers.IndexOf(buffer); + if (index != 0) + { + throw new NotImplementedException(); + } + return m_data.Bin; + } + + public NativeArray GetBufferBytes(UniGLTF.glTFBufferView bufferView) + { + if (!bufferView.buffer.TryGetValidIndex(Gltf.buffers.Count, out int bufferViewBufferIndex)) + { + throw new Exception(); + } + return GetBufferBytes(Gltf.buffers[bufferViewBufferIndex]); + } + + static NativeArray RestoreSparseAccessorUInt8(INativeArrayManager arrayManager, NativeArray bytes, int accessorCount, NativeArray indices, NativeArray valuesBytes) + where T : struct + { + var stride = Marshal.SizeOf(typeof(T)); + if (bytes.Length == 0) + { + bytes = arrayManager.CreateNativeArray(accessorCount * stride); + } + var dst = bytes.Reinterpret(1); + var values = valuesBytes.Reinterpret(1); + + for (int i = 0; i < indices.Length; ++i) + { + var index = indices[i]; + var value = values[i]; + dst[index] = value; + } + + return bytes; + } + + static NativeArray RestoreSparseAccessorUInt16(INativeArrayManager arrayManager, NativeArray bytes, int accessorCount, NativeArray indicesBytes, NativeArray valuesBytes) + where T : struct + { + var stride = Marshal.SizeOf(typeof(T)); + if (bytes.Length == 0) + { + bytes = arrayManager.CreateNativeArray(accessorCount * stride); + } + var dst = bytes.Reinterpret(1); + + var indices = indicesBytes.Reinterpret(1); + var values = valuesBytes.Reinterpret(1); + + for (int i = 0; i < indices.Length; ++i) + { + var index = indices[i]; + var value = values[i]; + dst[index] = value; + } + + return bytes; + } + + static NativeArray RestoreSparseAccessorUInt32(INativeArrayManager arrayManager, NativeArray bytes, int accessorCount, NativeArray indicesBytes, NativeArray valuesBytes) + where T : struct + { + var stride = Marshal.SizeOf(typeof(T)); + if (bytes.Length == 0) + { + bytes = arrayManager.CreateNativeArray(accessorCount * stride); + } + var dst = bytes.Reinterpret(1); + + var indices = indicesBytes.Reinterpret(1); + var values = valuesBytes.Reinterpret(1); + + for (int i = 0; i < indices.Length; ++i) + { + var index = indices[i]; + var value = values[i]; + dst[index] = value; + } + + return bytes; + } + + public NativeArray GetAccessorBytes(int accessorIndex) + { + var accessor = Gltf.accessors[accessorIndex]; + var sparse = accessor.sparse; + + NativeArray bytes = default; + + if (accessor.bufferView.TryGetValidIndex(Gltf.bufferViews.Count, out int bufferViewIndex)) + { + var view = Gltf.bufferViews[bufferViewIndex]; + if (view.buffer.TryGetValidIndex(Gltf.buffers.Count, out int bufferIndex)) + { + var buffer = m_data.Bin; + var byteSize = accessor.CalcByteSize(); + bytes = m_data.Bin.GetSubArray(view.byteOffset, view.byteLength).GetSubArray(accessor.byteOffset.GetValueOrDefault(), byteSize); + } + } + + if (sparse != null) + { + if (!sparse.indices.bufferView.TryGetValidIndex(Gltf.bufferViews.Count, out int sparseIndicesBufferViewIndex)) + { + throw new Exception(); + } + var sparseIndexView = Gltf.bufferViews[sparseIndicesBufferViewIndex]; + var sparseIndexBin = GetBufferBytes(sparseIndexView); + var sparseIndexBytes = sparseIndexBin + .GetSubArray(sparseIndexView.byteOffset, sparseIndexView.byteLength) + .GetSubArray(sparse.indices.byteOffset, ((AccessorValueType)sparse.indices.componentType).ByteSize() * sparse.count) + ; + + if (!sparse.values.bufferView.TryGetValidIndex(Gltf.bufferViews.Count, out int sparseValuesBufferViewIndex)) + { + throw new Exception(); + } + var sparseValueView = Gltf.bufferViews[sparseValuesBufferViewIndex]; + var sparseValueBin = GetBufferBytes(sparseValueView); + var sparseValueBytes = sparseValueBin + .GetSubArray(sparseValueView.byteOffset, sparseValueView.byteLength) + .GetSubArray(sparse.values.byteOffset, accessor.GetStride() * sparse.count); + ; + + if (sparse.indices.componentType == (UniGLTF.glComponentType)AccessorValueType.UNSIGNED_BYTE + && accessor.componentType == (UniGLTF.glComponentType)AccessorValueType.FLOAT + && accessor.type == "VEC3") + { + return RestoreSparseAccessorUInt8(m_data.NativeArrayManager, bytes, accessor.count, sparseIndexBytes, sparseValueBytes); + } + if (sparse.indices.componentType == (UniGLTF.glComponentType)AccessorValueType.UNSIGNED_SHORT + && accessor.componentType == (UniGLTF.glComponentType)AccessorValueType.FLOAT + && accessor.type == "VEC3") + { + return RestoreSparseAccessorUInt16(m_data.NativeArrayManager, bytes, accessor.count, sparseIndexBytes, sparseValueBytes); + } + if (sparse.indices.componentType == (UniGLTF.glComponentType)AccessorValueType.UNSIGNED_INT + && accessor.componentType == (UniGLTF.glComponentType)AccessorValueType.FLOAT + && accessor.type == "VEC3") + { + return RestoreSparseAccessorUInt32(m_data.NativeArrayManager, bytes, accessor.count, sparseIndexBytes, sparseValueBytes); + } + else + { + throw new NotImplementedException(); + } + } + else + { + if (bytes.Length == 0) + { + // sparse and all value is zero + return m_data.NativeArrayManager.CreateNativeArray(accessor.GetStride() * accessor.count); + } + + return bytes; + } + } + + public bool TryCreateAccessor(int accessorIndex, out BufferAccessor ba) + { + if (accessorIndex < 0 || accessorIndex >= Gltf.accessors.Count) + { + ba = default; + return false; + } + var accessor = Gltf.accessors[accessorIndex]; + var bytes = GetAccessorBytes(accessorIndex); + var vectorType = CachedEnum.Parse(accessor.type, ignoreCase: true); + ba = new BufferAccessor(m_data.NativeArrayManager, bytes, + (AccessorValueType)accessor.componentType, vectorType, accessor.count); + return true; + } + + public BufferAccessor CreateAccessor(int accessorIndex) + { + if (TryCreateAccessor(accessorIndex, out BufferAccessor ba)) + { + return ba; + } + else + { + return null; + } + } + + /// + /// submeshのindexが連続した領域に格納されているかを確認する + /// + bool AccessorsIsContinuous(int[] accessorIndices) + { + var firstAccessor = Gltf.accessors[accessorIndices[0]]; + var firstView = Gltf.bufferViews[firstAccessor.bufferView.Value]; + var firstAccessorByteOffset = firstAccessor.byteOffset.GetValueOrDefault(); + var start = firstView.byteOffset + firstAccessorByteOffset; + var pos = start; + foreach (var i in accessorIndices) + { + var current = Gltf.accessors[i]; + if (current.type != "SCALAR") + { + throw new ArgumentException($"accessor.type: {current.type}"); + } + + if (firstAccessor.componentType != current.componentType) + { + return false; + } + + var view = Gltf.bufferViews[current.bufferView.Value]; + if (firstView.buffer != view.buffer) + { + return false; + } + + var currentAccessorByteOffset = current.byteOffset.GetValueOrDefault(); + if (pos != view.byteOffset + currentAccessorByteOffset) + { + return false; + } + + var begin = view.byteOffset + currentAccessorByteOffset; + var byteLength = current.CalcByteSize(); + + pos += byteLength; + } + + return true; + } + + /// + /// Gltfの Primitive[] の indices をひとまとめにした + /// IndexBuffer を返す。 + /// + public BufferAccessor CreateAccessor(int[] accessorIndices) + { + var totalCount = accessorIndices.Sum(x => Gltf.accessors[x].count); + if (AccessorsIsContinuous(accessorIndices)) + { + // IndexBufferが連続して格納されている => Slice でいける + var firstAccessor = Gltf.accessors[accessorIndices[0]]; + var firstView = Gltf.bufferViews[firstAccessor.bufferView.Value]; + var start = firstView.byteOffset + firstAccessor.byteOffset.GetValueOrDefault(); + if (!firstView.buffer.TryGetValidIndex(Gltf.buffers.Count, out int firstViewBufferIndex)) + { + throw new Exception(); + } + var buffer = Gltf.buffers[firstViewBufferIndex]; + var bin = GetBufferBytes(buffer); + var bytes = bin.GetSubArray(start, totalCount * firstAccessor.GetStride()); + return new BufferAccessor(m_data.NativeArrayManager, bytes, + (AccessorValueType)firstAccessor.componentType, + CachedEnum.Parse(firstAccessor.type, ignoreCase: true), + totalCount); + } + else + { + // IndexBufferが連続して格納されていない => Int[] を作り直す + var indices = m_data.NativeArrayManager.CreateNativeArray(totalCount * Marshal.SizeOf(typeof(int))); + var span = indices.Reinterpret(1); + var offset = 0; + foreach (var accessorIndex in accessorIndices) + { + var accessor = Gltf.accessors[accessorIndex]; + if (accessor.type != "SCALAR") + { + throw new ArgumentException($"accessor.type: {accessor.type}"); + } + var view = Gltf.bufferViews[accessor.bufferView.Value]; + if (!view.buffer.TryGetValidIndex(Gltf.buffers.Count, out int viewBufferIndex)) + { + throw new Exception(); + } + var buffer = Gltf.buffers[viewBufferIndex]; + var bin = GetBufferBytes(buffer); + var start = view.byteOffset + accessor.byteOffset.GetValueOrDefault(); + var bytes = bin.GetSubArray(start, accessor.count * accessor.GetStride()); + var dst = indices.Reinterpret(1).GetSubArray(offset, accessor.count); + offset += accessor.count; + switch ((AccessorValueType)accessor.componentType) + { + case AccessorValueType.UNSIGNED_BYTE: + { + var src = bytes; + for (int i = 0; i < src.Length; ++i) + { + // byte to int + dst[i] = src[i]; + } + } + break; + + case AccessorValueType.UNSIGNED_SHORT: + { + var src = bytes.Reinterpret(1); + for (int i = 0; i < src.Length; ++i) + { + // ushort to int + dst[i] = src[i]; + } + } + break; + + case AccessorValueType.UNSIGNED_INT: + { + NativeArray.Copy(bytes, dst.Reinterpret(Marshal.SizeOf())); + } + break; + + default: + throw new NotImplementedException($"accessor.componentType: {accessor.componentType}"); + } + } + return new BufferAccessor(m_data.NativeArrayManager, indices, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, totalCount); + } + } + + public void CreateBufferAccessorAndAdd(int accessorIndex, VertexBuffer b, string key) + { + var a = CreateAccessor(accessorIndex); + if (a != null) + { + b.Add(key, a); + } + } + + public Node CreateNode(int index) + { + var x = Gltf.nodes[index]; + var node = new Node(x.name); + if (x.matrix != null) + { + if (x.matrix.Length != 16) throw new Exception("matrix member is not 16"); + if (x.translation != null && x.translation.Length > 0) throw new Exception("matrix with translation"); + if (x.rotation != null && x.rotation.Length > 0) throw new Exception("matrix with rotation"); + if (x.scale != null && x.scale.Length > 0) throw new Exception("matrix with scale"); + var m = UnityExtensions.MatrixFromArray(x.matrix); + + node.SetLocalMatrix(m, true); + } + else + { + if (x.translation != null && x.translation.Length == 3) + { + node.LocalTranslation = x.translation.ToVector3(); + } + if (x.rotation != null && x.rotation.Length == 4) + { + node.LocalRotation = x.rotation.ToQuaternion(); + } + if (x.scale != null && x.scale.Length == 3) + { + node.LocalScaling = x.scale.ToVector3(Vector3.one); + } + } + return node; + } + + public IEnumerable GetChildNodeIndices(int i) + { + var gltfNode = Gltf.nodes[i]; + if (gltfNode.children != null) + { + foreach (var j in gltfNode.children) + { + yield return j; + } + } + } + + public Skin CreateSkin(int index, List nodes) + { + var x = Gltf.skins[index]; + BufferAccessor inverseMatrices = null; + if (x.inverseBindMatrices != -1) + { + inverseMatrices = CreateAccessor(x.inverseBindMatrices); + } + var skin = new Skin + { + InverseMatrices = inverseMatrices, + Joints = x.joints.Select(y => nodes[y]).ToList(), + }; + if (x.skeleton != -1) // TODO: proto to int + { + skin.Root = nodes[x.skeleton]; + } + return skin; + } + + public MeshGroup CreateMesh(int index) + { + var x = Gltf.meshes[index]; + var group = x.FromGltf(this); + return group; + } + + public (int, int) GetNodeMeshSkin(int index) + { + var x = Gltf.nodes[index]; + + int meshIndex = -1; + if (x.mesh.TryGetValidIndex(Gltf.meshes.Count, out int mi)) + { + meshIndex = mi; + } + + int skinIndex = -1; + if (x.skin.TryGetValidIndex(Gltf.skins.Count, out int si)) + { + skinIndex = si; + } + + return (meshIndex, skinIndex); + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10ImportData.cs.meta b/Assets/External/VRM10/Runtime/IO/Vrm10ImportData.cs.meta new file mode 100644 index 000000000..235a48900 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10ImportData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a095747b4e9fcf1439a10e2e4913a32d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/External/VRM10/Runtime/IO/Vrm10Importer.cs new file mode 100644 index 000000000..e3a608e8b --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10Importer.cs @@ -0,0 +1,858 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using UniGLTF; +using UniGLTF.Utils; +using UnityEngine; +using VRMShaders; + + +namespace UniVRM10 +{ + /// + /// VrmLib.Model から UnityPrefab を構築する + /// + public class Vrm10Importer : UniGLTF.ImporterContext + { + private readonly Vrm10Data m_vrm; + /// VrmLib.Model の オブジェクトと UnityEngine.Object のマッピングを記録する + private readonly ModelMap m_map = new ModelMap(); + private readonly bool m_useControlRig; + + private VrmLib.Model m_model; + private IReadOnlyDictionary m_externalMap; + private Avatar m_humanoid; + private VRM10Object m_vrmObject; + private List<(ExpressionPreset Preset, VRM10Expression Clip)> m_expressions = new List<(ExpressionPreset, VRM10Expression)>(); + + public Vrm10Importer( + Vrm10Data vrm, + IReadOnlyDictionary externalObjectMap = null, + ITextureDeserializer textureDeserializer = null, + IMaterialDescriptorGenerator materialGenerator = null, + bool useControlRig = false + ) + : base(vrm.Data, externalObjectMap, textureDeserializer) + { + if (vrm == null) + { + throw new ArgumentNullException("vrm"); + } + m_vrm = vrm; + m_useControlRig = useControlRig; + + TextureDescriptorGenerator = new Vrm10TextureDescriptorGenerator(Data); + MaterialDescriptorGenerator = materialGenerator ?? Vrm10RenderPipelineMaterialDescriptorGeneratorDescriptorUtility.GetValidVrm10MaterialDescriptorGenerator(); + + m_externalMap = externalObjectMap; + if (m_externalMap == null) + { + m_externalMap = new Dictionary(); + } + } + + static void AssignHumanoid(List nodes, UniGLTF.Extensions.VRMC_vrm.HumanBone humanBone, VrmLib.HumanoidBones key) + { + if (nodes == null) + { + throw new ArgumentNullException("nodes"); + } + if (humanBone != null && humanBone.Node.HasValue) + { + var index = humanBone.Node.Value; + if (index >= 0 && index < nodes.Count) + { + nodes[index].HumanoidBone = key; + } + else + { + throw new IndexOutOfRangeException("AssignHumanoid"); + } + } + } + + public override async Task LoadAsync(IAwaitCaller awaitCaller, Func MeasureTime = null) + { + if (awaitCaller == null) + { + throw new ArgumentNullException(); + } + + // NOTE: VRM データに対して、Load 前に必要なヘビーな変換処理を行う. + // ヘビーなため、別スレッドで Run する. + await awaitCaller.Run(() => + { + // bin に対して右手左手変換を破壊的に実行することに注意 !(bin が変換済みになる) + m_model = ModelReader.Read(Data); + + // assign humanoid bones + if (m_vrm.VrmExtension.Humanoid is UniGLTF.Extensions.VRMC_vrm.Humanoid humanoid) + { + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Hips, VrmLib.HumanoidBones.hips); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftUpperLeg, VrmLib.HumanoidBones.leftUpperLeg); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightUpperLeg, VrmLib.HumanoidBones.rightUpperLeg); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLowerLeg, VrmLib.HumanoidBones.leftLowerLeg); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLowerLeg, VrmLib.HumanoidBones.rightLowerLeg); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftFoot, VrmLib.HumanoidBones.leftFoot); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightFoot, VrmLib.HumanoidBones.rightFoot); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Spine, VrmLib.HumanoidBones.spine); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Chest, VrmLib.HumanoidBones.chest); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Neck, VrmLib.HumanoidBones.neck); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Head, VrmLib.HumanoidBones.head); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftShoulder, VrmLib.HumanoidBones.leftShoulder); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightShoulder, VrmLib.HumanoidBones.rightShoulder); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftUpperArm, VrmLib.HumanoidBones.leftUpperArm); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightUpperArm, VrmLib.HumanoidBones.rightUpperArm); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLowerArm, VrmLib.HumanoidBones.leftLowerArm); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLowerArm, VrmLib.HumanoidBones.rightLowerArm); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftHand, VrmLib.HumanoidBones.leftHand); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightHand, VrmLib.HumanoidBones.rightHand); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftToes, VrmLib.HumanoidBones.leftToes); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightToes, VrmLib.HumanoidBones.rightToes); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftEye, VrmLib.HumanoidBones.leftEye); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightEye, VrmLib.HumanoidBones.rightEye); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Jaw, VrmLib.HumanoidBones.jaw); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftThumbMetacarpal, VrmLib.HumanoidBones.leftThumbMetacarpal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftThumbProximal, VrmLib.HumanoidBones.leftThumbProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftThumbDistal, VrmLib.HumanoidBones.leftThumbDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftIndexProximal, VrmLib.HumanoidBones.leftIndexProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftIndexIntermediate, VrmLib.HumanoidBones.leftIndexIntermediate); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftIndexDistal, VrmLib.HumanoidBones.leftIndexDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftMiddleProximal, VrmLib.HumanoidBones.leftMiddleProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftMiddleIntermediate, VrmLib.HumanoidBones.leftMiddleIntermediate); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftMiddleDistal, VrmLib.HumanoidBones.leftMiddleDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftRingProximal, VrmLib.HumanoidBones.leftRingProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftRingIntermediate, VrmLib.HumanoidBones.leftRingIntermediate); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftRingDistal, VrmLib.HumanoidBones.leftRingDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLittleProximal, VrmLib.HumanoidBones.leftLittleProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLittleIntermediate, VrmLib.HumanoidBones.leftLittleIntermediate); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLittleDistal, VrmLib.HumanoidBones.leftLittleDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightThumbMetacarpal, VrmLib.HumanoidBones.rightThumbMetacarpal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightThumbProximal, VrmLib.HumanoidBones.rightThumbProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightThumbDistal, VrmLib.HumanoidBones.rightThumbDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightIndexProximal, VrmLib.HumanoidBones.rightIndexProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightIndexIntermediate, VrmLib.HumanoidBones.rightIndexIntermediate); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightIndexDistal, VrmLib.HumanoidBones.rightIndexDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightMiddleProximal, VrmLib.HumanoidBones.rightMiddleProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightMiddleIntermediate, VrmLib.HumanoidBones.rightMiddleIntermediate); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightMiddleDistal, VrmLib.HumanoidBones.rightMiddleDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightRingProximal, VrmLib.HumanoidBones.rightRingProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightRingIntermediate, VrmLib.HumanoidBones.rightRingIntermediate); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightRingDistal, VrmLib.HumanoidBones.rightRingDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLittleProximal, VrmLib.HumanoidBones.rightLittleProximal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLittleIntermediate, VrmLib.HumanoidBones.rightLittleIntermediate); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLittleDistal, VrmLib.HumanoidBones.rightLittleDistal); + AssignHumanoid(m_model.Nodes, humanoid.HumanBones.UpperChest, VrmLib.HumanoidBones.upperChest); + } + }); + + return await base.LoadAsync(awaitCaller, MeasureTime); + } + + /// + /// VrmLib.Model から 構築する + /// + /// + /// + protected override async Task LoadGeometryAsync(IAwaitCaller awaitCaller, Func MeasureTime) + { + // fill assets + for (int i = 0; i < m_model.Materials.Count; ++i) + { + var src = m_model.Materials[i]; + var dst = MaterialFactory.Materials[i].Asset; + } + + await awaitCaller.NextFrame(); + + // mesh + for (int i = 0; i < m_model.MeshGroups.Count; ++i) + { + var src = m_model.MeshGroups[i]; + UnityEngine.Mesh mesh = default; + if (src.Meshes.Count == 1) + { + mesh = MeshImporterShared.LoadSharedMesh(src.Meshes[0], src.Skin); + } + else + { + // 頂点バッファの連結が必用 + // VRM-1 はこっち + // https://github.com/vrm-c/UniVRM/issues/800 + mesh = MeshImporterDivided.LoadDivided(src); + } + mesh.name = src.Name; + + m_map.Meshes.Add(src, mesh); + Meshes.Add(new MeshWithMaterials + { + Mesh = mesh, + Materials = src.Meshes[0].Submeshes.Select(x => MaterialFactory.Materials[x.Material].Asset).ToArray(), + }); + + + await awaitCaller.NextFrame(); + } + + // node: recursive + CreateNodes(m_model.Root, null, m_map.Nodes); + for (int i = 0; i < m_model.Nodes.Count; ++i) + { + Nodes.Add(m_map.Nodes[m_model.Nodes[i]].transform); + } + await awaitCaller.NextFrame(); + + if (Root == null) + { + Root = m_map.Nodes[m_model.Root]; + } + else + { + // replace + var modelRoot = m_map.Nodes[m_model.Root]; + foreach (Transform child in modelRoot.transform) + { + child.SetParent(Root.transform, true); + } + m_map.Nodes[m_model.Root] = Root; + } + await awaitCaller.NextFrame(); + + // renderer + var map = m_map; + foreach (var (node, go) in map.Nodes.Select(kv => (kv.Key, kv.Value))) + { + if (node.MeshGroup is null) + { + continue; + } + + CreateRenderer(node, go, map, MaterialFactory.Materials); + await awaitCaller.NextFrame(); + } + } + + protected override async Task OnLoadHierarchy(IAwaitCaller awaitCaller, Func MeasureTime) + { + Root.name = "VRM1"; + + // humanoid + var humanoid = Root.AddComponent(); + humanoid.AssignBones(m_map.Nodes.Select(x => (ToUnity(x.Key.HumanoidBone.GetValueOrDefault()), x.Value.transform))); + m_humanoid = humanoid.CreateAvatar(); + m_humanoid.name = "humanoid"; + var animator = Root.AddComponent(); + animator.avatar = m_humanoid; + + // VrmController + var controller = Root.AddComponent(); + controller.InitializeAtRuntime(m_useControlRig); + controller.enabled = false; + + // vrm + controller.Vrm = await LoadVrmAsync(awaitCaller, m_vrm.VrmExtension); + + // springBone + if (UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.TryGet(Data.GLTF.extensions, out UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone)) + { + await LoadSpringBoneAsync(awaitCaller, controller, springBone); + } + // constraint + await LoadConstraintAsync(awaitCaller, controller); + + // Hierarchyの構築が終わるまで遅延させる + controller.enabled = true; + } + + VRM10Expression GetOrLoadExpression(in SubAssetKey key, ExpressionPreset preset, UniGLTF.Extensions.VRMC_vrm.Expression expression) + { + VRM10Expression clip = default; + if (m_externalMap.TryGetValue(key, out UnityEngine.Object expressionObj)) + { + clip = expressionObj as VRM10Expression; + } + else + { + if (expression == null) + { + // default empty expression + expression = new UniGLTF.Extensions.VRMC_vrm.Expression + { + IsBinary = false, + OverrideBlink = UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.none, + OverrideLookAt = UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.none, + OverrideMouth = UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.none, + }; + } + clip = ScriptableObject.CreateInstance(); + clip.name = key.Name; + clip.IsBinary = expression.IsBinary.GetValueOrDefault(); + clip.OverrideBlink = expression.OverrideBlink; + clip.OverrideLookAt = expression.OverrideLookAt; + clip.OverrideMouth = expression.OverrideMouth; + + if (expression.MorphTargetBinds != null) + { + clip.MorphTargetBindings = expression.MorphTargetBinds?.Select(x => x.Build10(Root, m_map, m_model)) + .ToArray(); + } + else + { + clip.MorphTargetBindings = new MorphTargetBinding[] { }; + } + + if (expression.MaterialColorBinds != null) + { + clip.MaterialColorBindings = expression.MaterialColorBinds.Select(x => x.Build10(MaterialFactory.Materials)) + .Where(x => x.HasValue) + .Select(x => x.Value) + .ToArray(); + } + else + { + clip.MaterialColorBindings = new MaterialColorBinding[] { }; + } + + if (expression.TextureTransformBinds != null) + { + clip.MaterialUVBindings = expression?.TextureTransformBinds?.Select(x => x.Build10(MaterialFactory.Materials)) + .Where(x => x.HasValue) + .Select(x => x.Value) + .ToArray(); + } + else + { + clip.MaterialUVBindings = new MaterialUVBinding[] { }; + } + + m_expressions.Add((preset, clip)); + } + return clip; + } + + public async Task LoadVrmThumbnailAsync(IAwaitCaller awaitCaller = null) + { + if (awaitCaller == null) + { + awaitCaller = new ImmediateCaller(); + } + + if (Vrm10TextureDescriptorGenerator.TryGetMetaThumbnailTextureImportParam(Data, m_vrm.VrmExtension, out (SubAssetKey, VRMShaders.TextureDescriptor Param) kv)) + { + var texture = await TextureFactory.GetTextureAsync(kv.Param, awaitCaller); + return texture as Texture2D; + } + else + { + return null; + } + } + + async Task LoadVrmAsync(IAwaitCaller awaitCaller, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrmExtension) + { + if (m_externalMap.TryGetValue(VRM10Object.SubAssetKey, out UnityEngine.Object obj) && obj is VRM10Object vrm) + { + // use external object map + return vrm; + } + + // create new object + m_vrmObject = vrm = ScriptableObject.CreateInstance(); + vrm.name = VRM10Object.SubAssetKey.Name; + + // meta + if (vrmExtension.Meta != null) + { + var src = vrmExtension.Meta; + var meta = new VRM10ObjectMeta(); + vrm.Meta = meta; + meta.Name = src.Name; + meta.Version = src.Version; + meta.CopyrightInformation = src.CopyrightInformation; + meta.ContactInformation = src.ContactInformation; + meta.ThirdPartyLicenses = src.ThirdPartyLicenses; + // avatar + meta.AvatarPermission = src.AvatarPermission; + meta.ViolentUsage = src.AllowExcessivelyViolentUsage.GetValueOrDefault(); + meta.SexualUsage = src.AllowExcessivelySexualUsage.GetValueOrDefault(); + meta.CommercialUsage = src.CommercialUsage; + meta.PoliticalOrReligiousUsage = src.AllowPoliticalOrReligiousUsage.GetValueOrDefault(); + meta.AntisocialOrHateUsage = src.AllowAntisocialOrHateUsage.GetValueOrDefault(); + // redistribution + meta.CreditNotation = src.CreditNotation; + meta.Redistribution = src.AllowRedistribution.GetValueOrDefault(); + + meta.Modification = src.Modification; + meta.OtherLicenseUrl = src.OtherLicenseUrl; + // + if (src.References != null) + { + meta.References.AddRange(src.References); + } + if (src.Authors != null) + { + meta.Authors.AddRange(src.Authors); + } + + var tex2D = await LoadVrmThumbnailAsync(awaitCaller); + if (tex2D != null) + { + meta.Thumbnail = tex2D; + } + } + + // expression + { + vrm.Expression.Happy = GetOrLoadExpression(ExpressionKey.Happy.SubAssetKey, ExpressionPreset.happy, vrmExtension.Expressions?.Preset?.Happy); + vrm.Expression.Angry = GetOrLoadExpression(ExpressionKey.Angry.SubAssetKey, ExpressionPreset.angry, vrmExtension.Expressions?.Preset?.Angry); + vrm.Expression.Sad = GetOrLoadExpression(ExpressionKey.Sad.SubAssetKey, ExpressionPreset.sad, vrmExtension.Expressions?.Preset?.Sad); + vrm.Expression.Relaxed = GetOrLoadExpression(ExpressionKey.Relaxed.SubAssetKey, ExpressionPreset.relaxed, vrmExtension.Expressions?.Preset?.Relaxed); + vrm.Expression.Surprised = GetOrLoadExpression(ExpressionKey.Surprised.SubAssetKey, ExpressionPreset.surprised, vrmExtension.Expressions?.Preset?.Surprised); + vrm.Expression.Aa = GetOrLoadExpression(ExpressionKey.Aa.SubAssetKey, ExpressionPreset.aa, vrmExtension.Expressions?.Preset?.Aa); + vrm.Expression.Ih = GetOrLoadExpression(ExpressionKey.Ih.SubAssetKey, ExpressionPreset.ih, vrmExtension.Expressions?.Preset?.Ih); + vrm.Expression.Ou = GetOrLoadExpression(ExpressionKey.Ou.SubAssetKey, ExpressionPreset.ou, vrmExtension.Expressions?.Preset?.Ou); + vrm.Expression.Ee = GetOrLoadExpression(ExpressionKey.Ee.SubAssetKey, ExpressionPreset.ee, vrmExtension.Expressions?.Preset?.Ee); + vrm.Expression.Oh = GetOrLoadExpression(ExpressionKey.Oh.SubAssetKey, ExpressionPreset.oh, vrmExtension.Expressions?.Preset?.Oh); + vrm.Expression.Blink = GetOrLoadExpression(ExpressionKey.Blink.SubAssetKey, ExpressionPreset.blink, vrmExtension.Expressions?.Preset?.Blink); + vrm.Expression.BlinkLeft = GetOrLoadExpression(ExpressionKey.BlinkLeft.SubAssetKey, ExpressionPreset.blinkLeft, vrmExtension.Expressions?.Preset?.BlinkLeft); + vrm.Expression.BlinkRight = GetOrLoadExpression(ExpressionKey.BlinkRight.SubAssetKey, ExpressionPreset.blinkRight, vrmExtension.Expressions?.Preset?.BlinkRight); + vrm.Expression.LookUp = GetOrLoadExpression(ExpressionKey.LookUp.SubAssetKey, ExpressionPreset.lookUp, vrmExtension.Expressions?.Preset?.LookUp); + vrm.Expression.LookDown = GetOrLoadExpression(ExpressionKey.LookDown.SubAssetKey, ExpressionPreset.lookDown, vrmExtension.Expressions?.Preset?.LookDown); + vrm.Expression.LookLeft = GetOrLoadExpression(ExpressionKey.LookLeft.SubAssetKey, ExpressionPreset.lookLeft, vrmExtension.Expressions?.Preset?.LookLeft); + vrm.Expression.LookRight = GetOrLoadExpression(ExpressionKey.LookRight.SubAssetKey, ExpressionPreset.lookRight, vrmExtension.Expressions?.Preset?.LookRight); + vrm.Expression.Neutral = GetOrLoadExpression(ExpressionKey.Neutral.SubAssetKey, ExpressionPreset.neutral, vrmExtension.Expressions?.Preset?.Neutral); + if (vrmExtension?.Expressions?.Custom != null) + { + foreach (var (name, expression) in vrmExtension.Expressions.Custom.Select(kv => (kv.Key, kv.Value))) + { + var key = ExpressionKey.CreateCustom(name); + var preset = ExpressionPreset.custom; + var clip = GetOrLoadExpression(key.SubAssetKey, preset, expression); + if (clip != null) + { + vrm.Expression.AddClip(preset, clip); + } + } + } + } + + // lookat + if (vrmExtension.LookAt != null) + { + var src = vrmExtension.LookAt; + vrm.LookAt.LookAtType = src.Type; + if (src.OffsetFromHeadBone != null) + { + vrm.LookAt.OffsetFromHead = new Vector3(src.OffsetFromHeadBone[0], src.OffsetFromHeadBone[1], src.OffsetFromHeadBone[2]).ReverseX(); + } + if (src.RangeMapHorizontalInner != null) + { + vrm.LookAt.HorizontalInner = new CurveMapper(src.RangeMapHorizontalInner.InputMaxValue.Value, src.RangeMapHorizontalInner.OutputScale.Value); + } + if (src.RangeMapHorizontalOuter != null) + { + vrm.LookAt.HorizontalOuter = new CurveMapper(src.RangeMapHorizontalOuter.InputMaxValue.Value, src.RangeMapHorizontalOuter.OutputScale.Value); + } + if (src.RangeMapVerticalUp != null) + { + vrm.LookAt.VerticalUp = new CurveMapper(src.RangeMapVerticalUp.InputMaxValue.Value, src.RangeMapVerticalUp.OutputScale.Value); + } + if (src.RangeMapVerticalDown != null) + { + vrm.LookAt.VerticalDown = new CurveMapper(src.RangeMapVerticalDown.InputMaxValue.Value, src.RangeMapVerticalDown.OutputScale.Value); + } + } + + // firstPerson + if (vrmExtension.FirstPerson != null && vrmExtension.FirstPerson.MeshAnnotations != null) + { + var fp = vrmExtension.FirstPerson; + foreach (var x in fp.MeshAnnotations) + { + var node = Nodes[x.Node.Value]; + var relative = node.RelativePathFrom(Root.transform); + vrm.FirstPerson.Renderers.Add(new RendererFirstPersonFlags + { + FirstPersonFlag = x.Type, + Renderer = relative, + }); + } + } + else + { + // default 値を割り当てる + foreach (var smr in Root.GetComponentsInChildren()) + { + var relative = smr.transform.RelativePathFrom(Root.transform); + vrm.FirstPerson.Renderers.Add(new RendererFirstPersonFlags + { + FirstPersonFlag = UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto, + Renderer = relative, + }); + } + } + // 設定の無い renderer に auto を割り当てる + foreach (var smr in Root.GetComponentsInChildren()) + { + var relative = smr.transform.RelativePathFrom(Root.transform); + if (!vrm.FirstPerson.Renderers.Any(x => x.Renderer == relative)) + { + vrm.FirstPerson.Renderers.Add(new RendererFirstPersonFlags + { + FirstPersonFlag = UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto, + Renderer = relative, + }); + } + } + + return vrm; + } + + async Task LoadSpringBoneAsync(IAwaitCaller awaitCaller, Vrm10Instance controller, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone gltfVrmSpringBone) + { + await awaitCaller.NextFrame(); + + // colliders + var colliders = new List(); + if (gltfVrmSpringBone.Colliders != null) + { + foreach (var c in gltfVrmSpringBone.Colliders) + { + var collider = Nodes[c.Node.Value].gameObject.AddComponent(); + colliders.Add(collider); + if (c.Shape.Capsule is UniGLTF.Extensions.VRMC_springBone.ColliderShapeCapsule capsule) + { + collider.ColliderType = VRM10SpringBoneColliderTypes.Capsule; + collider.Offset = Vector3InvertX(capsule.Offset); + collider.Tail = Vector3InvertX(capsule.Tail); + collider.Radius = capsule.Radius.Value; + } + else if (c.Shape.Sphere is UniGLTF.Extensions.VRMC_springBone.ColliderShapeSphere sphere) + { + collider.ColliderType = VRM10SpringBoneColliderTypes.Sphere; + collider.Offset = Vector3InvertX(sphere.Offset); + collider.Radius = sphere.Radius.Value; + } + else + { + throw new Vrm10Exception("unknown shape"); + } + } + } + + // colliderGroup + if (gltfVrmSpringBone.ColliderGroups != null) + { + var secondary = Root.transform.Find("secondary"); + if (secondary == null) + { + secondary = new GameObject("secondary").transform; + secondary.SetParent(Root.transform, false); + } + + foreach (var g in gltfVrmSpringBone.ColliderGroups) + { + var colliderGroup = secondary.gameObject.AddComponent(); + colliderGroup.Name = g.Name; + controller.SpringBone.ColliderGroups.Add(colliderGroup); + + if (g != null && g.Colliders != null) + { + foreach (var c in g.Colliders) + { + if (c < 0 || c >= colliders.Count) + { + // 不正なindexの場合は無視する + continue; + } + + var collider = colliders[c]; + colliderGroup.Colliders.Add(collider); + } + } + } + } + + // springs + if (gltfVrmSpringBone.Springs != null) + { + // spring + foreach (var gltfSpring in gltfVrmSpringBone.Springs) + { + if (gltfSpring.Joints == null || gltfSpring.Joints.Count == 0) + { + continue; + } + var spring = new Vrm10InstanceSpringBone.Spring(gltfSpring.Name); + controller.SpringBone.Springs.Add(spring); + + if (gltfSpring.Center.HasValue) + { + spring.Center = Nodes[gltfSpring.Center.Value]; + } + + if (gltfSpring.ColliderGroups != null) + { + spring.ColliderGroups = gltfSpring.ColliderGroups.Select(x => controller.SpringBone.ColliderGroups[x]).ToList(); + } + // joint + foreach (var gltfJoint in gltfSpring.Joints) + { + if (gltfJoint.Node.HasValue) + { + var index = gltfJoint.Node.Value; + if (index < 0 || index >= Nodes.Count) + { + throw new IndexOutOfRangeException($"{index} > {Nodes.Count}"); + } + // https://github.com/vrm-c/UniVRM/issues/1441 + // + // https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_springBone-1.0-beta/schema/VRMC_springBone.joint.schema.json + // に基づきデフォルト値を補う + + // node is required + var go = Nodes[gltfJoint.Node.Value].gameObject; + var joint = go.GetComponent(); + if (joint != null) + { + // 仕様違反。マイグレーションで発生しうるのと、エクスポーターでの除外などがされていないので、 + // エラーにせずに飛ばす + Debug.LogWarning($"duplicated spring joint: {Data.TargetPath}"); + continue; + } + + joint = go.AddComponent(); + joint.m_jointRadius = gltfJoint.HitRadius.GetValueOrDefault(0.0f); + joint.m_dragForce = gltfJoint.DragForce.GetValueOrDefault(0.5f); + joint.m_gravityDir = gltfJoint.GravityDir != null ? Vector3InvertX(gltfJoint.GravityDir) : Vector3.down; + joint.m_gravityPower = gltfJoint.GravityPower.GetValueOrDefault(0.0f); + joint.m_stiffnessForce = gltfJoint.Stiffness.GetValueOrDefault(1.0f); + spring.Joints.Add(joint); + } + } + } + } + } + + static AxisMask ConstraintAxes(bool[] flags) + { + var mask = default(AxisMask); + if (flags != null && flags.Length == 3) + { + if (flags[0]) mask |= AxisMask.X; + if (flags[1]) mask |= AxisMask.Y; + if (flags[2]) mask |= AxisMask.Z; + } + return mask; + } + + static Vector3 Vector3InvertX(float[] f) + { + var v = default(Vector3); + if (f != null && f.Length == 3) + { + v.x = -f[0]; + v.y = f[1]; + v.z = f[2]; + } + return v; + } + + /// + /// https://github.com/vrm-c/vrm-specification/tree/master/specification/VRMC_node_constraint-1.0_beta + /// + /// * roll + /// * aim + /// * rotaton + /// + /// + /// + /// + /// + async Task LoadConstraintAsync(IAwaitCaller awaitCaller, Vrm10Instance controller) + { + for (int i = 0; i < Data.GLTF.nodes.Count; ++i) + { + var gltfNode = Data.GLTF.nodes[i]; + if (UniGLTF.Extensions.VRMC_node_constraint.GltfDeserializer.TryGet(gltfNode.extensions, out UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint ext)) + { + var constraint = ext.Constraint; + var node = Nodes[i]; + if (constraint.Roll != null) + { + var roll = constraint.Roll; + var component = node.gameObject.AddComponent(); + component.Source = Nodes[roll.Source.Value]; // required + component.Weight = roll.Weight.GetValueOrDefault(1.0f); + component.RollAxis = roll.RollAxis; // required + } + else if (constraint.Aim != null) + { + var aim = constraint.Aim; + var component = node.gameObject.AddComponent(); + component.Source = Nodes[aim.Source.Value]; // required + component.Weight = aim.Weight.GetValueOrDefault(1.0f); + component.AimAxis = Vrm10ConstraintUtil.ReverseX(aim.AimAxis); // required + } + else if (constraint.Rotation != null) + { + var rotation = constraint.Rotation; + var component = node.gameObject.AddComponent(); + component.Source = Nodes[rotation.Source.Value]; // required + component.Weight = rotation.Weight.GetValueOrDefault(1.0f); + } + else + { + throw new NotImplementedException(); + } + } + } + + await awaitCaller.NextFrame(); + } + + public static HumanBodyBones ToUnity(VrmLib.HumanoidBones bone) + { + switch (bone) + { + // https://github.com/vrm-c/vrm-specification/issues/380 + case VrmLib.HumanoidBones.unknown: return HumanBodyBones.LastBone; + case VrmLib.HumanoidBones.leftThumbMetacarpal: return HumanBodyBones.LeftThumbProximal; + case VrmLib.HumanoidBones.leftThumbProximal: return HumanBodyBones.LeftThumbIntermediate; + case VrmLib.HumanoidBones.rightThumbMetacarpal: return HumanBodyBones.RightThumbProximal; + case VrmLib.HumanoidBones.rightThumbProximal: return HumanBodyBones.RightThumbIntermediate; + } + return CachedEnum.Parse(bone.ToString(), ignoreCase: true); + } + + /// + /// ヒエラルキーを再帰的に構築する + /// + public static void CreateNodes(VrmLib.Node node, GameObject parent, Dictionary nodes) + { + GameObject go = new GameObject(node.Name); + nodes.Add(node, go); + + // world + go.transform.SetPositionAndRotation(node.Translation, node.Rotation); + if (parent != null) + { + go.transform.SetParent(parent.transform, true); + } + // local + go.transform.localScale = node.LocalScaling; + + if (node.Children.Count > 0) + { + for (int n = 0; n < node.Children.Count; n++) + { + CreateNodes(node.Children[n], go, nodes); + } + } + } + + /// + /// MeshFilter + MeshRenderer もしくは SkinnedMeshRenderer を構築する + /// + public static Renderer CreateRenderer(VrmLib.Node node, GameObject go, ModelMap map, + IReadOnlyList materialLoadInfos) + { + Renderer renderer = null; + var hasBlendShape = node.MeshGroup.Meshes[0].MorphTargets.Any(); + if (node.MeshGroup.Skin != null || hasBlendShape) + { + var skinnedMeshRenderer = go.AddComponent(); + renderer = skinnedMeshRenderer; + skinnedMeshRenderer.sharedMesh = map.Meshes[node.MeshGroup]; + if (node.MeshGroup.Skin != null) + { + skinnedMeshRenderer.bones = node.MeshGroup.Skin.Joints.Select(x => map.Nodes[x].transform).ToArray(); + if (node.MeshGroup.Skin.Root != null) + { + skinnedMeshRenderer.rootBone = map.Nodes[node.MeshGroup.Skin.Root].transform; + } + } + } + else + { + var meshFilter = go.AddComponent(); + renderer = go.AddComponent(); + meshFilter.sharedMesh = map.Meshes[node.MeshGroup]; + } + + // hide by default + renderer.enabled = false; + + if (node.MeshGroup.Meshes.Count == 0) + { + throw new NotImplementedException(); + } + else if (node.MeshGroup.Meshes.Count == 1) + { + var materials = node.MeshGroup.Meshes[0].Submeshes.Select(x => materialLoadInfos[x.Material].Asset).ToArray(); + renderer.sharedMaterials = materials; + } + else + { + var materials = node.MeshGroup.Meshes.Select(x => materialLoadInfos[x.Submeshes[0].Material].Asset).ToArray(); + renderer.sharedMaterials = materials; + } + + return renderer; + } + + public override void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) + { + // VRM 固有のリソース(ScriptableObject) + take(SubAssetKey.Create(m_humanoid), m_humanoid); + m_humanoid = null; + + if (m_vrmObject != null) + { + take(VRM10Object.SubAssetKey, m_vrmObject); + m_vrmObject = null; + } + + foreach (var (preset, x) in m_expressions) + { + take(new ExpressionKey(preset, x.name).SubAssetKey, x); + // do nothing + } + m_expressions.Clear(); + + // GLTF のリソース + base.TransferOwnership(take); + } + + public override void Dispose() + { + // VRM specific + if (m_humanoid != null) + { + UnityObjectDestroyer.DestroyRuntimeOrEditor(m_humanoid); + m_humanoid = null; + } + + if (m_vrmObject != null) + { + UnityObjectDestroyer.DestroyRuntimeOrEditor(m_vrmObject); + m_vrmObject = null; + } + + foreach (var (preset, clip) in m_expressions) + { + UnityObjectDestroyer.DestroyRuntimeOrEditor(clip); + } + m_expressions.Clear(); + + base.Dispose(); + } + + public sealed class ModelMap + { + public readonly Dictionary Nodes = new Dictionary(); + public readonly Dictionary Meshes = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/IO/Vrm10Importer.cs.meta b/Assets/External/VRM10/Runtime/IO/Vrm10Importer.cs.meta new file mode 100644 index 000000000..5d5cacea2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/Vrm10Importer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae61d167cf541b44c8645b3c864390f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/VrmAnimationExporter.cs b/Assets/External/VRM10/Runtime/IO/VrmAnimationExporter.cs new file mode 100644 index 000000000..864dd9a5f --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/VrmAnimationExporter.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UniGLTF; +using UniHumanoid; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + public class VrmAnimationExporter : gltfExporter + { + public VrmAnimationExporter( + ExportingGltfData data, + GltfExportSettings settings) + : base(data, settings) + { + settings.InverseAxis = Axes.X; + } + + readonly List m_times = new(); + + class PositionExporter + { + public List Values = new(); + public Transform Node; + readonly Transform m_root; + + public PositionExporter(Transform bone, Transform root) + { + Node = bone; + m_root = root; + } + + public void Add() + { + var p = m_root.worldToLocalMatrix.MultiplyPoint(Node.position); + // reverse-X + Values.Add(new Vector3(-p.x, p.y, p.z)); + } + } + PositionExporter m_position; + public void SetPositionBoneAndParent(Transform bone, Transform parent) + { + m_position = new PositionExporter(bone, parent); + } + + class RotationExporter + { + public List Values = new(); + public readonly Transform Node; + public Transform m_parent; + + public RotationExporter(Transform bone, Transform parent) + { + Node = bone; + m_parent = parent; + } + + public void Add() + { + var q = Quaternion.Inverse(m_parent.rotation) * Node.rotation; + // reverse-X + Values.Add(new Quaternion(q.x, -q.y, -q.z, q.w)); + } + } + readonly Dictionary m_rotations = new(); + public void AddRotationBoneAndParent(HumanBodyBones bone, Transform transform, Transform parent) + { + m_rotations.Add(bone, new RotationExporter(transform, parent)); + } + + public void AddFrame(TimeSpan time) + { + m_times.Add((float)time.TotalSeconds); + m_position.Add(); + foreach (var kv in m_rotations) + { + kv.Value.Add(); + } + } + + public void Export(Action addFrames) + { + base.Export(new RuntimeTextureSerializer()); + + addFrames(this); + + // + // export + // + var gltfAnimation = new glTFAnimation + { + }; + _data.Gltf.animations.Add(gltfAnimation); + + // this.Nodes には 右手左手変換後のコピーが入っている + // 代替として名前で逆引きする + var names = Nodes.Select(x => x.name).ToList(); + + // time values + var input = _data.ExtendBufferAndGetAccessorIndex(m_times.ToArray()); + + { + var output = _data.ExtendBufferAndGetAccessorIndex(m_position.Values.ToArray()); + var sampler = gltfAnimation.samplers.Count; + gltfAnimation.samplers.Add(new glTFAnimationSampler + { + input = input, + output = output, + interpolation = "LINEAR", + }); + + gltfAnimation.channels.Add(new glTFAnimationChannel + { + sampler = sampler, + target = new glTFAnimationTarget + { + node = names.IndexOf(m_position.Node.name), + path = "translation", + }, + }); + } + + foreach (var kv in m_rotations) + { + var output = _data.ExtendBufferAndGetAccessorIndex(kv.Value.Values.ToArray()); + var sampler = gltfAnimation.samplers.Count; + gltfAnimation.samplers.Add(new glTFAnimationSampler + { + input = input, + output = output, + interpolation = "LINEAR", + }); + + gltfAnimation.channels.Add(new glTFAnimationChannel + { + sampler = sampler, + target = new glTFAnimationTarget + { + node = names.IndexOf(kv.Value.Node.name), + path = "rotation", + }, + }); + } + + // VRMC_vrm_animation + var vrmAnimation = VrmAnimationUtil.Create(m_rotations.ToDictionary(kv => kv.Key, kv => kv.Value.Node), names); + UniGLTF.Extensions.VRMC_vrm_animation.GltfSerializer.SerializeTo( + ref _data.Gltf.extensions + , vrmAnimation); + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/VrmAnimationExporter.cs.meta b/Assets/External/VRM10/Runtime/IO/VrmAnimationExporter.cs.meta new file mode 100644 index 000000000..56ed3cc88 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/VrmAnimationExporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ec9e478ed511fa478a5935aa08b36c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/VrmAnimationImporter.cs b/Assets/External/VRM10/Runtime/IO/VrmAnimationImporter.cs new file mode 100644 index 000000000..e52a898dc --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/VrmAnimationImporter.cs @@ -0,0 +1,299 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using UniGLTF; +using UniGLTF.Extensions.VRMC_vrm_animation; +using UniHumanoid; +using UniJSON; +using UnityEngine; +using UniVRM10; +using VRMShaders; + +namespace UniVRM10 +{ + public class VrmAnimationImporter : UniGLTF.ImporterContext + { + VRMC_vrm_animation m_vrma; + + public VrmAnimationImporter(GltfData data, + IReadOnlyDictionary externalObjectMap = null, + ITextureDeserializer textureDeserializer = null, + IMaterialDescriptorGenerator materialGenerator = null) + : base(data, externalObjectMap, textureDeserializer, materialGenerator) + { + InvertAxis = Axes.X; + + m_vrma = GetExtension(Data); + } + + private static VRMC_vrm_animation GetExtension(GltfData data) + { + if (data.GLTF.extensions is UniGLTF.glTFExtensionImport extensions) + { + foreach (var kv in extensions.ObjectItems()) + { + if (kv.Key.GetString() == "VRMC_vrm_animation") + { + return UniGLTF.Extensions.VRMC_vrm_animation.GltfDeserializer.Deserialize(kv.Value); + } + } + } + return null; + } + + private static int? GetNodeIndex(UniGLTF.Extensions.VRMC_vrm_animation.Humanoid humanoid, HumanBodyBones bone) + { + switch (bone) + { + case HumanBodyBones.Hips: return humanoid.HumanBones.Hips?.Node; + case HumanBodyBones.LeftUpperLeg: return humanoid.HumanBones.LeftUpperLeg?.Node; + case HumanBodyBones.RightUpperLeg: return humanoid.HumanBones.RightUpperLeg?.Node; + case HumanBodyBones.LeftLowerLeg: return humanoid.HumanBones.LeftLowerLeg?.Node; + case HumanBodyBones.RightLowerLeg: return humanoid.HumanBones.RightLowerLeg?.Node; + case HumanBodyBones.LeftFoot: return humanoid.HumanBones.LeftFoot?.Node; + case HumanBodyBones.RightFoot: return humanoid.HumanBones.RightFoot?.Node; + case HumanBodyBones.Spine: return humanoid.HumanBones.Spine?.Node; + case HumanBodyBones.Chest: return humanoid.HumanBones.Chest?.Node; + case HumanBodyBones.Neck: return humanoid.HumanBones.Neck?.Node; + case HumanBodyBones.Head: return humanoid.HumanBones.Head?.Node; + case HumanBodyBones.LeftShoulder: return humanoid.HumanBones.LeftShoulder?.Node; + case HumanBodyBones.RightShoulder: return humanoid.HumanBones.RightShoulder?.Node; + case HumanBodyBones.LeftUpperArm: return humanoid.HumanBones.LeftUpperArm?.Node; + case HumanBodyBones.RightUpperArm: return humanoid.HumanBones.RightUpperArm?.Node; + case HumanBodyBones.LeftLowerArm: return humanoid.HumanBones.LeftLowerArm?.Node; + case HumanBodyBones.RightLowerArm: return humanoid.HumanBones.RightLowerArm?.Node; + case HumanBodyBones.LeftHand: return humanoid.HumanBones.LeftHand?.Node; + case HumanBodyBones.RightHand: return humanoid.HumanBones.RightHand?.Node; + case HumanBodyBones.LeftToes: return humanoid.HumanBones.LeftToes?.Node; + case HumanBodyBones.RightToes: return humanoid.HumanBones.RightToes?.Node; + // case HumanBodyBones.LeftEye: return humanoid.HumanBones.LeftEye?.Node; + // case HumanBodyBones.RightEye: return humanoid.HumanBones.RightEye?.Node; + case HumanBodyBones.Jaw: return humanoid.HumanBones.Jaw?.Node; + case HumanBodyBones.LeftThumbProximal: return humanoid.HumanBones.LeftThumbMetacarpal?.Node; // Metacarpal + case HumanBodyBones.LeftThumbIntermediate: return humanoid.HumanBones.LeftThumbProximal?.Node; // Proximal + case HumanBodyBones.LeftThumbDistal: return humanoid.HumanBones.LeftThumbDistal?.Node; + case HumanBodyBones.LeftIndexProximal: return humanoid.HumanBones.LeftIndexProximal?.Node; + case HumanBodyBones.LeftIndexIntermediate: return humanoid.HumanBones.LeftIndexIntermediate?.Node; + case HumanBodyBones.LeftIndexDistal: return humanoid.HumanBones.LeftIndexDistal?.Node; + case HumanBodyBones.LeftMiddleProximal: return humanoid.HumanBones.LeftMiddleProximal?.Node; + case HumanBodyBones.LeftMiddleIntermediate: return humanoid.HumanBones.LeftMiddleIntermediate?.Node; + case HumanBodyBones.LeftMiddleDistal: return humanoid.HumanBones.LeftMiddleDistal?.Node; + case HumanBodyBones.LeftRingProximal: return humanoid.HumanBones.LeftRingProximal?.Node; + case HumanBodyBones.LeftRingIntermediate: return humanoid.HumanBones.LeftRingIntermediate?.Node; + case HumanBodyBones.LeftRingDistal: return humanoid.HumanBones.LeftRingDistal?.Node; + case HumanBodyBones.LeftLittleProximal: return humanoid.HumanBones.LeftLittleProximal?.Node; + case HumanBodyBones.LeftLittleIntermediate: return humanoid.HumanBones.LeftLittleIntermediate?.Node; + case HumanBodyBones.LeftLittleDistal: return humanoid.HumanBones.LeftLittleDistal?.Node; + case HumanBodyBones.RightThumbProximal: return humanoid.HumanBones.RightThumbMetacarpal?.Node; // Metacarpal + case HumanBodyBones.RightThumbIntermediate: return humanoid.HumanBones.RightThumbProximal?.Node; // Proximal + case HumanBodyBones.RightThumbDistal: return humanoid.HumanBones.RightThumbDistal?.Node; + case HumanBodyBones.RightIndexProximal: return humanoid.HumanBones.RightIndexProximal?.Node; + case HumanBodyBones.RightIndexIntermediate: return humanoid.HumanBones.RightIndexIntermediate?.Node; + case HumanBodyBones.RightIndexDistal: return humanoid.HumanBones.RightIndexDistal?.Node; + case HumanBodyBones.RightMiddleProximal: return humanoid.HumanBones.RightMiddleProximal?.Node; + case HumanBodyBones.RightMiddleIntermediate: return humanoid.HumanBones.RightMiddleIntermediate?.Node; + case HumanBodyBones.RightMiddleDistal: return humanoid.HumanBones.RightMiddleDistal?.Node; + case HumanBodyBones.RightRingProximal: return humanoid.HumanBones.RightRingProximal?.Node; + case HumanBodyBones.RightRingIntermediate: return humanoid.HumanBones.RightRingIntermediate?.Node; + case HumanBodyBones.RightRingDistal: return humanoid.HumanBones.RightRingDistal?.Node; + case HumanBodyBones.RightLittleProximal: return humanoid.HumanBones.RightLittleProximal?.Node; + case HumanBodyBones.RightLittleIntermediate: return humanoid.HumanBones.RightLittleIntermediate?.Node; + case HumanBodyBones.RightLittleDistal: return humanoid.HumanBones.RightLittleDistal?.Node; + case HumanBodyBones.UpperChest: return humanoid.HumanBones.UpperChest?.Node; + } + return default; + } + + public Dictionary GetHumanMap() + { + var humanMap = new Dictionary(); + if (m_vrma is UniGLTF.Extensions.VRMC_vrm_animation.VRMC_vrm_animation animation && animation.Humanoid != null) + { + foreach (HumanBodyBones bone in UniGLTF.Utils.CachedEnum.GetValues()) + { + // Debug.Log($"{bone} => {index}"); + var node = GetNodeIndex(animation.Humanoid, bone); + if (node.HasValue) + { + humanMap.Add(bone, Nodes[node.Value]); + } + } + } + return humanMap; + } + + class ExpressionInfo + { + public ExpressionKey Key; + public int ChannelIndex; + public string PropertyName; + public glTFAnimationChannel Channel; + } + + ExpressionInfo GetExpression(glTFAnimation animation, ExpressionKey key, string propertyName, Expression expression) + { + if (expression == null) + { + return null; + } + if (!expression.Node.HasValue) + { + return null; + } + + for (int i = 0; i < animation.channels.Count; ++i) + { + var channel = animation.channels[i]; + if (channel.target.node == expression.Node.Value) + { + return new ExpressionInfo + { + Key = key, + ChannelIndex = i, + // 全部小文字 + PropertyName = propertyName.ToLower(), + Channel = channel, + }; + } + } + + return null; + } + + IEnumerable IterateExpressions() + { + if (m_vrma is UniGLTF.Extensions.VRMC_vrm_animation.VRMC_vrm_animation animation && animation.Expressions != null) + { + var gltfAnimation = Data.GLTF.animations[0]; + if (animation.Expressions.Preset is Preset preset) + { + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.happy), nameof(Vrm10AnimationInstance.preset_happy), preset.Happy) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.angry), nameof(Vrm10AnimationInstance.preset_angry), preset.Angry) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.sad), nameof(Vrm10AnimationInstance.preset_sad), preset.Sad) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.relaxed), nameof(Vrm10AnimationInstance.preset_relaxed), preset.Relaxed) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.surprised), nameof(Vrm10AnimationInstance.preset_surprised), preset.Surprised) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.aa), nameof(Vrm10AnimationInstance.preset_aa), preset.Aa) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.ih), nameof(Vrm10AnimationInstance.preset_ih), preset.Ih) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.ou), nameof(Vrm10AnimationInstance.preset_ou), preset.Ou) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.ee), nameof(Vrm10AnimationInstance.preset_ee), preset.Ee) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.oh), nameof(Vrm10AnimationInstance.preset_oh), preset.Oh) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.blink), nameof(Vrm10AnimationInstance.preset_blink), preset.Blink) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.blinkLeft), nameof(Vrm10AnimationInstance.preset_blinkleft), preset.BlinkLeft) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.blinkRight), nameof(Vrm10AnimationInstance.preset_blinkright), preset.BlinkRight) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.lookUp), "preset_lookup", preset.LookUp) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.lookDown), "preset_lookdown", preset.LookDown) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.lookLeft), "preset_lookleft", preset.LookLeft) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.lookRight), "preset_lookright", preset.LookRight) is ExpressionInfo info) yield return info; } + { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.neutral), nameof(Vrm10AnimationInstance.preset_neutral), preset.Neutral) is ExpressionInfo info) yield return info; } + } + if (animation.Expressions.Custom != null) + { + int customIndex = 0; + foreach (var (k, v) in animation.Expressions.Custom.OrderBy(kv => kv.Value.Node)) + { + var info = GetExpression(gltfAnimation, ExpressionKey.CreateCustom(k), $"custom_{customIndex:D2}", v); + ++customIndex; + if (info != null) + { + yield return info; + } + } + } + } + } + + /// + /// xyz translation カーブから x だけの カーブを生成する + /// + /// + /// + /// + static AnimationCurve CreateCurve( + float[] input, + float[] output) + { + var keyframes = new List(); + for (var inputIndex = 0; inputIndex < input.Length; ++inputIndex) + { + var time = input[inputIndex]; + // translation + var value = output[inputIndex * 3]; + keyframes.Add(new Keyframe(time, value, 0, 0)); + if (keyframes.Count > 0) + { + AnimationImporterUtil.CalculateTangent(keyframes, keyframes.Count - 1); + } + } + + var curve = new AnimationCurve(); + foreach (var keyFrame in keyframes) + { + curve.AddKey(keyFrame); + } + return curve; + } + + public override async Task LoadAsync(IAwaitCaller awaitCaller, Func measureTime = null) + { + // Expression は AnimationClip を分ける。 + // glTFData から関連 Animation を取り除いて、取っておく。 + var expressions = IterateExpressions().ToArray(); + foreach (var channelIndex in expressions.Select(x => x.ChannelIndex).OrderByDescending(x => x)) + { + var nodeIndex = Data.GLTF.animations[0].channels[channelIndex].target.node; + Data.GLTF.nodes.RemoveAt(nodeIndex); + // 後ろから順に channel を除去 + Data.GLTF.animations[0].channels.RemoveAt(channelIndex); + + Debug.Log($"remove: {channelIndex}"); + } + Data.GLTF.scenes[0].nodes = Data.GLTF.scenes[0].nodes.Take(1).ToArray(); + + // Humanoid Animation が Gltf アニメーションとしてロードされる + var instance = await base.LoadAsync(awaitCaller, measureTime); + + // setup humanoid + var humanMap = GetHumanMap(); + if (humanMap.Count > 0) + { + var description = AvatarDescription.Create(humanMap); + // + // avatar + // + var avatar = description.CreateAvatar(instance.Root.transform); + avatar.name = "Avatar"; + // AvatarDescription = description; + var animator = instance.gameObject.AddComponent(); + animator.avatar = avatar; + } + + if (expressions.Length > 0) + { + var animation = instance.GetComponent(); + var clip = animation.clip; + + // Expression の float カーブを追加する + // VrmAnimationInstance の "preset_xx" field に連動する + var gltfAnimation = Data.GLTF.animations[0]; + foreach (var expression in expressions) + { + var channel = expression.Channel; + var sampler = gltfAnimation.samplers[channel.sampler]; + var input = Data.GetArrayFromAccessor(sampler.input); + var output = Data.FlatternFloatArrayFromAccessor(sampler.output); + var curve = CreateCurve( + input.ToArray(), + output.ToArray()); + clip.SetCurve("", typeof(Vrm10AnimationInstance), expression.PropertyName, curve); + } + } + + // VRMA-animation solver + var animationInstance = instance.gameObject.AddComponent(); + animationInstance.Initialize(expressions.Select(x => x.Key)); + + return instance; + } + } +} diff --git a/Assets/External/VRM10/Runtime/IO/VrmAnimationImporter.cs.meta b/Assets/External/VRM10/Runtime/IO/VrmAnimationImporter.cs.meta new file mode 100644 index 000000000..33367c278 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/VrmAnimationImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0381f410b38d5184baa6f28213608810 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/IO/VrmAnimationUtil.cs b/Assets/External/VRM10/Runtime/IO/VrmAnimationUtil.cs new file mode 100644 index 000000000..38e22d49b --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/VrmAnimationUtil.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using UniGLTF.Extensions.VRMC_vrm_animation; + +namespace UniVRM10 +{ + public static class VrmAnimationUtil + { + public static VRMC_vrm_animation Create( + Dictionary map, + List names) + { + var vrmAnimation = new VRMC_vrm_animation + { + SpecVersion = "1.0", + Humanoid = new UniGLTF.Extensions.VRMC_vrm_animation.Humanoid + { + HumanBones = new HumanBones(), + } + }; + foreach (var kv in map) + { + switch (kv.Key) + { + case UnityEngine.HumanBodyBones.Hips: vrmAnimation.Humanoid.HumanBones.Hips = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftUpperLeg: vrmAnimation.Humanoid.HumanBones.LeftUpperLeg = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightUpperLeg: vrmAnimation.Humanoid.HumanBones.RightUpperLeg = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftLowerLeg: vrmAnimation.Humanoid.HumanBones.LeftLowerLeg = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightLowerLeg: vrmAnimation.Humanoid.HumanBones.RightLowerLeg = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftFoot: vrmAnimation.Humanoid.HumanBones.LeftFoot = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightFoot: vrmAnimation.Humanoid.HumanBones.RightFoot = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.Spine: vrmAnimation.Humanoid.HumanBones.Spine = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.Chest: vrmAnimation.Humanoid.HumanBones.Chest = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.UpperChest: vrmAnimation.Humanoid.HumanBones.UpperChest = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.Neck: vrmAnimation.Humanoid.HumanBones.Neck = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.Head: vrmAnimation.Humanoid.HumanBones.Head = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftShoulder: vrmAnimation.Humanoid.HumanBones.LeftShoulder = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightShoulder: vrmAnimation.Humanoid.HumanBones.RightShoulder = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftUpperArm: vrmAnimation.Humanoid.HumanBones.LeftUpperArm = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightUpperArm: vrmAnimation.Humanoid.HumanBones.RightUpperArm = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftLowerArm: vrmAnimation.Humanoid.HumanBones.LeftLowerArm = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightLowerArm: vrmAnimation.Humanoid.HumanBones.RightLowerArm = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftHand: vrmAnimation.Humanoid.HumanBones.LeftHand = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightHand: vrmAnimation.Humanoid.HumanBones.RightHand = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftToes: vrmAnimation.Humanoid.HumanBones.LeftToes = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightToes: vrmAnimation.Humanoid.HumanBones.RightToes = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.Jaw: vrmAnimation.Humanoid.HumanBones.Jaw = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftThumbProximal: vrmAnimation.Humanoid.HumanBones.LeftThumbMetacarpal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftThumbIntermediate: vrmAnimation.Humanoid.HumanBones.LeftThumbProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftThumbDistal: vrmAnimation.Humanoid.HumanBones.LeftThumbDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftIndexProximal: vrmAnimation.Humanoid.HumanBones.LeftIndexProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftIndexIntermediate: vrmAnimation.Humanoid.HumanBones.LeftIndexIntermediate = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftIndexDistal: vrmAnimation.Humanoid.HumanBones.LeftIndexDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftMiddleProximal: vrmAnimation.Humanoid.HumanBones.LeftMiddleProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftMiddleIntermediate: vrmAnimation.Humanoid.HumanBones.LeftMiddleIntermediate = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftMiddleDistal: vrmAnimation.Humanoid.HumanBones.LeftMiddleDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftRingProximal: vrmAnimation.Humanoid.HumanBones.LeftRingProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftRingIntermediate: vrmAnimation.Humanoid.HumanBones.LeftRingIntermediate = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftRingDistal: vrmAnimation.Humanoid.HumanBones.LeftRingDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftLittleProximal: vrmAnimation.Humanoid.HumanBones.LeftLittleProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftLittleIntermediate: vrmAnimation.Humanoid.HumanBones.LeftLittleIntermediate = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.LeftLittleDistal: vrmAnimation.Humanoid.HumanBones.LeftLittleDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightThumbProximal: vrmAnimation.Humanoid.HumanBones.RightThumbMetacarpal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightThumbIntermediate: vrmAnimation.Humanoid.HumanBones.RightThumbProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightThumbDistal: vrmAnimation.Humanoid.HumanBones.RightThumbDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightIndexProximal: vrmAnimation.Humanoid.HumanBones.RightIndexProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightIndexIntermediate: vrmAnimation.Humanoid.HumanBones.RightIndexIntermediate = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightIndexDistal: vrmAnimation.Humanoid.HumanBones.RightIndexDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightMiddleProximal: vrmAnimation.Humanoid.HumanBones.RightMiddleProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightMiddleIntermediate: vrmAnimation.Humanoid.HumanBones.RightMiddleIntermediate = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightMiddleDistal: vrmAnimation.Humanoid.HumanBones.RightMiddleDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightRingProximal: vrmAnimation.Humanoid.HumanBones.RightRingProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightRingIntermediate: vrmAnimation.Humanoid.HumanBones.RightRingIntermediate = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightRingDistal: vrmAnimation.Humanoid.HumanBones.RightRingDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightLittleProximal: vrmAnimation.Humanoid.HumanBones.RightLittleProximal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightLittleIntermediate: vrmAnimation.Humanoid.HumanBones.RightLittleIntermediate = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + case UnityEngine.HumanBodyBones.RightLittleDistal: vrmAnimation.Humanoid.HumanBones.RightLittleDistal = new HumanBone { Node = names.IndexOf(kv.Value.name) }; break; + } + } + + return vrmAnimation; + } + } +} + diff --git a/Assets/External/VRM10/Runtime/IO/VrmAnimationUtil.cs.meta b/Assets/External/VRM10/Runtime/IO/VrmAnimationUtil.cs.meta new file mode 100644 index 000000000..d4a5e89f0 --- /dev/null +++ b/Assets/External/VRM10/Runtime/IO/VrmAnimationUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e8cc186fd23c35d488e371b0b58a27ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/MeshUtility.meta b/Assets/External/VRM10/Runtime/MeshUtility.meta new file mode 100644 index 000000000..70b8b2c67 --- /dev/null +++ b/Assets/External/VRM10/Runtime/MeshUtility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4eeaac509504ff94e9743df73d3dae42 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/External/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs new file mode 100644 index 000000000..cafb06db5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniHumanoid; +using UnityEngine; + + +namespace UniVRM10 +{ + public class Vrm10MeshUtility : UniGLTF.MeshUtility.GltfMeshUtility + { + public Vrm10MeshUtility() + { + FreezeBlendShapeRotationAndScaling = true; + } + + bool _generateFirstPerson = false; + public override IEnumerable CopyInstantiate(GameObject go, GameObject instance) + { + var copy = base.CopyInstantiate(go, instance); + _generateFirstPerson = false; + if (GenerateMeshForFirstPersonAuto) + { + foreach (var g in copy) + { + if (g.Name == "auto") + { + _generateFirstPerson = true; + // 元のメッシュを三人称に変更 + yield return new UniGLTF.MeshUtility.MeshIntegrationGroup + { + Name = UniGLTF.Extensions.VRMC_vrm.FirstPersonType.thirdPersonOnly.ToString(), + IntegrationType = UniGLTF.MeshUtility.MeshIntegrationGroup.MeshIntegrationTypes.ThirdPersonOnly, + Renderers = g.Renderers.ToList(), + }; + } + yield return g; + } + } + else + { + foreach (var g in copy) + { + yield return g; + } + } + } + + protected override + bool TryIntegrate( + GameObject empty, + UniGLTF.MeshUtility.MeshIntegrationGroup group, + out (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) resultAndAdded) + { + if (!base.TryIntegrate(empty, group, out resultAndAdded)) + { + return false; + } + var (result, newList) = resultAndAdded; + + if (_generateFirstPerson && group.Name == nameof(UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto)) + { + // Mesh 統合の後処理 + // FirstPerson == "auto" の場合に + // 頭部の無いモデルを追加で作成する + Debug.Log("generateFirstPerson"); + if (result.Integrated.Mesh != null) + { + // BlendShape 有り + _ProcessFirstPerson(_vrmInstance.Humanoid.Head, result.Integrated.IntegratedRenderer); + } + if (result.IntegratedNoBlendShape.Mesh != null) + { + // BlendShape 無しの方 + _ProcessFirstPerson(_vrmInstance.Humanoid.Head, result.IntegratedNoBlendShape.IntegratedRenderer); + } + } + return true; + } + + private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + var task = VRM10ObjectFirstPerson.CreateErasedMeshAsync( + smr, + firstPersonBone, + new VRMShaders.ImmediateCaller()); + task.Wait(); + var mesh = task.Result; + if (mesh != null) + { + smr.sharedMesh = mesh; + smr.name = "auto.headless"; + } + else + { + Debug.LogWarning("no result"); + } + } + + Vrm10Instance _vrmInstance = null; + /// + /// glTF に比べて Humanoid や FirstPerson の処理が追加される + /// + public override (List, List) Process( + GameObject target, IEnumerable groupCopy) + { + _vrmInstance = target.GetComponent(); + if (_vrmInstance == null) + { + throw new ArgumentException(); + } + + // TODO: update: spring + // TODO: update: constraint + // TODO: update: firstPerson offset + var (list, newList) = base.Process(target, groupCopy); + + if (FreezeBlendShapeRotationAndScaling) + { + var animator = target.GetComponent(); + var newAvatar = AvatarDescription.RecreateAvatar(animator); + GameObject.DestroyImmediate(animator); + animator = target.AddComponent(); + animator.avatar = newAvatar; + } + + return (list, newList); + } + + public override void UpdateMeshIntegrationGroups(GameObject root) + { + MeshIntegrationGroups.Clear(); + if (root == null) + { + return; + } + var vrm1 = root.GetComponent(); + if (vrm1 == null) + { + return; + } + var vrmObject = vrm1.Vrm; + if (vrmObject == null) + { + return; + } + var fp = vrmObject.FirstPerson; + if (fp == null) + { + return; + } + foreach (var a in fp.Renderers) + { + var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString()); + g.Renderers.Add(a.GetRenderer(root.transform)); + } + + var orphan = root.GetComponentsInChildren().Where(x => !_HasRenderer(x)).ToArray(); + if (orphan.Length > 0) + { + var g = _GetOrCreateGroup("both"); + g.Renderers.AddRange(orphan); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs.meta b/Assets/External/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs.meta new file mode 100644 index 000000000..60452fa5d --- /dev/null +++ b/Assets/External/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ef8f213cebb99f418c39baa9419296e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration.meta b/Assets/External/VRM10/Runtime/Migration.meta new file mode 100644 index 000000000..26398a409 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 475aa606f7fac0648a504be5102a6f16 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/Materials.meta b/Assets/External/VRM10/Runtime/Migration/Materials.meta new file mode 100644 index 000000000..6eee5178a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f68d2e3e086d4768ae14cee7b28493cc +timeCreated: 1635418532 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationLegacyUnlitMaterial.cs b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationLegacyUnlitMaterial.cs new file mode 100644 index 000000000..8e7e5a50d --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationLegacyUnlitMaterial.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using UniGLTF; +using UniJSON; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Migration Target: VRM file with Unlit material exported with UniVRM v0.43 or lower. + /// + /// 過去の UniVRM において、KHR_materials_unlit 拡張を使わず、VRM 拡張を用いて Unlit を表現していた Material をマイグレーションする。 + /// KHR_materials_unlit を用いてマイグレーションする. + /// + internal static class MigrationLegacyUnlitMaterial + { + public static bool Migrate(glTF gltf, IReadOnlyList vrm0XMaterials) + { + var anyMigrated = false; + + for (var materialIdx = 0; materialIdx < gltf.materials.Count; ++materialIdx) + { + try + { + var newMaterial = Migrate(vrm0XMaterials[materialIdx], gltf.materials[materialIdx].name); + if (newMaterial != null) + { + // NOTE: マイグレーション対象だった場合、上書きする. + gltf.materials[materialIdx] = newMaterial; + anyMigrated = true; + } + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + + return anyMigrated; + } + + private static glTFMaterial Migrate(JsonNode vrm0XMaterial, string materialName) + { + var unlitMaterial = new glTFMaterial + { + name = materialName, + pbrMetallicRoughness = new glTFPbrMetallicRoughness + { + metallicFactor = 0f, + roughnessFactor = 1f, + }, + extensions = new glTFExtensionExport() + .Add(glTF_KHR_materials_unlit.ExtensionName, new ArraySegment(glTF_KHR_materials_unlit.Raw)), + }; + + switch (MigrationMaterialUtil.GetShaderName(vrm0XMaterial)) + { + case "Unlit/Color": + unlitMaterial.pbrMetallicRoughness.baseColorFactor = MigrationMaterialUtil.GetBaseColorFactor(vrm0XMaterial); + unlitMaterial.pbrMetallicRoughness.baseColorTexture = null; + return unlitMaterial; + case "Unlit/Texture": + unlitMaterial.pbrMetallicRoughness.baseColorFactor = new float[] {1, 1, 1, 1}; + unlitMaterial.pbrMetallicRoughness.baseColorTexture = MigrationMaterialUtil.GetBaseColorTexture(vrm0XMaterial); + return unlitMaterial; + case "Unlit/Transparent": + unlitMaterial.pbrMetallicRoughness.baseColorFactor = new float[] {1, 1, 1, 1}; + unlitMaterial.pbrMetallicRoughness.baseColorTexture = MigrationMaterialUtil.GetBaseColorTexture(vrm0XMaterial); + unlitMaterial.alphaMode = "BLEND"; + return unlitMaterial; + case "Unlit/Transparent Cutout": + unlitMaterial.pbrMetallicRoughness.baseColorFactor = new float[] {1, 1, 1, 1}; + unlitMaterial.pbrMetallicRoughness.baseColorTexture = MigrationMaterialUtil.GetBaseColorTexture(vrm0XMaterial); + unlitMaterial.alphaMode = "MASK"; + unlitMaterial.alphaCutoff = MigrationMaterialUtil.GetCutoff(vrm0XMaterial); + return unlitMaterial; + case "VRM/UnlitTexture": + unlitMaterial.pbrMetallicRoughness.baseColorFactor = new float[] {1, 1, 1, 1}; + unlitMaterial.pbrMetallicRoughness.baseColorTexture = MigrationMaterialUtil.GetBaseColorTexture(vrm0XMaterial); + return unlitMaterial; + case "VRM/UnlitTransparent": + unlitMaterial.pbrMetallicRoughness.baseColorFactor = new float[] {1, 1, 1, 1}; + unlitMaterial.pbrMetallicRoughness.baseColorTexture = MigrationMaterialUtil.GetBaseColorTexture(vrm0XMaterial); + unlitMaterial.alphaMode = "BLEND"; + return unlitMaterial; + case "VRM/UnlitCutout": + unlitMaterial.pbrMetallicRoughness.baseColorFactor = new float[] {1, 1, 1, 1}; + unlitMaterial.pbrMetallicRoughness.baseColorTexture = MigrationMaterialUtil.GetBaseColorTexture(vrm0XMaterial); + unlitMaterial.alphaMode = "MASK"; + unlitMaterial.alphaCutoff = MigrationMaterialUtil.GetCutoff(vrm0XMaterial); + return unlitMaterial; + case "VRM/UnlitTransparentZWrite": + // NOTE: ZWrite マテリアルのみ、MToon にマイグレーションするため、別処理. + return null; + default: + return null; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationLegacyUnlitMaterial.cs.meta b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationLegacyUnlitMaterial.cs.meta new file mode 100644 index 000000000..461c31842 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationLegacyUnlitMaterial.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 46c50e244d72488dac8e26320bac782d +timeCreated: 1635420423 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMToonMaterial.cs b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMToonMaterial.cs new file mode 100644 index 000000000..0aecd7bfa --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMToonMaterial.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections.Generic; +using MToon; +using UniGLTF; +using UniGLTF.Extensions.VRMC_materials_mtoon; +using UniJSON; +using UnityEngine; +using VRMShaders.VRM10.MToon10.Runtime; +using ColorSpace = VRMShaders.ColorSpace; +using OutlineWidthMode = MToon.OutlineWidthMode; +using RenderMode = MToon.RenderMode; + +namespace UniVRM10 +{ + internal static class MigrationMToonMaterial + { + public static void Migrate(glTF gltf, JsonNode vrm0) + { + // Create MToonDefinition(0.x) from JSON(0.x) + var sourceMaterials = new (Vrm0XMToonValue, glTFMaterial)[gltf.materials.Count]; + for (int i = 0; i < gltf.materials.Count; ++i) + { + var vrm0XMaterial = vrm0["materialProperties"][i]; + if (MigrationMaterialUtil.GetShaderName(vrm0XMaterial) == "VRM/MToon") + { + sourceMaterials[i] = (new Vrm0XMToonValue(vrm0XMaterial), gltf.materials[i]); + } + else + { + // NOTE: MToon ではない場合、マイグレーション先に書き込まない. + sourceMaterials[i] = (null, null); + } + } + + // Collect RenderQueues Pass + // 元の描画順序をできるだけ保つようにして RenderQueue を変換する + var transparentRenderQueues = new SortedSet(); + var transparentZWriteRenderQueues = new SortedSet(); + foreach (var (mtoon, gltfMaterial) in sourceMaterials) + { + if (mtoon == null) + { + continue; + } + switch (mtoon.Definition.Rendering.RenderMode) + { + case RenderMode.Opaque: + break; + case RenderMode.Cutout: + break; + case RenderMode.Transparent: + transparentRenderQueues.Add(mtoon.Definition.Rendering.RenderQueueOffsetNumber); + break; + case RenderMode.TransparentWithZWrite: + transparentZWriteRenderQueues.Add(mtoon.Definition.Rendering.RenderQueueOffsetNumber); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + var defaultTransparentQueue = 0; + var transparentRenderQueueMap = new Dictionary(); + foreach (var srcQueue in transparentRenderQueues.Reverse()) + { + transparentRenderQueueMap.Add(srcQueue, defaultTransparentQueue--); + } + var defaultTransparentZWriteQueue = 0; + var transparentZWriteRenderQueueMap = new Dictionary(); + foreach (var srcQueue in transparentZWriteRenderQueues) + { + transparentZWriteRenderQueueMap.Add(srcQueue, defaultTransparentZWriteQueue++); + } + + // Main Pass + foreach (var (mtoon, gltfMaterial) in sourceMaterials) + { + if (mtoon == null) + { + continue; + } + var extensions = new glTFExtensionExport(); + gltfMaterial.extensions = extensions; + extensions.Add( + glTF_KHR_materials_unlit.ExtensionName, + new ArraySegment(glTF_KHR_materials_unlit.Raw)); + + // + // definition の中身を gltfMaterial と gltfMaterial.extensions.VRMC_materials_mtoon に移し替える + // + var dst = new VRMC_materials_mtoon + { + SpecVersion = Vrm10Exporter.MTOON_SPEC_VERSION, + }; + + // Texture Transform + Vector2? textureScale = default; + Vector2? textureOffset = default; + if (mtoon.TextureIndexMap.MainTex.HasValue && mtoon.TextureOffsetScales.TryGetValue("_MainTex", out var offsetScaleArray)) + { + textureScale = new Vector2(offsetScaleArray[2], offsetScaleArray[3]); + textureOffset = new Vector2(offsetScaleArray[0], offsetScaleArray[1]); + } + + // Rendering + switch (mtoon.Definition.Rendering.RenderMode) + { + case RenderMode.Opaque: + gltfMaterial.alphaMode = "OPAQUE"; + dst.TransparentWithZWrite = false; + gltfMaterial.alphaCutoff = 0.5f; + dst.RenderQueueOffsetNumber = 0; + break; + case RenderMode.Cutout: + gltfMaterial.alphaMode = "MASK"; + dst.TransparentWithZWrite = false; + gltfMaterial.alphaCutoff = mtoon.Definition.Color.CutoutThresholdValue; + dst.RenderQueueOffsetNumber = 0; + break; + case RenderMode.Transparent: + gltfMaterial.alphaMode = "BLEND"; + dst.TransparentWithZWrite = false; + gltfMaterial.alphaCutoff = 0.5f; + dst.RenderQueueOffsetNumber = Mathf.Clamp(transparentRenderQueueMap[mtoon.Definition.Rendering.RenderQueueOffsetNumber], -9, 0); + break; + case RenderMode.TransparentWithZWrite: + gltfMaterial.alphaMode = "BLEND"; + dst.TransparentWithZWrite = true; + gltfMaterial.alphaCutoff = 0.5f; + dst.RenderQueueOffsetNumber = Mathf.Clamp(transparentZWriteRenderQueueMap[mtoon.Definition.Rendering.RenderQueueOffsetNumber], 0, +9); + break; + default: + throw new ArgumentOutOfRangeException(); + } + switch (mtoon.Definition.Rendering.CullMode) + { + case MToon.CullMode.Back: + gltfMaterial.doubleSided = false; + break; + case MToon.CullMode.Off: + gltfMaterial.doubleSided = true; + break; + case MToon.CullMode.Front: + // GLTF not support + gltfMaterial.doubleSided = true; + break; + default: + throw new NotImplementedException(); + } + + // Lighting + gltfMaterial.pbrMetallicRoughness.baseColorFactor = mtoon.Definition.Color.LitColor.ToFloat4(ColorSpace.sRGB, ColorSpace.Linear); + if (mtoon.TextureIndexMap.MainTex.HasValue) + { + gltfMaterial.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo + { + index = mtoon.TextureIndexMap.MainTex.Value + }; + if (textureScale.HasValue && textureOffset.HasValue) + { + Vrm10MaterialExportUtils.ExportTextureTransform( + gltfMaterial.pbrMetallicRoughness.baseColorTexture, + textureScale.Value, + textureOffset.Value + ); + } + } + + dst.ShadeColorFactor = mtoon.Definition.Color.ShadeColor.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear); + if (mtoon.TextureIndexMap.ShadeTexture.HasValue) + { + dst.ShadeMultiplyTexture = new TextureInfo + { + Index = mtoon.TextureIndexMap.ShadeTexture.Value + }; + if (textureScale.HasValue && textureOffset.HasValue) + { + Vrm10MaterialExportUtils.ExportTextureTransform( + dst.ShadeMultiplyTexture, + textureScale.Value, + textureOffset.Value + ); + } + } + + // NOTE: DESTRUCTIVE MIGRATION + // Lit Texture が存在するが Shade Texture が存在しないとき、 Lit Texture を Shade Texture に設定する. + // これは破壊的マイグレーションだが、以下の MToon 0.x の状況により、問題が起きるユーザが多いためマイグレーションする. + // - MToon 0.x は 2 枚メインテクスチャを設定するのが正しい状態であるという周知の不足 + // - MToon 0.x は Global Illumination の実装不備で、Shade Texture を設定しなくてもそれなりに表示できてしまっていた + if (mtoon.TextureIndexMap.MainTex.HasValue && !mtoon.TextureIndexMap.ShadeTexture.HasValue) + { + dst.ShadeMultiplyTexture = new TextureInfo + { + Index = mtoon.TextureIndexMap.MainTex.Value + }; + if (textureScale.HasValue && textureOffset.HasValue) + { + Vrm10MaterialExportUtils.ExportTextureTransform( + dst.ShadeMultiplyTexture, + textureScale.Value, + textureOffset.Value + ); + } + } + + if (mtoon.TextureIndexMap.BumpMap.HasValue) + { + gltfMaterial.normalTexture = new glTFMaterialNormalTextureInfo + { + index = mtoon.TextureIndexMap.BumpMap.Value, + scale = mtoon.Definition.Lighting.Normal.NormalScaleValue + }; + if (textureScale.HasValue && textureOffset.HasValue) + { + Vrm10MaterialExportUtils.ExportTextureTransform( + gltfMaterial.normalTexture, + textureScale.Value, + textureOffset.Value + ); + } + } + + dst.ShadingShiftFactor = MToon10Migrator.MigrateToShadingShift( + mtoon.Definition.Lighting.LitAndShadeMixing.ShadingToonyValue, + mtoon.Definition.Lighting.LitAndShadeMixing.ShadingShiftValue + ); + + dst.ShadingToonyFactor = MToon10Migrator.MigrateToShadingToony( + mtoon.Definition.Lighting.LitAndShadeMixing.ShadingToonyValue, + mtoon.Definition.Lighting.LitAndShadeMixing.ShadingShiftValue + ); + + // GI + dst.GiEqualizationFactor = MToon10Migrator.MigrateToGiEqualization(mtoon.Definition.Lighting.LightingInfluence.GiIntensityValue); + + // Emission + gltfMaterial.emissiveFactor = mtoon.Definition.Emission.EmissionColor.ToFloat3(ColorSpace.Linear, ColorSpace.Linear); + if (mtoon.TextureIndexMap.EmissionMap.HasValue) + { + gltfMaterial.emissiveTexture = new glTFMaterialEmissiveTextureInfo + { + index = mtoon.TextureIndexMap.EmissionMap.Value + }; + if (textureScale.HasValue && textureOffset.HasValue) + { + Vrm10MaterialExportUtils.ExportTextureTransform( + gltfMaterial.emissiveTexture, + textureScale.Value, + textureOffset.Value + ); + } + } + + // Rim Lighting + if (mtoon.TextureIndexMap.SphereAdd.HasValue) + { + // NOTE: MatCap behaviour will change in VRM 1.0. + // Texture transform is not required. + dst.MatcapTexture = new TextureInfo + { + Index = mtoon.TextureIndexMap.SphereAdd.Value + }; + dst.MatcapFactor = new [] { 1f, 1f, 1f }; + } + else + { + dst.MatcapFactor = new[] { 0f, 0f, 0f }; + } + dst.ParametricRimColorFactor = mtoon.Definition.Rim.RimColor.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear); + dst.ParametricRimFresnelPowerFactor = mtoon.Definition.Rim.RimFresnelPowerValue; + dst.ParametricRimLiftFactor = mtoon.Definition.Rim.RimLiftValue; + if (mtoon.TextureIndexMap.RimTexture.HasValue) + { + dst.RimMultiplyTexture = new TextureInfo + { + Index = mtoon.TextureIndexMap.RimTexture.Value + }; + if (textureScale.HasValue && textureOffset.HasValue) + { + Vrm10MaterialExportUtils.ExportTextureTransform( + dst.RimMultiplyTexture, + textureScale.Value, + textureOffset.Value + ); + } + } + // NOTE: DESTRUCTIVE MIGRATION + // Rim Lighting behaviour will be merged with MatCap in VRM 1.0. + // So, RimLightingMixFactor set to 1.0, because it is safe appearance. + dst.RimLightingMixFactor = 1.0f; + + // Outline + const float centimeterToMeter = 0.01f; + const float oneHundredth = 0.01f; + switch (mtoon.Definition.Outline.OutlineWidthMode) + { + case OutlineWidthMode.None: + dst.OutlineWidthMode = UniGLTF.Extensions.VRMC_materials_mtoon.OutlineWidthMode.none; + dst.OutlineWidthFactor = null; + break; + case OutlineWidthMode.WorldCoordinates: + dst.OutlineWidthMode = UniGLTF.Extensions.VRMC_materials_mtoon.OutlineWidthMode.worldCoordinates; + dst.OutlineWidthFactor = mtoon.Definition.Outline.OutlineWidthValue * centimeterToMeter; + break; + case OutlineWidthMode.ScreenCoordinates: + dst.OutlineWidthMode = UniGLTF.Extensions.VRMC_materials_mtoon.OutlineWidthMode.screenCoordinates; + // NOTE: 従来は、縦幅の半分を 100% としたときの % の値だった。 + // 1.0 では縦幅を 1 としたときの値とするので、 1/200 する。 + dst.OutlineWidthFactor = mtoon.Definition.Outline.OutlineWidthValue * oneHundredth * 0.5f; + break; + default: + throw new ArgumentOutOfRangeException($"OutlineWidthMode: {(int)mtoon.Definition.Outline.OutlineWidthMode}"); + } + if (mtoon.TextureIndexMap.OutlineWidthTexture.HasValue) + { + dst.OutlineWidthMultiplyTexture = new TextureInfo + { + Index = mtoon.TextureIndexMap.OutlineWidthTexture.Value + }; + if (textureScale.HasValue && textureOffset.HasValue) + { + Vrm10MaterialExportUtils.ExportTextureTransform( + dst.OutlineWidthMultiplyTexture, + textureScale.Value, + textureOffset.Value + ); + } + } + dst.OutlineColorFactor = mtoon.Definition.Outline.OutlineColor.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear); + switch (mtoon.Definition.Outline.OutlineColorMode) + { + case OutlineColorMode.FixedColor: + dst.OutlineLightingMixFactor = 0.0f; + break; + case OutlineColorMode.MixedLighting: + dst.OutlineLightingMixFactor = mtoon.Definition.Outline.OutlineLightingMixValue; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + // UV Animation + if (mtoon.TextureIndexMap.UvAnimMaskTexture.HasValue) + { + dst.UvAnimationMaskTexture = new TextureInfo + { + Index = mtoon.TextureIndexMap.UvAnimMaskTexture.Value + }; + if (textureScale.HasValue && textureOffset.HasValue) + { + Vrm10MaterialExportUtils.ExportTextureTransform( + dst.UvAnimationMaskTexture, + textureScale.Value, + textureOffset.Value + ); + } + } + dst.UvAnimationRotationSpeedFactor = mtoon.Definition.TextureOption.UvAnimationRotationSpeedValue; + dst.UvAnimationScrollXSpeedFactor = mtoon.Definition.TextureOption.UvAnimationScrollXSpeedValue; + const float invertY = -1f; + dst.UvAnimationScrollYSpeedFactor = mtoon.Definition.TextureOption.UvAnimationScrollYSpeedValue * invertY; + + // Export + UniGLTF.Extensions.VRMC_materials_mtoon.GltfSerializer.SerializeTo(ref gltfMaterial.extensions, dst); + + if (!gltf.extensionsUsed.Contains(UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon.ExtensionName)) + { + gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon.ExtensionName); + } + + if (!gltf.extensionsUsed.Contains(glTF_KHR_texture_transform.ExtensionName)) + { + gltf.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName); + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMToonMaterial.cs.meta b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMToonMaterial.cs.meta new file mode 100644 index 000000000..10f7f4431 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMToonMaterial.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e48d262d503ddfd4b86aeef6512697eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMaterialUtil.cs b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMaterialUtil.cs new file mode 100644 index 000000000..91d87dbc2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMaterialUtil.cs @@ -0,0 +1,119 @@ +using System; +using System.Linq; +using UniGLTF; +using UniJSON; +using UnityEngine; + +namespace UniVRM10 +{ + internal static class MigrationMaterialUtil + { + private const string ShaderNameKey = "shader"; + private const string VectorPropertiesKey = "vectorProperties"; + private const string FloatPropertiesKey = "floatProperties"; + private const string TexturePropertiesKey = "textureProperties"; + private const string MainTexKey = "_MainTex"; + private const string ColorKey = "_Color"; + private const string CutoffKey = "_Cutoff"; + + public static string GetShaderName(JsonNode vrm0XMaterial) + { + try + { + return vrm0XMaterial[ShaderNameKey].GetString(); + } + catch (Exception) + { + Debug.LogWarning($"Migration Warning: ShaderName fallback default."); + return string.Empty; + } + } + + public static float[] GetBaseColorFactor(JsonNode vrm0XMaterial) + { + try + { + var factor = vrm0XMaterial[VectorPropertiesKey][ColorKey]; + if (!factor.IsArray() || factor.GetArrayCount() != 4) + { + throw new Exception("not float4"); + } + return factor.ArrayItems().Select(x => x.GetSingle()).ToArray(); + } + catch (Exception) + { + Debug.LogWarning($"Migration Warning: BaseColorFactor fallback default."); + return new float[] {1, 1, 1, 1}; + } + } + + public static glTFMaterialBaseColorTextureInfo GetBaseColorTexture(JsonNode vrm0XMaterial) + { + try + { + var textureInfo = new glTFMaterialBaseColorTextureInfo + { + index = vrm0XMaterial[TexturePropertiesKey][MainTexKey].GetInt32(), + }; + var os = GetBaseColorTextureOffsetScale(vrm0XMaterial); + glTF_KHR_texture_transform.Serialize(textureInfo, (os.offsetX, os.offsetY), (os.scaleX, os.scaleY)); + return textureInfo; + } + catch (Exception) + { + Debug.LogWarning($"Migration Warning: BaseColorTexture fallback default."); + return null; + } + } + + private static (float offsetX, float offsetY, float scaleX, float scaleY) GetBaseColorTextureOffsetScale(JsonNode vrm0XMaterial) + { + try + { + var unityOffsetScale = vrm0XMaterial[VectorPropertiesKey][MainTexKey]; + if (!unityOffsetScale.IsArray() || unityOffsetScale.GetArrayCount() != 4) + { + throw new Exception("not float4"); + } + + var unityOffsetX = unityOffsetScale[0].GetSingle(); + var unityOffsetY = unityOffsetScale[1].GetSingle(); + var unityScaleX = unityOffsetScale[2].GetSingle(); + var unityScaleY = unityOffsetScale[3].GetSingle(); + + return (unityOffsetX, 1.0f - unityOffsetY - unityScaleY, unityScaleX, unityScaleY); + } + catch (Exception) + { + Debug.LogWarning($"Migration Warning: BaseColorTextureScaleOffset fallback default."); + return (0, 0, 1, 1); + } + } + + public static float GetCutoff(JsonNode vrm0XMaterial) + { + try + { + return vrm0XMaterial[FloatPropertiesKey][CutoffKey].GetSingle(); + } + catch (Exception) + { + Debug.LogWarning($"Migration Warning: Cutoff fallback default."); + return 0.5f; + } + } + + public static int? GetRenderQueue(JsonNode vrm0XMaterial) + { + try + { + return vrm0XMaterial["renderQueue"].GetInt32(); + } + catch (Exception) + { + Debug.LogWarning($"Migration Warning: RenderQueue fallback default."); + return default; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMaterialUtil.cs.meta b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMaterialUtil.cs.meta new file mode 100644 index 000000000..7587a12df --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationMaterialUtil.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e9d2327bd1774f949440b833af321d69 +timeCreated: 1635423551 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationPbrMaterial.cs b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationPbrMaterial.cs new file mode 100644 index 000000000..350eec06f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationPbrMaterial.cs @@ -0,0 +1,100 @@ +using System; +using System.Linq; +using UniGLTF; +using UniJSON; +using UnityEngine; +using ColorSpace = VRMShaders.ColorSpace; + +namespace UniVRM10 +{ + internal static class MigrationPbrMaterial + { + private const string UsingGltfMaterialKeywordInVrmExtension = "VRM_USE_GLTFSHADER"; + private const string ExporterVersionKey = "exporterVersion"; + + /// + /// vanilla の gltf material を対象とする. + /// KHR_materials_unlit 拡張や VRM.materialProperties で MToon を対象とするマテリアルは処理してはいけない。 + /// + public static void Migrate(glTF gltf, JsonNode vrm0XExtension) + { + var needMigrationRoughnessTextureValueSquared = false; + var needMigrationEmissiveFactorGamma = false; + if (vrm0XExtension.TryGet(ExporterVersionKey, out var vrm0XVersionStringNode)) + { + var vrm0XVersionString = vrm0XVersionStringNode.GetString(); + if (Vrm0XVersion.ParseVersion(vrm0XVersionString, out var vrm0XVersion)) + { + needMigrationRoughnessTextureValueSquared = Vrm0XVersion.IsNewer( + new Vrm0XVersion.Version + { + Major = 0, + Minor = 69, + Patch = 0, + Pre = "", + }, + vrm0XVersion + ); + needMigrationEmissiveFactorGamma = Vrm0XVersion.IsNewer( + new Vrm0XVersion.Version + { + Major = 0, + Minor = 107, + Patch = 0, + Pre = "", + }, + vrm0XVersion + ); + } + } + for (var idx = 0; idx < gltf.materials.Count; ++idx) + { + MigrateMaterial(gltf, vrm0XExtension, idx, needMigrationRoughnessTextureValueSquared, needMigrationEmissiveFactorGamma); + } + } + + private static void MigrateMaterial(glTF gltf, JsonNode vrm0XExtension, int idx, bool needMigrationRoughnessTextureValueSquared, bool needMigrationEmissiveFactorGamma) + { + var src = gltf.materials[idx]; + var vrm0XMaterial = vrm0XExtension["materialProperties"][idx]; + + // NOTE: ignore MToon + if (MigrationMaterialUtil.GetShaderName(vrm0XMaterial) != UsingGltfMaterialKeywordInVrmExtension) return; + // NOTE: ignore Unlit + if (glTF_KHR_materials_unlit.IsEnable(src)) return; + + if (needMigrationRoughnessTextureValueSquared) + { + // NOTE: 非常に実装がめんどくさい、かつ刺さるシチュエーションがかなり少ないので放置. + } + + if (needMigrationEmissiveFactorGamma && src.emissiveFactor != null && src.emissiveFactor.Length == 3) + { + var emissiveFactor = new Color(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]); + if (UniGLTF.glTF_KHR_materials_emissive_strength.TryGet(src.extensions, out var emissiveStrength)) + { + emissiveFactor *= emissiveStrength.emissiveStrength; + } + else if (UniGLTF.Extensions.VRMC_materials_hdr_emissiveMultiplier.GltfDeserializer.TryGet(src.extensions, out var ex)) + { + if (ex.EmissiveMultiplier != null) + { + emissiveFactor *= ex.EmissiveMultiplier.Value; + } + } + // NOTE: 新しい emissive_strength 拡張を書き込むため、拡張をまっさらにする + var extensionsExport = new glTFExtensionExport(); + src.extensions = extensionsExport; + + var linearEmissiveFactor = emissiveFactor.linear; + if (linearEmissiveFactor.maxColorComponent > 1) + { + var maxColorComponent = linearEmissiveFactor.maxColorComponent; + linearEmissiveFactor /= maxColorComponent; + UniGLTF.glTF_KHR_materials_emissive_strength.Serialize(ref src.extensions, maxColorComponent); + } + src.emissiveFactor = linearEmissiveFactor.ToFloat3(ColorSpace.Linear, ColorSpace.Linear); + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationPbrMaterial.cs.meta b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationPbrMaterial.cs.meta new file mode 100644 index 000000000..ecfc5507b --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationPbrMaterial.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ec22998490984df4a7f04d03174fc3e0 +timeCreated: 1667803769 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationUnlitTransparentZWriteMaterial.cs b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationUnlitTransparentZWriteMaterial.cs new file mode 100644 index 000000000..b0d2c809c --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationUnlitTransparentZWriteMaterial.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using UniGLTF; +using UniGLTF.Extensions.VRMC_materials_mtoon; +using UniJSON; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Migration Target: VRM file with "VRM/UnlitTransparentZWrite" material exported with UniVRM v0.43 or lower. + /// + /// 過去の UniVRM の "VRM/UnlitTransparentZWrite" シェーダをマイグレーションする. + /// 他の Unlit シェーダと違い、VRMC_materials_mtoon を用いてマイグレーションする. + /// + internal static class MigrationUnlitTransparentZWriteMaterial + { + private const int MaxRenderQueueOffset = 9; // NOTE: vrm-1.0 spec + + private const string Unity0XShaderName = "VRM/UnlitTransparentZWrite"; + private const int Unity0XDefaultRenderQueue = 2501; + + public static bool Migrate(glTF gltf, IReadOnlyList vrm0XMaterials) + { + var anyMigrated = false; + var mapper = GetRenderQueueMapper(vrm0XMaterials); + + for (var materialIdx = 0; materialIdx < gltf.materials.Count; ++materialIdx) + { + try + { + var newMaterial = Migrate(vrm0XMaterials[materialIdx], gltf.materials[materialIdx].name, mapper); + if (newMaterial != null) + { + // NOTE: UnlitTransparentZWrite の場合は、名前を引き継いで、glTFMaterial を上書きする. + gltf.materials[materialIdx] = newMaterial; + anyMigrated = true; + } + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + + return anyMigrated; + } + + private static Dictionary GetRenderQueueMapper(IReadOnlyList vrm0XMaterials) + { + try + { + var renderQueueSet = new SortedSet(); + foreach (var vrm0XMaterial in vrm0XMaterials) + { + var renderQueue = MigrationMaterialUtil.GetRenderQueue(vrm0XMaterial); + if (renderQueue.HasValue && renderQueue.Value != -1) + { + renderQueueSet.Add(renderQueue.Value); + } + else + { + renderQueueSet.Add(Unity0XDefaultRenderQueue); + } + } + + var mapper = new Dictionary(); + var currentQueueOffset = 0; + foreach (var queue in renderQueueSet) + { + mapper.Add(queue, currentQueueOffset); + currentQueueOffset = Mathf.Min(currentQueueOffset + 1, MaxRenderQueueOffset); + } + + return mapper; + } + catch (Exception ex) + { + Debug.LogException(ex); + return new Dictionary(); + } + } + + private static glTFMaterial Migrate(JsonNode vrm0XMaterial, string materialName, Dictionary renderQueueMapper) + { + try + { + if (MigrationMaterialUtil.GetShaderName(vrm0XMaterial) != Unity0XShaderName) + { + return null; + } + + var baseColorFactor = MigrationMaterialUtil.GetBaseColorFactor(vrm0XMaterial); + var baseColorTexture = MigrationMaterialUtil.GetBaseColorTexture(vrm0XMaterial); + var emissiveTexture = new glTFMaterialEmissiveTextureInfo + { + index = baseColorTexture.index, + extensions = baseColorTexture.extensions, + }; + var renderQueue = MigrationMaterialUtil.GetRenderQueue(vrm0XMaterial) ?? Unity0XDefaultRenderQueue; + var renderQueueOffset = renderQueueMapper.ContainsKey(renderQueue) ? renderQueueMapper[renderQueue] : 0; + + var mtoonMaterial = new glTFMaterial + { + name = materialName, + extensions = new glTFExtensionExport().Add( + glTF_KHR_materials_unlit.ExtensionName, + new ArraySegment(glTF_KHR_materials_unlit.Raw) + ), + pbrMetallicRoughness = new glTFPbrMetallicRoughness + { + baseColorFactor = new[] { 0f, 0f, 0f, baseColorFactor[3] }, // black + _Color.a + baseColorTexture = baseColorTexture, // _MainTex + metallicFactor = 0f, + roughnessFactor = 1f, + }, + alphaMode = "BLEND", + alphaCutoff = 0.5f, + doubleSided = false, + emissiveFactor = new[] { baseColorFactor[0], baseColorFactor[1], baseColorFactor[2] }, // _Color.rgb + emissiveTexture = emissiveTexture, + }; + + var mtoon10 = new VRMC_materials_mtoon + { + SpecVersion = Vrm10Exporter.MTOON_SPEC_VERSION, + TransparentWithZWrite = true, // transparent with zWrite + RenderQueueOffsetNumber = renderQueueOffset, + ShadeColorFactor = new[] { 0f, 0f, 0f }, // black + OutlineWidthMode = OutlineWidthMode.none // disable outline + }; + UniGLTF.Extensions.VRMC_materials_mtoon.GltfSerializer.SerializeTo(ref mtoonMaterial.extensions, + mtoon10); + + return mtoonMaterial; + } + catch (Exception) + { + Debug.LogWarning($"Migration failed in VRM/UnlitTransparentZWrite material: {materialName}"); + return null; + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/MigrationUnlitTransparentZWriteMaterial.cs.meta b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationUnlitTransparentZWriteMaterial.cs.meta new file mode 100644 index 000000000..a2f7a6613 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/MigrationUnlitTransparentZWriteMaterial.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 281c0ecbae8e489db4c86a553636ae44 +timeCreated: 1635426676 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonTextureIndexMap.cs b/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonTextureIndexMap.cs new file mode 100644 index 000000000..36c6d4740 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonTextureIndexMap.cs @@ -0,0 +1,18 @@ +namespace UniVRM10 +{ + internal struct Vrm0XMToonTextureIndexMap + { + // glTF + public int? MainTex; + public int? BumpMap; + public int? EmissionMap; + // VRMC_materials_mtoon + public int? ShadeTexture; + public int? ReceiveShadowTexture; + public int? ShadingGradeTexture; + public int? RimTexture; + public int? SphereAdd; + public int? OutlineWidthTexture; + public int? UvAnimMaskTexture; + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonTextureIndexMap.cs.meta b/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonTextureIndexMap.cs.meta new file mode 100644 index 000000000..7972c38b2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonTextureIndexMap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 50d80cf68f2f7c1488b02f62a96782ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonValue.cs b/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonValue.cs new file mode 100644 index 000000000..6a68bc5ce --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonValue.cs @@ -0,0 +1,250 @@ +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UniJSON; +using UnityEngine; +using VRMShaders; +using ColorSpace = VRMShaders.ColorSpace; + +namespace UniVRM10 +{ + /// + /// vrm-0 の json から vrm-0 の MToon.Definition を生成する。 + /// + /// Texture2D は作成せずに、直接 index を操作する。 + /// + /// + internal sealed class Vrm0XMToonValue + { + public MToon.MToonDefinition Definition { get; } + public Dictionary TextureOffsetScales { get; } + public Vrm0XMToonTextureIndexMap TextureIndexMap { get; } + + public Vrm0XMToonValue(JsonNode vrmMaterial) + { + var definition = new MToon.MToonDefinition + { + Color = new MToon.ColorDefinition { }, + Lighting = new MToon.LightingDefinition + { + LightingInfluence = new MToon.LightingInfluenceDefinition { }, + LitAndShadeMixing = new MToon.LitAndShadeMixingDefinition { }, + Normal = new MToon.NormalDefinition { } + }, + Emission = new MToon.EmissionDefinition { }, + MatCap = new MToon.MatCapDefinition { }, + Meta = new MToon.MetaDefinition { }, + Outline = new MToon.OutlineDefinition { }, + Rendering = new MToon.RenderingDefinition { }, + Rim = new MToon.RimDefinition { }, + TextureOption = new MToon.TextureUvCoordsDefinition { } + }; + + var offsetScale = new Dictionary(); + foreach (var kv in vrmMaterial["vectorProperties"].ObjectItems()) + { + var key = kv.Key.GetString(); + switch (key) + { + // Lighting + case "_Color": + definition.Color.LitColor = ToColor(kv.Value, ColorSpace.sRGB, ColorSpace.sRGB); + break; + case "_ShadeColor": + definition.Color.ShadeColor = ToColor(kv.Value, ColorSpace.sRGB, ColorSpace.sRGB); + break; + + // Emission + case "_EmissionColor": + definition.Emission.EmissionColor = ToColor(kv.Value, ColorSpace.Linear, ColorSpace.Linear); + break; + + // Rim Lighting + case "_RimColor": + definition.Rim.RimColor = ToColor(kv.Value, ColorSpace.sRGB, ColorSpace.sRGB); + break; + + // Outline + case "_OutlineColor": + definition.Outline.OutlineColor = ToColor(kv.Value, ColorSpace.sRGB, ColorSpace.sRGB); + break; + + // Texture ST + case "_MainTex": + case "_ShadeTexture": + case "_BumpMap": + case "_EmissionMap": + case "_OutlineWidthTexture": + case "_ReceiveShadowTexture": + case "_RimTexture": + case "_ShadingGradeTexture": + case "_SphereAdd": + case "_UvAnimMaskTexture": + // scale, offset + offsetScale.Add(key, ToFloat4(kv.Value)); + break; + + default: + if (Symbols.VRM_DEVELOP) + { + Debug.LogWarning($"vectorProperties: {kv.Key}: {kv.Value}"); + } + break; + } + } + + foreach (var kv in vrmMaterial["floatProperties"].ObjectItems()) + { + var value = kv.Value.GetSingle(); + switch (kv.Key.GetString()) + { + // Rendering + case "_BlendMode": + definition.Rendering.RenderMode = (MToon.RenderMode)(int)value; + break; + case "_CullMode": + definition.Rendering.CullMode = (MToon.CullMode)(int)value; + break; + case "_Cutoff": + definition.Color.CutoutThresholdValue = value; + break; + + // Lighting + case "_BumpScale": + definition.Lighting.Normal.NormalScaleValue = value; + break; + case "_LightColorAttenuation": + definition.Lighting.LightingInfluence.LightColorAttenuationValue = value; + break; + case "_ShadeShift": + definition.Lighting.LitAndShadeMixing.ShadingShiftValue = value; + break; + case "_ShadeToony": + definition.Lighting.LitAndShadeMixing.ShadingToonyValue = value; + break; + case "_ShadingGradeRate": + // Not supported + break; + case "_ReceiveShadowRate": + // Not supported + break; + + // GI + case "_IndirectLightIntensity": + definition.Lighting.LightingInfluence.GiIntensityValue = value; + break; + + // Rim Lighting + case "_RimFresnelPower": + definition.Rim.RimFresnelPowerValue = value; + break; + case "_RimLift": + definition.Rim.RimLiftValue = value; + break; + case "_RimLightingMix": + definition.Rim.RimLightingMixValue = value; + break; + + // Outline + case "_OutlineColorMode": + definition.Outline.OutlineColorMode = (MToon.OutlineColorMode)value; + break; + case "_OutlineLightingMix": + definition.Outline.OutlineLightingMixValue = value; + break; + case "_OutlineScaledMaxDistance": + definition.Outline.OutlineScaledMaxDistanceValue = value; + break; + case "_OutlineWidth": + definition.Outline.OutlineWidthValue = value; + break; + case "_OutlineWidthMode": + if (value > 2) + { + value = 0; + } + definition.Outline.OutlineWidthMode = (MToon.OutlineWidthMode)value; + break; + + // UV Animation + case "_UvAnimRotation": + definition.TextureOption.UvAnimationRotationSpeedValue = value; + break; + + case "_UvAnimScrollX": + definition.TextureOption.UvAnimationScrollXSpeedValue = value; + break; + + case "_UvAnimScrollY": + definition.TextureOption.UvAnimationScrollYSpeedValue = value; + break; + + case "_OutlineCullMode": + case "_ZWrite": + case "_DstBlend": + case "_SrcBlend": + case "_MToonVersion": + case "_DebugMode": + // Auto generated + break; + + default: + if (Symbols.VRM_DEVELOP) + { + Debug.LogWarning($"floatProperties: {kv.Key} is unknown"); + } + break; + } + } + + var map = new Vrm0XMToonTextureIndexMap(); + + foreach (var kv in vrmMaterial["textureProperties"].ObjectItems()) + { + var index = kv.Value.GetInt32(); + switch (kv.Key.GetString()) + { + // Lighting + case "_MainTex": map.MainTex = index; break; + case "_ShadeTexture": map.ShadeTexture = index; break; + case "_BumpMap": map.BumpMap = index; break; + case "_ReceiveShadowTexture": map.ReceiveShadowTexture = index; break; + case "_ShadingGradeTexture": map.ShadingGradeTexture = index; break; + // Emission + case "_EmissionMap": map.EmissionMap = index; break; + // Rim Lighting + case "_RimTexture": map.RimTexture = index; break; + case "_SphereAdd": map.SphereAdd = index; break; + // Outline + case "_OutlineWidthTexture": map.OutlineWidthTexture = index; break; + // UV Animation + case "_UvAnimMaskTexture": map.UvAnimMaskTexture = index; break; + default: + if (Symbols.VRM_DEVELOP) + { + Debug.LogWarning($"textureProperties: {kv.Key} is unknown"); + } + break; + } + } + + definition.Rendering.RenderQueueOffsetNumber = + vrmMaterial["renderQueue"].GetInt32() - + MToon.Utils.GetRenderQueueRequirement(definition.Rendering.RenderMode).DefaultValue; + + Definition = definition; + TextureOffsetScales = offsetScale; + TextureIndexMap = map; + } + + private static Color ToColor(JsonNode node, ColorSpace srcColorSpace, ColorSpace dstColorSpace) + { + return node.ArrayItems().Select(x => ListTreeNodeExtensions.GetSingle(x)).ToArray().ToColor4(srcColorSpace, dstColorSpace); + } + + private static float[] ToFloat4(JsonNode node) + { + return node.ArrayItems().Select(x => x.GetSingle()).ToArray(); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonValue.cs.meta b/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonValue.cs.meta new file mode 100644 index 000000000..cfcc79e55 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Materials/Vrm0XMToonValue.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 83b04861c6ae4b64b724b122b261f4da +timeCreated: 1635423935 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/MeshUpdater.cs b/Assets/External/VRM10/Runtime/Migration/MeshUpdater.cs new file mode 100644 index 000000000..50aef5cb9 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MeshUpdater.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using UniGLTF; +using Unity.Collections; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// 座標系を変換した Model により、Mesh, Node, BindMatrices を更新する。 + /// + /// * gltf.images の参照する bufferView + /// * gltf.meshes の参照する index, VERTEX, MorphTarget の accessor, bufferView + /// * gltf.nodes の参照する skin の inverseBindMatrices 向けの accessor, bufferView + /// + /// を詰め込みなすことで bin を再構築する + /// + class MeshUpdater + { + GltfData _data; + ArrayByteBuffer _buffer; + List _bufferViews = new List(); + List _accessors = new List(); + + MeshUpdater(GltfData data) + { + _data = data; + _buffer = new ArrayByteBuffer(new byte[data.Bin.Length]); + } + + /// + /// data を model で更新する + /// + /// 更新前のオリジナル + /// 座標系の変換などの操作済み + /// + public static (glTF, ArraySegment) Execute(GltfData data, VrmLib.Model model) + { + return new MeshUpdater(data).Update(model); + } + + int AddBuffer(NativeArray bytes, glBufferTarget target) + { + var bufferView = _buffer.Extend(bytes, target); + var index = _bufferViews.Count; + _bufferViews.Add(bufferView); + + // padding for 4byte alignment + var mod = bytes.Length % 4; + if (mod != 0) + { + _buffer.Extend(new ArraySegment(new byte[4 - mod])); + } + + return index; + } + + static (float[], float[]) GetMinMax(NativeArray v) + { + var minX = float.PositiveInfinity; + var minY = float.PositiveInfinity; + var minZ = float.PositiveInfinity; + var maxX = float.NegativeInfinity; + var maxY = float.NegativeInfinity; + var maxZ = float.NegativeInfinity; + for (int i = 0; i < v.Length; ++i) + { + if (v[i].x < minX) minX = v[i].x; + if (v[i].y < minY) minY = v[i].y; + if (v[i].z < minZ) minZ = v[i].z; + if (v[i].x > maxX) maxX = v[i].x; + if (v[i].y > maxY) maxY = v[i].y; + if (v[i].z > maxZ) maxZ = v[i].z; + } + return (new float[] { minX, minY, minZ }, new float[] { maxX, maxY, maxZ }); + } + + int AddAccessor(NativeArray span, glBufferTarget target, bool minMaxBounds) where T : struct + { + var bufferViewIndex = AddBuffer(span.Reinterpret(Marshal.SizeOf()), target); + var accessor = new glTFAccessor + { + bufferView = bufferViewIndex, + count = span.Length, + byteOffset = 0, + componentType = glTFExtensions.GetComponentType(), + type = glTFExtensions.GetAccessorType(), + }; + if (minMaxBounds) + { + if (span is NativeArray positions) + { + var (min, max) = GetMinMax(positions); + accessor.min = min; + accessor.max = max; + } + } + var index = _accessors.Count; + _accessors.Add(accessor); + return index; + } + + int? AddAccessor(BufferAccessor buffer, glBufferTarget target, bool minMaxBounds) where T : struct + { + if (buffer == null) + { + return default; + } + return AddAccessor(buffer.GetSpan(), target, minMaxBounds); + } + + struct MorphAccessor + { + public int? Position; + public int? Normal; + }; + + /// + /// bufferView, accessor を push することで bin を再構築する + /// + /// meshの右手左手変換結果 + /// + (glTF, ArraySegment) Update(VrmLib.Model model) + { + var gltf = _data.GLTF; + + // copy images + foreach (var image in gltf.images) + { + var bytes = _data.GetBytesFromBufferView(image.bufferView); + image.bufferView = AddBuffer(bytes, default); + } + + // copy mesh + if (model.MeshGroups.All(x => x.Meshes.Count == 1)) + { + UpdateSharedVertexBuffer(model); + } + else + { + UpdateDividedVertexBuffer(model); + } + + // update nodes and remove unused skin + var skins = gltf.skins.ToArray(); + gltf.skins.Clear(); + foreach (var (gltfNode, node) in Enumerable.Zip(gltf.nodes, model.Nodes, (l, r) => (l, r))) + { + gltfNode.translation = node.LocalTranslation.ToFloat3(); + gltfNode.rotation = node.LocalRotation.ToFloat4(); + gltfNode.scale = node.LocalScaling.ToFloat3(); + + // remove matrix properties because TRS is used + gltfNode.matrix = null; + + if (gltfNode.mesh >= 0) + { + if (gltfNode.skin >= 0) + { + // + // mesh with skin + // only this case, skin is enable + // [SkinnedMeshRenderer] + // + var gltfSkin = skins[gltfNode.skin]; + // get or create + var skinIndex = gltf.skins.IndexOf(gltfSkin); + if (skinIndex == -1) + { + skinIndex = gltf.skins.Count; + gltfSkin.inverseBindMatrices = AddAccessor(node.MeshGroup.Skin.InverseMatrices.GetSpan(), default, false); + gltf.skins.Add(gltfSkin); + } + else + { + // multi nodes sharing a same skin may be error ? + // edge case. + } + // update + gltfNode.skin = skinIndex; + } + else + { + // + // mesh without skin + // [MeshRenderer] + // + } + } + else + { + if (gltfNode.skin >= 0) + { + // + // no mesh but skin + // fix error + // + gltfNode.skin = -1; + } + else + { + // + // no mesh no skin + // + } + } + } + + // replace + gltf.buffers[0].byteLength = _buffer.Bytes.Count; + gltf.bufferViews = _bufferViews; + gltf.accessors = _accessors; + + return (gltf, _buffer.Bytes); + + } + + /// + /// model はひとつのノードに複数の mesh をぶら下げることができる(meshGroup) + /// gltf.meshes[i].primitives[j] <-> model.meshGroups[i].meshes[0].submeshes[j] + /// + void UpdateSharedVertexBuffer(VrmLib.Model model) + { + var gltf = _data.GLTF; + + // gltfMeshes[i] <=> MeshGroups[i].Meshes[0] ( MeshGroups[i].Meshes.Count == 1 ) + foreach (var (gltfMesh, mesh) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r.Meshes[0]))) + { + NativeArray indices; + switch (mesh.IndexBuffer.Stride) + { + case 1: + { + // byte + var byte_indices = mesh.IndexBuffer.GetSpan(); + indices = _data.NativeArrayManager.Convert(byte_indices, (byte x) => (uint)x); + break; + } + + case 2: + { + // ushort + var ushort_indices = mesh.IndexBuffer.GetSpan(); + indices = _data.NativeArrayManager.Convert(ushort_indices, (ushort x) => (uint)x); + break; + } + + case 4: + { + // uint + indices = mesh.IndexBuffer.GetSpan(); + break; + } + + default: + throw new NotImplementedException(); + } + var position = AddAccessor(mesh.VertexBuffer.Positions, glBufferTarget.ARRAY_BUFFER, true); + var normal = AddAccessor(mesh.VertexBuffer.Normals, glBufferTarget.ARRAY_BUFFER, false); + var uv = AddAccessor(mesh.VertexBuffer.TexCoords, glBufferTarget.ARRAY_BUFFER, false); + var weights = AddAccessor(mesh.VertexBuffer.Weights, glBufferTarget.ARRAY_BUFFER, false); + var joints = AddAccessor(mesh.VertexBuffer.Joints, glBufferTarget.ARRAY_BUFFER, false); + var color = AddAccessor(mesh.VertexBuffer.Colors, glBufferTarget.ARRAY_BUFFER, false); + + var morphTargets = new MorphAccessor[] { }; + if (mesh.MorphTargets != null) + { + morphTargets = mesh.MorphTargets.Select(x => new MorphAccessor + { + Position = AddAccessor(x.VertexBuffer.Positions, glBufferTarget.ARRAY_BUFFER, true), + Normal = AddAccessor(x.VertexBuffer.Normals, glBufferTarget.ARRAY_BUFFER, false), + }).ToArray(); + } + + // gltfPrim[j] <=> mesh.Submeshes[j] + foreach (var (gltfPrim, submesh) in Enumerable.Zip(gltfMesh.primitives, mesh.Submeshes, (l, r) => (l, r))) + { + var subIndices = indices.GetSubArray(submesh.Offset, submesh.DrawCount); + gltfPrim.indices = AddAccessor(subIndices, glBufferTarget.ELEMENT_ARRAY_BUFFER, false); + gltfPrim.attributes.POSITION = position.Value; + gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる + gltfPrim.attributes.TANGENT = -1; + gltfPrim.attributes.COLOR_0 = color.GetValueOrDefault(-1); + gltfPrim.attributes.TEXCOORD_0 = uv.GetValueOrDefault(-1); // ありえる? + gltfPrim.attributes.TEXCOORD_1 = -1; + gltfPrim.attributes.WEIGHTS_0 = weights.GetValueOrDefault(-1); + gltfPrim.attributes.JOINTS_0 = joints.GetValueOrDefault(-1); + foreach (var (gltfMorph, morph) in Enumerable.Zip(gltfPrim.targets, morphTargets, (l, r) => (l, r))) + { + gltfMorph.POSITION = morph.Position.GetValueOrDefault(-1); + gltfMorph.NORMAL = morph.Normal.GetValueOrDefault(-1); + gltfMorph.TANGENT = -1; + } + } + } + } + + /// + /// model はひとつのノードに複数の mesh をぶら下げることができる(meshGroup) + /// gltf.meshes[i].primitives[j] <-> model.meshGroups[i].meshes[j].submeshes[0] + /// + void UpdateDividedVertexBuffer(VrmLib.Model model) + { + var gltf = _data.GLTF; + + // gltfMesh[i] <=> meshGroups[i] + foreach (var (gltfMesh, meshGroup) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r))) + { + // gltfPrimitives[j] <=> meshGroup.Meshes[j] (meshGroup.Meshes[j].Submeshes.Count==1) + foreach (var (gltfPrim, mesh) in Enumerable.Zip(gltfMesh.primitives, meshGroup.Meshes, (l, r) => (l, r))) + { + NativeArray indices; + switch (mesh.IndexBuffer.Stride) + { + case 1: + { + // byte + var byte_indices = mesh.IndexBuffer.GetSpan(); + indices = _data.NativeArrayManager.Convert(byte_indices, (byte x) => (uint)x); + break; + } + + case 2: + { + // ushort + var ushort_indices = mesh.IndexBuffer.GetSpan(); + indices = _data.NativeArrayManager.Convert(ushort_indices, (ushort x) => (uint)x); + break; + } + + case 4: + { + // uint + indices = mesh.IndexBuffer.GetSpan(); + break; + } + + default: + throw new NotImplementedException(); + } + + var position = AddAccessor(mesh.VertexBuffer.Positions, glBufferTarget.ARRAY_BUFFER, true); + var normal = AddAccessor(mesh.VertexBuffer.Normals, glBufferTarget.ARRAY_BUFFER, false); + var uv = AddAccessor(mesh.VertexBuffer.TexCoords, glBufferTarget.ARRAY_BUFFER, false); + var weights = AddAccessor(mesh.VertexBuffer.Weights, glBufferTarget.ARRAY_BUFFER, false); + var joints = AddAccessor(mesh.VertexBuffer.Joints, glBufferTarget.ARRAY_BUFFER, false); + var color = AddAccessor(mesh.VertexBuffer.Colors, glBufferTarget.ARRAY_BUFFER, false); + + var morphTargets = new MorphAccessor[] { }; + if (mesh.MorphTargets != null) + { + morphTargets = mesh.MorphTargets.Select(x => new MorphAccessor + { + Position = AddAccessor(x.VertexBuffer.Positions, glBufferTarget.ARRAY_BUFFER, true), + Normal = AddAccessor(x.VertexBuffer.Normals, glBufferTarget.ARRAY_BUFFER, false), + }).ToArray(); + } + + gltfPrim.indices = AddAccessor(indices, glBufferTarget.ELEMENT_ARRAY_BUFFER, false); + gltfPrim.attributes.POSITION = position.Value; + gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる + gltfPrim.attributes.TANGENT = -1; + gltfPrim.attributes.COLOR_0 = color.GetValueOrDefault(-1); + gltfPrim.attributes.TEXCOORD_0 = uv.GetValueOrDefault(-1); // ありえる? + gltfPrim.attributes.TEXCOORD_1 = -1; + gltfPrim.attributes.WEIGHTS_0 = weights.GetValueOrDefault(-1); + gltfPrim.attributes.JOINTS_0 = joints.GetValueOrDefault(-1); + foreach (var (gltfMorph, morph) in Enumerable.Zip(gltfPrim.targets, morphTargets, (l, r) => (l, r))) + { + gltfMorph.POSITION = morph.Position.GetValueOrDefault(-1); + gltfMorph.NORMAL = morph.Normal.GetValueOrDefault(-1); + gltfMorph.TANGENT = -1; + } + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MeshUpdater.cs.meta b/Assets/External/VRM10/Runtime/Migration/MeshUpdater.cs.meta new file mode 100644 index 000000000..1a0dd05c2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MeshUpdater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c49ea19813d8f214dbe789fd79f78b28 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationCheck.cs b/Assets/External/VRM10/Runtime/Migration/MigrationCheck.cs new file mode 100644 index 000000000..57153aff6 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationCheck.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using UniJSON; + +namespace UniVRM10 +{ + /// + /// for UnitTest + /// + internal static class MigrationCheck + { + #region for UnitTest + public class MigrationException : Exception + { + public MigrationException(string key, string value) : base($"{key}: {value}") + { + } + } + + public static void CheckBone(string bone, JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.HumanBone vrm1) + { + var vrm0NodeIndex = vrm0["node"].GetInt32(); + if (vrm0NodeIndex != vrm1.Node) + { + throw new Exception($"different {bone}: {vrm0NodeIndex} != {vrm1.Node}"); + } + } + + public static void CheckHumanoid(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Humanoid vrm1) + { + foreach (var humanoidBone in vrm0["humanBones"].ArrayItems()) + { + var boneType = humanoidBone["bone"].GetString(); + switch (boneType) + { + case "hips": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Hips); break; + case "leftUpperLeg": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftUpperLeg); break; + case "rightUpperLeg": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightUpperLeg); break; + case "leftLowerLeg": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLowerLeg); break; + case "rightLowerLeg": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLowerLeg); break; + case "leftFoot": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftFoot); break; + case "rightFoot": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightFoot); break; + case "spine": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Spine); break; + case "chest": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Chest); break; + case "neck": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Neck); break; + case "head": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Head); break; + case "leftShoulder": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftShoulder); break; + case "rightShoulder": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightShoulder); break; + case "leftUpperArm": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftUpperArm); break; + case "rightUpperArm": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightUpperArm); break; + case "leftLowerArm": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLowerArm); break; + case "rightLowerArm": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLowerArm); break; + case "leftHand": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftHand); break; + case "rightHand": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightHand); break; + case "leftToes": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftToes); break; + case "rightToes": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightToes); break; + case "leftEye": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftEye); break; + case "rightEye": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightEye); break; + case "jaw": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Jaw); break; + case "leftThumbMetacarpal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftThumbMetacarpal); break; + case "leftThumbProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftThumbProximal); break; + case "leftThumbDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftThumbDistal); break; + case "leftIndexProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftIndexProximal); break; + case "leftIndexIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftIndexIntermediate); break; + case "leftIndexDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftIndexDistal); break; + case "leftMiddleProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftMiddleProximal); break; + case "leftMiddleIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftMiddleIntermediate); break; + case "leftMiddleDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftMiddleDistal); break; + case "leftRingProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftRingProximal); break; + case "leftRingIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftRingIntermediate); break; + case "leftRingDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftRingDistal); break; + case "leftLittleProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLittleProximal); break; + case "leftLittleIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLittleIntermediate); break; + case "leftLittleDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLittleDistal); break; + case "rightThumbMetacarpal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightThumbMetacarpal); break; + case "rightThumbProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightThumbProximal); break; + case "rightThumbDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightThumbDistal); break; + case "rightIndexProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightIndexProximal); break; + case "rightIndexIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightIndexIntermediate); break; + case "rightIndexDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightIndexDistal); break; + case "rightMiddleProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightMiddleProximal); break; + case "rightMiddleIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightMiddleIntermediate); break; + case "rightMiddleDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightMiddleDistal); break; + case "rightRingProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightRingProximal); break; + case "rightRingIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightRingIntermediate); break; + case "rightRingDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightRingDistal); break; + case "rightLittleProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLittleProximal); break; + case "rightLittleIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLittleIntermediate); break; + case "rightLittleDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLittleDistal); break; + case "upperChest": CheckBone(boneType, humanoidBone, vrm1.HumanBones.UpperChest); break; + default: throw new MigrationException("humanonoid.humanBones[*].bone", boneType); + } + } + } + + static bool IsSingleList(string key, string lhs, List rhs) + { + if (rhs.Count != 1) throw new MigrationException(key, $"{rhs.Count}"); + return lhs == rhs[0]; + } + + static string AvatarPermission(string key, UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType x) + { + switch (x) + { + case UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.everyone: return "Everyone"; + // case AvatarPermissionType.onlyAuthor: return "OnlyAuthor"; + // case AvatarPermissionType.explicitlyLicensedPerson: return "Explicited"; + } + throw new MigrationException(key, $"{x}"); + } + + public static void CheckMeta(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Meta vrm1) + { + if (vrm0["title"].GetString() != vrm1.Name) throw new MigrationException("meta.title", vrm1.Name); + if (vrm0["version"].GetString() != vrm1.Version) throw new MigrationException("meta.version", vrm1.Version); + if (!IsSingleList("meta.author", vrm0["author"].GetString(), vrm1.Authors)) throw new MigrationException("meta.author", $"{vrm1.Authors}"); + if (vrm0["contactInformation"].GetString() != vrm1.ContactInformation) throw new MigrationException("meta.contactInformation", vrm1.ContactInformation); + if (!IsSingleList("meta.reference", vrm0["reference"].GetString(), vrm1.References)) throw new MigrationException("meta.reference", $"{vrm1.References}"); + if (vrm0["texture"].GetInt32() != vrm1.ThumbnailImage) throw new MigrationException("meta.texture", $"{vrm1.ThumbnailImage}"); + + if (vrm0["allowedUserName"].GetString() != AvatarPermission("meta.allowedUserName", vrm1.AvatarPermission)) throw new MigrationException("meta.allowedUserName", $"{vrm1.AvatarPermission}"); + if (vrm0["violentUssageName"].GetString() == "Allow" != vrm1.AllowExcessivelyViolentUsage) throw new MigrationException("meta.violentUssageName", $"{vrm1.AllowExcessivelyViolentUsage}"); + if (vrm0["sexualUssageName"].GetString() == "Allow" != vrm1.AllowExcessivelySexualUsage) throw new MigrationException("meta.sexualUssageName", $"{vrm1.AllowExcessivelyViolentUsage}"); + + if (vrm0["commercialUssageName"].GetString() == "Allow") + { + if (vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalNonProfit) + { + throw new MigrationException("meta.commercialUssageName", $"{vrm1.CommercialUsage}"); + } + } + else + { + if (vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.corporation + || vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalProfit) + { + throw new MigrationException("meta.commercialUssageName", $"{vrm1.CommercialUsage}"); + } + } + + if (MigrationVrmMeta.GetLicenseUrl(vrm0) != vrm1.OtherLicenseUrl) throw new MigrationException("meta.otherLicenseUrl", vrm1.OtherLicenseUrl); + + switch (vrm0["licenseName"].GetString()) + { + case "Other": + { + if (vrm1.Modification != UniGLTF.Extensions.VRMC_vrm.ModificationType.prohibited) throw new MigrationException("meta.licenceName", $"{vrm1.Modification}"); + if (vrm1.AllowRedistribution.Value) throw new MigrationException("meta.liceneName", $"{vrm1.Modification}"); + break; + } + + default: + throw new NotImplementedException(); + } + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1) + { + CheckMeta(vrm0["meta"], vrm1.Meta); + CheckHumanoid(vrm0["humanoid"], vrm1.Humanoid); + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrm1, List nodes) + { + // Migration.CheckSpringBone(vrm0["secondaryAnimation"], vrm1.sp) + } + #endregion + + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationCheck.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationCheck.cs.meta new file mode 100644 index 000000000..291c53d68 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationCheck.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 082de46c993eb764eb020101c113824a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationException.cs b/Assets/External/VRM10/Runtime/Migration/MigrationException.cs new file mode 100644 index 000000000..641727b8c --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationException.cs @@ -0,0 +1,11 @@ +using System; + +namespace UniVRM10 +{ + internal class MigrationException : Exception + { + public MigrationException(string key, string value) : base($"{key}: {value}") + { + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationException.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationException.cs.meta new file mode 100644 index 000000000..5ca257f15 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09e748ecf102bb44a96f0b640a6a3ed1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationMaterials.cs b/Assets/External/VRM10/Runtime/Migration/MigrationMaterials.cs new file mode 100644 index 000000000..116683450 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationMaterials.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using UniGLTF; +using UniJSON; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// VRM 拡張に含まれる Material 情報を用いて、マイグレーションを行う. + /// 前提として、glTF の仕様の範囲で glTFMaterial は既に読み込み済みであると仮定する. + /// + internal static class MigrationMaterials + { + private const string DontUseExtensionShaderName = "VRM_USE_GLTFSHADER"; + private const string MaterialPropertiesKey = "materialProperties"; + + public static void Migrate(glTF gltf, JsonNode vrm0) + { + var needsDisablingVertexColor = false; + var vrm0XMaterialList = vrm0[MaterialPropertiesKey].ArrayItems().ToArray(); + + try + { + // 1. VRM 拡張がついていない PBR Material のマイグレーション. + MigrationPbrMaterial.Migrate(gltf, vrm0); + + // 2. VRM 拡張のうち、古い Unlit 情報からの取得を試みる. + if (MigrationLegacyUnlitMaterial.Migrate(gltf, vrm0XMaterialList)) + { + // NOTE: 古い Unlit である場合、頂点カラー情報を破棄する. + needsDisablingVertexColor = true; + } + + // 3. VRM 拡張のうち、UnlitTransparentZWrite 情報からの取得を試みる. + if (MigrationUnlitTransparentZWriteMaterial.Migrate(gltf, vrm0XMaterialList)) + { + // NOTE: 古い Unlit である場合、頂点カラー情報を破棄する. + needsDisablingVertexColor = true; + } + + // 4. VRM 拡張のうち、MToon 情報からの取得を試みる. + // NOTE: MToon だった場合、内部で material.extensions を破棄してしまう. + MigrationMToonMaterial.Migrate(gltf, vrm0); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + + if (needsDisablingVertexColor) + { + DisableVertexColor(gltf); + } + } + + private static void DisableVertexColor(glTF gltf) + { + foreach (var mesh in gltf.meshes) + { + foreach (var primitive in mesh.primitives) + { + primitive.attributes.COLOR_0 = -1; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationMaterials.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationMaterials.cs.meta new file mode 100644 index 000000000..9924968b8 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationMaterials.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 431e7e81ad3b4f7e9a03ad46d85f9d07 +timeCreated: 1635418411 \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVector3.cs b/Assets/External/VRM10/Runtime/Migration/MigrationVector3.cs new file mode 100644 index 000000000..5ed47bbbe --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVector3.cs @@ -0,0 +1,34 @@ +using UniJSON; + +namespace UniVRM10 +{ + internal static class MigrateVector3 + { + /// + /// VRM0は本来 (x, y, -z) と座標変換するべきところをしていない。 + /// 一方 VRM1 は (-x, y, z) と座標変換するように仕様を変更した。 + /// + /// VRM0 => VRM1 の変換では、 (-x, y, z) する。 + /// + /// + /// + public static float[] Migrate(JsonNode vrm0) + { + return new float[] + { + -vrm0["x"].GetSingle(), + vrm0["y"].GetSingle(), + vrm0["z"].GetSingle(), + }; + } + + public static float[] Migrate(JsonNode parent, string key) + { + if (!parent.ContainsKey(key)) + { + return new float[] { 0, 0, 0 }; + } + return Migrate(parent[key]); + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVector3.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationVector3.cs.meta new file mode 100644 index 000000000..2cf08232a --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVector3.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee1ce63f5e26b4d438908ae385e2d6a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/External/VRM10/Runtime/Migration/MigrationVrm.cs new file mode 100644 index 000000000..df8e005c5 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrm.cs @@ -0,0 +1,221 @@ +using System.Runtime.CompilerServices; +using System; +using System.Collections.Generic; +using UniGLTF; +using UniJSON; +using Unity.Collections; + +[assembly: InternalsVisibleTo("VRM10.Tests")] +[assembly: InternalsVisibleTo("VRM10.Tests.PlayMode")] + +namespace UniVRM10 +{ + /// + /// Convert vrm0 binary to vrm1 binary. Json processing + /// + static internal class MigrationVrm + { + public static byte[] Migrate(byte[] vrm0bytes, VRM10ObjectMeta meta = null, Action modGltf = null) + { + using (var data = new GlbBinaryParser(vrm0bytes, "migration").Parse()) + { + return Migrate(data, meta, modGltf); + } + } + + static (int, int) GetVertexRange(NativeArray indices) + { + var min = int.MaxValue; ; + var max = 0; + foreach (var i in indices) + { + if (i < min) min = i; + if (i > max) max = i; + } + return (min, max); + } + + /// vrm0 をパースしたデータ + /// migration 時に合成するライセンス情報 + /// + public static byte[] Migrate(GltfData data, VRM10ObjectMeta meta = null, Action modGltf = null) + { + // VRM0 -> Unity + var model = ModelReader.Read(data, VrmLib.Coordinates.Vrm0); + // Unity -> VRM1 + model.ConvertCoordinate(VrmLib.Coordinates.Vrm1); + + var (gltf, bin) = MeshUpdater.Execute(data, model); + + // remove existing VRM0 extension + gltf.extensions = null; + if (gltf.extensionsUsed.Contains("VRM")) + { + gltf.extensionsUsed.Remove("VRM"); + } + + MigrateVrm(gltf, data.Json.ParseAsJson()["extensions"]["VRM"], meta); + + if (modGltf != null) + { + modGltf(gltf); + } + + // Serialize whole glTF + ArraySegment vrm1Json = default; + { + var f = new JsonFormatter(); + GltfSerializer.Serialize(f, gltf); + vrm1Json = f.GetStoreBytes(); + } + + return Glb.Create(vrm1Json, bin).ToBytes(); + } + + /// + /// dst が null の場合だけ代入する。 + /// 先に来た方を有効にしたい。 + /// + /// + /// + static void SetIfNull(ref UniGLTF.Extensions.VRMC_vrm.Expression dst, UniGLTF.Extensions.VRMC_vrm.Expression src) + { + if (dst == null) + { + dst = src; + } + } + + static void MigrateVrm(glTF gltf, JsonNode vrm0, VRM10ObjectMeta meta) + { + var meshToNode = CreateMeshToNode(gltf); + + { + // vrm + var vrm1 = new UniGLTF.Extensions.VRMC_vrm.VRMC_vrm + { + SpecVersion = Vrm10Exporter.VRM_SPEC_VERSION + }; + gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm.ExtensionName); + + if (meta == null) + { + // migrate from vrm-0.x + vrm1.Meta = MigrationVrmMeta.Migrate(gltf, vrm0["meta"]); + } + else + { + // inject from arg + vrm1.Meta = new UniGLTF.Extensions.VRMC_vrm.Meta + { + LicenseUrl = Vrm10Exporter.LICENSE_URL_JA, + AllowExcessivelySexualUsage = false, + AllowExcessivelyViolentUsage = false, + AllowPoliticalOrReligiousUsage = false, + AllowRedistribution = false, + }; + Vrm10Exporter.ExportMeta(vrm1, meta, null); + } + // humanoid (required) + vrm1.Humanoid = MigrationVrmHumanoid.Migrate(vrm0["humanoid"]); + + // blendshape (optional) + if (vrm0.TryGet("blendShapeMaster", out JsonNode vrm0BlendShape)) + { + vrm1.Expressions = new UniGLTF.Extensions.VRMC_vrm.Expressions + { + Preset = new UniGLTF.Extensions.VRMC_vrm.Preset(), + Custom = new Dictionary(), + }; + foreach (var (preset, customName, expression) in MigrationVrmExpression.Migrate(gltf, vrm0BlendShape, meshToNode)) + { + switch (preset) + { + case ExpressionPreset.happy: SetIfNull(ref vrm1.Expressions.Preset.Happy, expression); break; + case ExpressionPreset.angry: SetIfNull(ref vrm1.Expressions.Preset.Angry, expression); break; + case ExpressionPreset.sad: SetIfNull(ref vrm1.Expressions.Preset.Sad, expression); break; + case ExpressionPreset.relaxed: SetIfNull(ref vrm1.Expressions.Preset.Relaxed, expression); break; + case ExpressionPreset.surprised: SetIfNull(ref vrm1.Expressions.Preset.Surprised, expression); break; + case ExpressionPreset.aa: SetIfNull(ref vrm1.Expressions.Preset.Aa, expression); break; + case ExpressionPreset.ih: SetIfNull(ref vrm1.Expressions.Preset.Ih, expression); break; + case ExpressionPreset.ou: SetIfNull(ref vrm1.Expressions.Preset.Ou, expression); break; + case ExpressionPreset.ee: SetIfNull(ref vrm1.Expressions.Preset.Ee, expression); break; + case ExpressionPreset.oh: SetIfNull(ref vrm1.Expressions.Preset.Oh, expression); break; + case ExpressionPreset.blink: SetIfNull(ref vrm1.Expressions.Preset.Blink, expression); break; + case ExpressionPreset.blinkLeft: SetIfNull(ref vrm1.Expressions.Preset.BlinkLeft, expression); break; + case ExpressionPreset.blinkRight: SetIfNull(ref vrm1.Expressions.Preset.BlinkRight, expression); break; + case ExpressionPreset.lookUp: SetIfNull(ref vrm1.Expressions.Preset.LookUp, expression); break; + case ExpressionPreset.lookDown: SetIfNull(ref vrm1.Expressions.Preset.LookDown, expression); break; + case ExpressionPreset.lookLeft: SetIfNull(ref vrm1.Expressions.Preset.LookLeft, expression); break; + case ExpressionPreset.lookRight: SetIfNull(ref vrm1.Expressions.Preset.LookRight, expression); break; + case ExpressionPreset.neutral: SetIfNull(ref vrm1.Expressions.Preset.Neutral, expression); break; + case ExpressionPreset.custom: + if (vrm1.Expressions.Custom.ContainsKey(customName)) + { + // 同名が既存。先着を有効とする + } + else + { + vrm1.Expressions.Custom[customName] = expression; + } + break; + default: throw new NotImplementedException(); + } + } + } + + // lookat & firstperson (optional) + if (vrm0.TryGet("firstPerson", out JsonNode vrm0FirstPerson)) + { + (vrm1.LookAt, vrm1.FirstPerson) = MigrationVrmLookAtAndFirstPerson.Migrate(gltf, vrm0FirstPerson); + } + + UniGLTF.Extensions.VRMC_vrm.GltfSerializer.SerializeTo(ref gltf.extensions, vrm1); + } + + // springBone & collider (optional) + if (vrm0.TryGet("secondaryAnimation", out JsonNode vrm0SpringBone)) + { + var springBone = MigrationVrmSpringBone.Migrate(gltf, vrm0SpringBone); + UniGLTF.Extensions.VRMC_springBone.GltfSerializer.SerializeTo(ref gltf.extensions, springBone); + gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_springBone.VRMC_springBone.ExtensionName); + } + + // Material + { + MigrationMaterials.Migrate(gltf, vrm0); + } + } + + public delegate int MeshIndexToNodeIndexFunc(int meshIndex); + + public static MeshIndexToNodeIndexFunc CreateMeshToNode(UniGLTF.glTF gltf) + { + return (int mesh) => + { + for (int i = 0; i < gltf.nodes.Count; ++i) + { + var node = gltf.nodes[i]; + if (node.mesh == mesh) + { + return i; + } + } + return -1; + }; + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1, MeshIndexToNodeIndexFunc meshToNode) + { + MigrationVrmMeta.Check(vrm0["meta"], vrm1.Meta); + MigrationVrmHumanoid.Check(vrm0["humanoid"], vrm1.Humanoid); + MigrationVrmExpression.Check(vrm0["blendShapeMaster"], vrm1.Expressions, meshToNode); + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrm1, List nodes) + { + // Migration.CheckSpringBone(vrm0["secondaryAnimation"], vrm1.sp) + } + } + +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrm.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationVrm.cs.meta new file mode 100644 index 000000000..09c343804 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrm.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab1292ee15555c249af9108c10133c99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmExpression.cs b/Assets/External/VRM10/Runtime/Migration/MigrationVrmExpression.cs new file mode 100644 index 000000000..e694a8af8 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmExpression.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniJSON; +using UnityEngine; + +namespace UniVRM10 +{ + internal static class MigrationVrmExpression + { + /// + /// preset 名の文字列から ExpressionPreset を確定させる。 + /// + /// 0.x の特殊な挙動として、 + /// preset名が "unknown" の場合に、 + /// "name" を preset 名として解釈を試みる。 + /// + /// + /// + /// + static ExpressionPreset ToPreset(JsonNode json, string name) + { + var src = json.GetString().ToLowerInvariant(); + if (src == "unknown") + { + // VRM 0.x では以下の実装が存在した。 + // Preset が unknown で Name が Joy の表情があったときに + // それは Preset が Joy であるとみなしてロードしていた。 + src = name.ToLowerInvariant(); + } + + switch (src) + { + // https://github.com/vrm-c/vrm-specification/issues/185 + // https://github.com/vrm-c/UniVRM/issues/1482 + case "neutral": return ExpressionPreset.neutral; + + case "a": return ExpressionPreset.aa; + case "i": return ExpressionPreset.ih; + case "u": return ExpressionPreset.ou; + case "e": return ExpressionPreset.ee; + case "o": return ExpressionPreset.oh; + + case "blink": return ExpressionPreset.blink; + case "blink_l": return ExpressionPreset.blinkLeft; + case "blink_r": return ExpressionPreset.blinkRight; + + // https://github.com/vrm-c/vrm-specification/issues/163 + case "joy": return ExpressionPreset.happy; + case "angry": return ExpressionPreset.angry; + case "sorrow": return ExpressionPreset.sad; + case "fun": return ExpressionPreset.relaxed; + case "surprised": return ExpressionPreset.surprised; + + case "lookup": return ExpressionPreset.lookUp; + case "lookdown": return ExpressionPreset.lookDown; + case "lookleft": return ExpressionPreset.lookLeft; + case "lookright": return ExpressionPreset.lookRight; + } + + return ExpressionPreset.custom; + } + + static IEnumerable ToMorphTargetBinds(JsonNode json, + MigrationVrm.MeshIndexToNodeIndexFunc meshToNode) + { + foreach (var x in json.ArrayItems()) + { + var meshIndex = x["mesh"].GetInt32(); + var morphTargetIndex = x["index"].GetInt32(); + var weight = x["weight"].GetSingle(); + + var bind = new UniGLTF.Extensions.VRMC_vrm.MorphTargetBind(); + + // https://github.com/vrm-c/vrm-specification/pull/106 + // https://github.com/vrm-c/vrm-specification/pull/153 + var nodeIndex = meshToNode(meshIndex); + if (nodeIndex == -1) + { + // invalid data. skip + Debug.LogWarning($"[MigrationVrmExpression] node.mesh == {meshIndex} not found"); + continue; + } + bind.Node = nodeIndex; + bind.Index = morphTargetIndex; + // https://github.com/vrm-c/vrm-specification/issues/209 + bind.Weight = weight * 0.01f; + + yield return bind; + } + } + + public const string COLOR_PROPERTY = "_Color"; + public const string EMISSION_COLOR_PROPERTY = "_EmissionColor"; + public const string RIM_COLOR_PROPERTY = "_RimColor"; + public const string OUTLINE_COLOR_PROPERTY = "_OutlineColor"; + public const string SHADE_COLOR_PROPERTY = "_ShadeColor"; + + static UniGLTF.Extensions.VRMC_vrm.MaterialColorType? ToMaterialColorType(string src) + { + switch (src) + { + case COLOR_PROPERTY: + return UniGLTF.Extensions.VRMC_vrm.MaterialColorType.color; + + case EMISSION_COLOR_PROPERTY: + return UniGLTF.Extensions.VRMC_vrm.MaterialColorType.emissionColor; + + case RIM_COLOR_PROPERTY: + return UniGLTF.Extensions.VRMC_vrm.MaterialColorType.rimColor; + + case SHADE_COLOR_PROPERTY: + return UniGLTF.Extensions.VRMC_vrm.MaterialColorType.shadeColor; + + case OUTLINE_COLOR_PROPERTY: + return UniGLTF.Extensions.VRMC_vrm.MaterialColorType.outlineColor; + } + + return default; + } + + /// + /// MaterialValue の仕様変更 + /// + /// * MaterialColorBind + /// * TextureTransformBind + /// + /// の2種類になった。 + /// + /// + /// + /// + /// + static void ToMaterialColorBinds(UniGLTF.glTF gltf, JsonNode json, UniGLTF.Extensions.VRMC_vrm.Expression expression) + { + foreach (var x in json.ArrayItems()) + { + var materialName = x["materialName"].GetString(); + var material = gltf.materials.FirstOrDefault(y => y.name == materialName); + if (material == null) + { + // invalid data. skip + Debug.LogWarning($"[MigrationVrmExpression] material.name == {materialName} is not found"); + continue; + } + var materialIndex = gltf.materials.IndexOf(material); + if (materialIndex == -1) + { + // invalid data. skip + Debug.LogWarning($"[MigrationVrmExpression] material.name == {materialName} index"); + continue; + } + var propertyName = x["propertyName"].GetString(); + var targetValue = x["targetValue"].ArrayItems().Select(y => y.GetSingle()).ToArray(); + if (propertyName == "_MainTex_ST") + { + // VRM-0 は無変換 + var (scale, offset) = UniGLTF.TextureTransform.VerticalFlipScaleOffset( + new UnityEngine.Vector2(targetValue[0], targetValue[1]), + new UnityEngine.Vector2(targetValue[2], targetValue[3])); + + if (!expression.TextureTransformBinds.Exists(bind => bind.Material == materialIndex)) + { + expression.TextureTransformBinds.Add(new UniGLTF.Extensions.VRMC_vrm.TextureTransformBind + { + Material = materialIndex, + Scale = new float[] { scale.x, scale.y }, + Offset = new float[] { offset.x, offset.y } + }); + } + } + else if (propertyName == "_MainTex_ST_S") + { + // VRM-0 は無変換 + var (scale, offset) = UniGLTF.TextureTransform.VerticalFlipScaleOffset( + new UnityEngine.Vector2(targetValue[0], 1), + new UnityEngine.Vector2(targetValue[2], 0)); + + if (!expression.TextureTransformBinds.Exists(bind => bind.Material == materialIndex)) + { + expression.TextureTransformBinds.Add(new UniGLTF.Extensions.VRMC_vrm.TextureTransformBind + { + Material = materialIndex, + Scale = new float[] { scale.x, scale.y }, + Offset = new float[] { offset.x, offset.y } + }); + } + } + else if (propertyName == "_MainTex_ST_T") + { + // VRM-0 は無変換 + var (scale, offset) = UniGLTF.TextureTransform.VerticalFlipScaleOffset( + new UnityEngine.Vector2(1, targetValue[1]), + new UnityEngine.Vector2(0, targetValue[3])); + + if (!expression.TextureTransformBinds.Exists(bind => bind.Material == materialIndex)) + { + expression.TextureTransformBinds.Add(new UniGLTF.Extensions.VRMC_vrm.TextureTransformBind + { + Material = materialIndex, + Scale = new float[] { scale.x, scale.y }, + Offset = new float[] { offset.x, offset.y } + }); + } + } + else + { + var materialColorType = ToMaterialColorType(propertyName); + if (materialColorType.HasValue) + { + // color + expression.MaterialColorBinds.Add(new UniGLTF.Extensions.VRMC_vrm.MaterialColorBind + { + Material = materialIndex, + Type = materialColorType.Value, + TargetValue = targetValue, + }); + } + } + } + } + + public static IEnumerable<(ExpressionPreset, string, UniGLTF.Extensions.VRMC_vrm.Expression)> Migrate(UniGLTF.glTF gltf, JsonNode json, + MigrationVrm.MeshIndexToNodeIndexFunc meshToNode) + { + foreach (var blendShapeClip in json["blendShapeGroups"].ArrayItems()) + { + var name = blendShapeClip["name"].GetString(); + var isBinary = false; + if (blendShapeClip.TryGet("isBinary", out JsonNode isBinaryNode)) + { + isBinary = isBinaryNode.GetBoolean(); + } + var preset = ToPreset(blendShapeClip["presetName"], name); + var expression = new UniGLTF.Extensions.VRMC_vrm.Expression + { + IsBinary = isBinary, + MorphTargetBinds = new List(), + MaterialColorBinds = new List(), + TextureTransformBinds = new List(), + }; + expression.MorphTargetBinds = ToMorphTargetBinds(blendShapeClip["binds"], meshToNode).ToList(); + + if (blendShapeClip.TryGet("materialValues", out JsonNode materialValues)) + { + ToMaterialColorBinds(gltf, materialValues, expression); + } + + yield return (preset, name, expression); + } + } + + static void Check(string name, JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Expression vrm1, + MigrationVrm.MeshIndexToNodeIndexFunc meshToNode) + { + if (vrm0["binds"].GetArrayCount() == 0) + { + if (vrm1.MorphTargetBinds == null) + { + // OK + return; + } + else + { + throw new MigrationException($"expression.{name}.binds", "different count"); + } + } + + foreach (var (l, r) in Enumerable.Zip(vrm0["binds"].ArrayItems(), vrm1.MorphTargetBinds, (x, y) => (x, y))) + { + var mesh = l["mesh"].GetInt32(); + var node = meshToNode(mesh); + if (node != r.Node) + { + throw new MigrationException($"expression.{name}.binds.node", $"{node} != {r.Node}"); + } + + var index = l["index"].GetInt32(); + if (index != r.Index) + { + throw new MigrationException($"expression.{name}.binds.index", $"{index} != {r.Index}"); + } + + var weight = l["weight"].GetSingle() * 0.01f; // [0, 100] to [0, 1.0f] + if (weight != r.Weight) + { + throw new MigrationException($"expression.{name}.binds.weight", $"{weight} != {r.Weight}"); + } + } + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Expressions vrm1, + MigrationVrm.MeshIndexToNodeIndexFunc meshToNode) + { + foreach (var blendShape in vrm0["blendShapeGroups"].ArrayItems()) + { + var name = blendShape["presetName"].GetString().ToLower(); + switch (name) + { + case "a": Check(name, blendShape, vrm1.Preset.Aa, meshToNode); break; + case "i": Check(name, blendShape, vrm1.Preset.Ih, meshToNode); break; + case "u": Check(name, blendShape, vrm1.Preset.Ou, meshToNode); break; + case "e": Check(name, blendShape, vrm1.Preset.Ee, meshToNode); break; + case "o": Check(name, blendShape, vrm1.Preset.Oh, meshToNode); break; + case "blink": Check(name, blendShape, vrm1.Preset.Blink, meshToNode); break; + case "joy": Check(name, blendShape, vrm1.Preset.Happy, meshToNode); break; + case "angry": Check(name, blendShape, vrm1.Preset.Angry, meshToNode); break; + case "sorrow": Check(name, blendShape, vrm1.Preset.Sad, meshToNode); break; + case "fun": Check(name, blendShape, vrm1.Preset.Relaxed, meshToNode); break; + case "lookup": Check(name, blendShape, vrm1.Preset.LookUp, meshToNode); break; + case "lookdown": Check(name, blendShape, vrm1.Preset.LookDown, meshToNode); break; + case "lookleft": Check(name, blendShape, vrm1.Preset.LookLeft, meshToNode); break; + case "lookright": Check(name, blendShape, vrm1.Preset.LookRight, meshToNode); break; + case "blink_l": Check(name, blendShape, vrm1.Preset.BlinkLeft, meshToNode); break; + case "blink_r": Check(name, blendShape, vrm1.Preset.BlinkRight, meshToNode); break; + case "neutral": Check(name, blendShape, vrm1.Preset.Neutral, meshToNode); break; + default: + { + string found = default; + foreach (var kv in vrm1.Custom) + { + if (kv.Key.ToLower() == name) + { + Check(name, blendShape, kv.Value, meshToNode); + found = kv.Key; + break; + } + } + if (found == null) + { + throw new MigrationException(name, $"expression not migrated"); + } + break; + } + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmExpression.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationVrmExpression.cs.meta new file mode 100644 index 000000000..f001ec92f --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmExpression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bc0b82a3f20bf5429f1ee36766f5769 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmFirstPersonAndLookAt.cs b/Assets/External/VRM10/Runtime/Migration/MigrationVrmFirstPersonAndLookAt.cs new file mode 100644 index 000000000..4ed6aded1 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmFirstPersonAndLookAt.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using UniGLTF; +using UniGLTF.Extensions.VRMC_vrm; +using UniJSON; + +namespace UniVRM10 +{ + public static class MigrationVrmLookAtAndFirstPerson + { + private static LookAtRangeMap MigrateLookAtRangeMap(JsonNode firstPersonJsonNode, string key, float defaultXRange, float defaultYRange) + { + // NOTE: Curve は VRM 1.0 では廃止されるため, 考慮しません. + if (firstPersonJsonNode.TryGet(key, out var curveMapperJsonNode) && + curveMapperJsonNode.TryGet("xRange", out var xRangeJsonNode) && + curveMapperJsonNode.TryGet("yRange", out var yRangeJsonNode)) + { + return new LookAtRangeMap + { + InputMaxValue = xRangeJsonNode.GetSingle(), + OutputScale = yRangeJsonNode.GetSingle(), + }; + } + + return new LookAtRangeMap + { + InputMaxValue = defaultXRange, + OutputScale = defaultYRange, + }; + } + + private static LookAtType MigrateLookAtType(JsonNode firstPersonJsonNode, string key) + { + if (firstPersonJsonNode.TryGet(key, out var lookAtTypeStringJsonNode)) + { + switch (lookAtTypeStringJsonNode.GetString().ToLowerInvariant()) + { + case "bone": + return LookAtType.bone; + case "blendshape": + return LookAtType.expression; + } + } + + return LookAtType.bone; + } + + private static FirstPersonType MigrateFirstPersonType(JsonNode meshAnnotationJsonNode, string key) + { + if (meshAnnotationJsonNode.TryGet(key, out var firstPersonTypeStringJsonNode)) + { + switch (firstPersonTypeStringJsonNode.GetString().ToLowerInvariant()) + { + case "auto": + return FirstPersonType.auto; + case "both": + return FirstPersonType.both; + case "thirdpersononly": + return FirstPersonType.thirdPersonOnly; + case "firstpersononly": + return FirstPersonType.firstPersonOnly; + } + } + + return FirstPersonType.auto; + } + + private static int? MigrateFirstPersonMeshIndex(JsonNode meshAnnotationJsonNode, string key, glTF gltf) + { + if (meshAnnotationJsonNode.TryGet(key, out var meshIndexJsonNode)) + { + var meshIndex = meshIndexJsonNode.GetInt32(); + if (meshIndex < 0) + { + return default; + } + + // NOTE: VRM 1.0 では glTF の Node Index を記録するため、それに変換する. + // TODO: mesh が共有されたノードの場合はどうなる? 0x の場合はどうなっていたかを調べて挙動を追従する. + for (var gltfNodeIndex = 0; gltfNodeIndex < gltf.nodes.Count; ++gltfNodeIndex) + { + var node = gltf.nodes[gltfNodeIndex]; + if (node.mesh == meshIndex) + { + return gltfNodeIndex; + } + } + } + + // NOTE: VRM をベースに改造した VRM モデルなど、Renderer の増減に対して FirstPerson の設定が追従しないまま null が出力されていることが多い. + return default; + } + + public static (LookAt, FirstPerson) Migrate(glTF gltf, JsonNode firstPersonJsonNode) + { + // NOTE: VRM 1.0 では, LookAt の情報は FirstPerson から独立した型に保存されます. + var lookAtType = MigrateLookAtType(firstPersonJsonNode, "lookAtTypeName"); + var defaultXRangeValue = 90f; + var defaultYRangeValue = GetDefaultCurveMapperYRangeValue(lookAtType); + var lookAt = new LookAt + { + Type = lookAtType, + RangeMapHorizontalInner = MigrateLookAtRangeMap(firstPersonJsonNode, "lookAtHorizontalInner", defaultXRangeValue, defaultYRangeValue), + RangeMapHorizontalOuter = MigrateLookAtRangeMap(firstPersonJsonNode, "lookAtHorizontalOuter", defaultXRangeValue, defaultYRangeValue), + RangeMapVerticalDown = MigrateLookAtRangeMap(firstPersonJsonNode, "lookAtVerticalDown", defaultXRangeValue, defaultYRangeValue), + RangeMapVerticalUp = MigrateLookAtRangeMap(firstPersonJsonNode, "lookAtVerticalUp", defaultXRangeValue, defaultYRangeValue), + OffsetFromHeadBone = MigrateVector3.Migrate(firstPersonJsonNode, "firstPersonBoneOffset"), + }; + + var firstPerson = new FirstPerson + { + // NOTE: VRM 1.0 では firstPersonBone は廃止され, Head Bone 固定になります. + // NOTE: VRM 1.0 では firstPersonBoneOffset は FirstPerson 拡張ではなく LookAt 拡張の OffsetFromHeadBone に移行します. + MeshAnnotations = new List(), + }; + if (firstPersonJsonNode.TryGet("meshAnnotations", out var meshAnnotationArrayJsonNode)) + { + foreach (var meshAnnotationJsonNode in meshAnnotationArrayJsonNode.ArrayItems()) + { + var renderNodeIndex = MigrateFirstPersonMeshIndex(meshAnnotationJsonNode, "mesh", gltf); + if (renderNodeIndex.HasValue) + { + firstPerson.MeshAnnotations.Add(new MeshAnnotation + { + Node = renderNodeIndex.Value, + Type = MigrateFirstPersonType(meshAnnotationJsonNode, "firstPersonFlag"), + }); + } + } + }; + + return (lookAt, firstPerson); + } + + private static float GetDefaultCurveMapperYRangeValue(LookAtType type) + { + switch (type) + { + case LookAtType.bone: + return 10f; + case LookAtType.expression: + return 1f; + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmFirstPersonAndLookAt.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationVrmFirstPersonAndLookAt.cs.meta new file mode 100644 index 000000000..c67118f95 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmFirstPersonAndLookAt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1736a4eb52b0ede499816b187e7c6e08 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmHumanoid.cs b/Assets/External/VRM10/Runtime/Migration/MigrationVrmHumanoid.cs new file mode 100644 index 000000000..efe873467 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmHumanoid.cs @@ -0,0 +1,187 @@ +using System; +using UniJSON; + +namespace UniVRM10 +{ + // { + // "bone": "hips", + // "node": 14, + // "useDefaultValues": true, + // "min": { + // "x": 0, + // "y": 0, + // "z": 0 + // }, + // "max": { + // "x": 0, + // "y": 0, + // "z": 0 + // }, + // "center": { + // "x": 0, + // "y": 0, + // "z": 0 + // }, + // "axisLength": 0 + // }, + public static class MigrationVrmHumanoid + { + static UniGLTF.Extensions.VRMC_vrm.HumanBone MigrateHumanoidBone(JsonNode vrm0) + { + return new UniGLTF.Extensions.VRMC_vrm.HumanBone + { + Node = vrm0["node"].GetInt32(), + }; + } + + public static UniGLTF.Extensions.VRMC_vrm.Humanoid Migrate(JsonNode vrm0) + { + var humanoid = new UniGLTF.Extensions.VRMC_vrm.Humanoid + { + HumanBones = new UniGLTF.Extensions.VRMC_vrm.HumanBones() + }; + + foreach (var humanoidBone in vrm0["humanBones"].ArrayItems()) + { + var boneType = humanoidBone["bone"].GetString(); + switch (boneType) + { + case "hips": humanoid.HumanBones.Hips = MigrateHumanoidBone(humanoidBone); break; + case "leftUpperLeg": humanoid.HumanBones.LeftUpperLeg = MigrateHumanoidBone(humanoidBone); break; + case "rightUpperLeg": humanoid.HumanBones.RightUpperLeg = MigrateHumanoidBone(humanoidBone); break; + case "leftLowerLeg": humanoid.HumanBones.LeftLowerLeg = MigrateHumanoidBone(humanoidBone); break; + case "rightLowerLeg": humanoid.HumanBones.RightLowerLeg = MigrateHumanoidBone(humanoidBone); break; + case "leftFoot": humanoid.HumanBones.LeftFoot = MigrateHumanoidBone(humanoidBone); break; + case "rightFoot": humanoid.HumanBones.RightFoot = MigrateHumanoidBone(humanoidBone); break; + case "spine": humanoid.HumanBones.Spine = MigrateHumanoidBone(humanoidBone); break; + case "chest": humanoid.HumanBones.Chest = MigrateHumanoidBone(humanoidBone); break; + case "neck": humanoid.HumanBones.Neck = MigrateHumanoidBone(humanoidBone); break; + case "head": humanoid.HumanBones.Head = MigrateHumanoidBone(humanoidBone); break; + case "leftShoulder": humanoid.HumanBones.LeftShoulder = MigrateHumanoidBone(humanoidBone); break; + case "rightShoulder": humanoid.HumanBones.RightShoulder = MigrateHumanoidBone(humanoidBone); break; + case "leftUpperArm": humanoid.HumanBones.LeftUpperArm = MigrateHumanoidBone(humanoidBone); break; + case "rightUpperArm": humanoid.HumanBones.RightUpperArm = MigrateHumanoidBone(humanoidBone); break; + case "leftLowerArm": humanoid.HumanBones.LeftLowerArm = MigrateHumanoidBone(humanoidBone); break; + case "rightLowerArm": humanoid.HumanBones.RightLowerArm = MigrateHumanoidBone(humanoidBone); break; + case "leftHand": humanoid.HumanBones.LeftHand = MigrateHumanoidBone(humanoidBone); break; + case "rightHand": humanoid.HumanBones.RightHand = MigrateHumanoidBone(humanoidBone); break; + case "leftToes": humanoid.HumanBones.LeftToes = MigrateHumanoidBone(humanoidBone); break; + case "rightToes": humanoid.HumanBones.RightToes = MigrateHumanoidBone(humanoidBone); break; + case "leftEye": humanoid.HumanBones.LeftEye = MigrateHumanoidBone(humanoidBone); break; + case "rightEye": humanoid.HumanBones.RightEye = MigrateHumanoidBone(humanoidBone); break; + case "jaw": humanoid.HumanBones.Jaw = MigrateHumanoidBone(humanoidBone); break; + case "leftThumbProximal": humanoid.HumanBones.LeftThumbMetacarpal = MigrateHumanoidBone(humanoidBone); break; + case "leftThumbIntermediate": humanoid.HumanBones.LeftThumbProximal = MigrateHumanoidBone(humanoidBone); break; + case "leftThumbDistal": humanoid.HumanBones.LeftThumbDistal = MigrateHumanoidBone(humanoidBone); break; + case "leftIndexProximal": humanoid.HumanBones.LeftIndexProximal = MigrateHumanoidBone(humanoidBone); break; + case "leftIndexIntermediate": humanoid.HumanBones.LeftIndexIntermediate = MigrateHumanoidBone(humanoidBone); break; + case "leftIndexDistal": humanoid.HumanBones.LeftIndexDistal = MigrateHumanoidBone(humanoidBone); break; + case "leftMiddleProximal": humanoid.HumanBones.LeftMiddleProximal = MigrateHumanoidBone(humanoidBone); break; + case "leftMiddleIntermediate": humanoid.HumanBones.LeftMiddleIntermediate = MigrateHumanoidBone(humanoidBone); break; + case "leftMiddleDistal": humanoid.HumanBones.LeftMiddleDistal = MigrateHumanoidBone(humanoidBone); break; + case "leftRingProximal": humanoid.HumanBones.LeftRingProximal = MigrateHumanoidBone(humanoidBone); break; + case "leftRingIntermediate": humanoid.HumanBones.LeftRingIntermediate = MigrateHumanoidBone(humanoidBone); break; + case "leftRingDistal": humanoid.HumanBones.LeftRingDistal = MigrateHumanoidBone(humanoidBone); break; + case "leftLittleProximal": humanoid.HumanBones.LeftLittleProximal = MigrateHumanoidBone(humanoidBone); break; + case "leftLittleIntermediate": humanoid.HumanBones.LeftLittleIntermediate = MigrateHumanoidBone(humanoidBone); break; + case "leftLittleDistal": humanoid.HumanBones.LeftLittleDistal = MigrateHumanoidBone(humanoidBone); break; + case "rightThumbProximal": humanoid.HumanBones.RightThumbMetacarpal = MigrateHumanoidBone(humanoidBone); break; + case "rightThumbIntermediate": humanoid.HumanBones.RightThumbProximal = MigrateHumanoidBone(humanoidBone); break; + case "rightThumbDistal": humanoid.HumanBones.RightThumbDistal = MigrateHumanoidBone(humanoidBone); break; + case "rightIndexProximal": humanoid.HumanBones.RightIndexProximal = MigrateHumanoidBone(humanoidBone); break; + case "rightIndexIntermediate": humanoid.HumanBones.RightIndexIntermediate = MigrateHumanoidBone(humanoidBone); break; + case "rightIndexDistal": humanoid.HumanBones.RightIndexDistal = MigrateHumanoidBone(humanoidBone); break; + case "rightMiddleProximal": humanoid.HumanBones.RightMiddleProximal = MigrateHumanoidBone(humanoidBone); break; + case "rightMiddleIntermediate": humanoid.HumanBones.RightMiddleIntermediate = MigrateHumanoidBone(humanoidBone); break; + case "rightMiddleDistal": humanoid.HumanBones.RightMiddleDistal = MigrateHumanoidBone(humanoidBone); break; + case "rightRingProximal": humanoid.HumanBones.RightRingProximal = MigrateHumanoidBone(humanoidBone); break; + case "rightRingIntermediate": humanoid.HumanBones.RightRingIntermediate = MigrateHumanoidBone(humanoidBone); break; + case "rightRingDistal": humanoid.HumanBones.RightRingDistal = MigrateHumanoidBone(humanoidBone); break; + case "rightLittleProximal": humanoid.HumanBones.RightLittleProximal = MigrateHumanoidBone(humanoidBone); break; + case "rightLittleIntermediate": humanoid.HumanBones.RightLittleIntermediate = MigrateHumanoidBone(humanoidBone); break; + case "rightLittleDistal": humanoid.HumanBones.RightLittleDistal = MigrateHumanoidBone(humanoidBone); break; + case "upperChest": humanoid.HumanBones.UpperChest = MigrateHumanoidBone(humanoidBone); break; + default: throw new NotImplementedException($"unknown bone: {boneType}"); + } + } + + return humanoid; + } + + public static void CheckBone(string bone, JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.HumanBone vrm1) + { + var vrm0NodeIndex = vrm0["node"].GetInt32(); + if (vrm0NodeIndex != vrm1.Node) + { + throw new Exception($"different {bone}: {vrm0NodeIndex} != {vrm1.Node}"); + } + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Humanoid vrm1) + { + foreach (var humanoidBone in vrm0["humanBones"].ArrayItems()) + { + var boneType = humanoidBone["bone"].GetString(); + switch (boneType) + { + case "hips": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Hips); break; + case "leftUpperLeg": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftUpperLeg); break; + case "rightUpperLeg": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightUpperLeg); break; + case "leftLowerLeg": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLowerLeg); break; + case "rightLowerLeg": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLowerLeg); break; + case "leftFoot": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftFoot); break; + case "rightFoot": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightFoot); break; + case "spine": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Spine); break; + case "chest": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Chest); break; + case "neck": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Neck); break; + case "head": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Head); break; + case "leftShoulder": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftShoulder); break; + case "rightShoulder": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightShoulder); break; + case "leftUpperArm": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftUpperArm); break; + case "rightUpperArm": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightUpperArm); break; + case "leftLowerArm": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLowerArm); break; + case "rightLowerArm": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLowerArm); break; + case "leftHand": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftHand); break; + case "rightHand": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightHand); break; + case "leftToes": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftToes); break; + case "rightToes": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightToes); break; + case "leftEye": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftEye); break; + case "rightEye": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightEye); break; + case "jaw": CheckBone(boneType, humanoidBone, vrm1.HumanBones.Jaw); break; + case "leftThumbProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftThumbMetacarpal); break; + case "leftThumbIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftThumbProximal); break; + case "leftThumbDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftThumbDistal); break; + case "leftIndexProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftIndexProximal); break; + case "leftIndexIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftIndexIntermediate); break; + case "leftIndexDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftIndexDistal); break; + case "leftMiddleProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftMiddleProximal); break; + case "leftMiddleIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftMiddleIntermediate); break; + case "leftMiddleDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftMiddleDistal); break; + case "leftRingProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftRingProximal); break; + case "leftRingIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftRingIntermediate); break; + case "leftRingDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftRingDistal); break; + case "leftLittleProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLittleProximal); break; + case "leftLittleIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLittleIntermediate); break; + case "leftLittleDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.LeftLittleDistal); break; + case "rightThumbProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightThumbMetacarpal); break; + case "rightThumbIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightThumbProximal); break; + case "rightThumbDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightThumbDistal); break; + case "rightIndexProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightIndexProximal); break; + case "rightIndexIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightIndexIntermediate); break; + case "rightIndexDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightIndexDistal); break; + case "rightMiddleProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightMiddleProximal); break; + case "rightMiddleIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightMiddleIntermediate); break; + case "rightMiddleDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightMiddleDistal); break; + case "rightRingProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightRingProximal); break; + case "rightRingIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightRingIntermediate); break; + case "rightRingDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightRingDistal); break; + case "rightLittleProximal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLittleProximal); break; + case "rightLittleIntermediate": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLittleIntermediate); break; + case "rightLittleDistal": CheckBone(boneType, humanoidBone, vrm1.HumanBones.RightLittleDistal); break; + case "upperChest": CheckBone(boneType, humanoidBone, vrm1.HumanBones.UpperChest); break; + default: throw new MigrationException("humanoid.humanBones[*].bone", boneType); + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmHumanoid.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationVrmHumanoid.cs.meta new file mode 100644 index 000000000..579bfd811 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmHumanoid.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc4116dfb9da18945a4b602558c3f8b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmMeta.cs b/Assets/External/VRM10/Runtime/Migration/MigrationVrmMeta.cs new file mode 100644 index 000000000..05438fb2d --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmMeta.cs @@ -0,0 +1,287 @@ +using System; +using System.Collections.Generic; +using UniJSON; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// 互換性の無いところ + /// + /// * きつくなる方向は許す + /// * 緩くなる方向は不許可(throw) + /// + // "meta": { + // "title": "Alicia Solid", + // "version": "1.10", + // "author": "© DWANGO Co., Ltd.", + // "contactInformation": "https://3d.nicovideo.jp/alicia/", + // "reference": "", + // "texture": 7, + // "allowedUserName": "Everyone", + // "violentUssageName": "Disallow", + // "sexualUssageName": "Disallow", + // "commercialUssageName": "Allow", + // "otherPermissionUrl": "https://3d.nicovideo.jp/alicia/rule.html", + // "licenseName": "Other", + // "otherLicenseUrl": "https://3d.nicovideo.jp/alicia/rule.html" + // }, + public static class MigrationVrmMeta + { + public static UniGLTF.Extensions.VRMC_vrm.Meta Migrate(UniGLTF.glTF gltf, JsonNode vrm0) + { + var meta = new UniGLTF.Extensions.VRMC_vrm.Meta + { + LicenseUrl = Vrm10Exporter.LICENSE_URL_JA, + AllowPoliticalOrReligiousUsage = false, + AllowExcessivelySexualUsage = false, + AllowExcessivelyViolentUsage = false, + AllowRedistribution = false, + AvatarPermission = UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.onlyAuthor, + CommercialUsage = UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalNonProfit, + CreditNotation = UniGLTF.Extensions.VRMC_vrm.CreditNotationType.required, + Modification = UniGLTF.Extensions.VRMC_vrm.ModificationType.prohibited, + }; + + string otherLicenseUrl = default; + string otherPermissionUrl = default; + + foreach (var kv in vrm0.ObjectItems()) + { + var key = kv.Key.GetString(); + switch (key) + { + case "title": meta.Name = kv.Value.GetString(); break; + case "version": meta.Version = kv.Value.GetString(); break; + case "author": meta.Authors = new List() { kv.Value.GetString() }; break; + case "contactInformation": meta.ContactInformation = kv.Value.GetString(); break; + case "reference": meta.References = new List() { kv.Value.GetString() }; break; + case "texture": + { + // vrm0x use texture. vrm10 use image + var textureIndex = kv.Value.GetInt32(); + if (textureIndex == -1) + { + meta.ThumbnailImage = -1; + } + else + { + var gltfTexture = gltf.textures[textureIndex]; + meta.ThumbnailImage = gltfTexture.source; + } + break; + } + + case "allowedUserName": + { + var allowedUserName = kv.Value.GetString(); + switch (allowedUserName) + { + case "OnlyAuthor": + meta.AvatarPermission = UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.onlyAuthor; + break; + case "ExplicitlyLicensedPerson": + meta.AvatarPermission = UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.onlySeparatelyLicensedPerson; + break; + case "Everyone": + meta.AvatarPermission = UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.everyone; + break; + default: + throw new NotImplementedException($"{key}: {allowedUserName}"); + } + } + break; + + case "violentUssageName": // Typo "Ussage" is VRM 0.x spec. + { + var violentUsageName = kv.Value.GetString(); + switch (violentUsageName) + { + case "Allow": + meta.AllowExcessivelyViolentUsage = true; + break; + case "Disallow": + meta.AllowExcessivelyViolentUsage = false; + break; + default: + throw new NotImplementedException($"{key}: {violentUsageName}"); + } + } + break; + + case "sexualUssageName": // Typo "Ussage" is VRM 0.x spec. + { + var sexualUsageName = kv.Value.GetString(); + switch (sexualUsageName) + { + case "Allow": + meta.AllowExcessivelySexualUsage = true; + break; + case "Disallow": + meta.AllowExcessivelySexualUsage = false; + break; + default: + throw new NotImplementedException($"{key}: {sexualUsageName}"); + } + } + break; + + case "commercialUssageName": // Typo "Ussage" is VRM 0.x spec. + { + var commercialUsageName = kv.Value.GetString(); + switch (commercialUsageName) + { + case "Allow": + meta.CommercialUsage = UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalProfit; + break; + case "Disallow": + meta.CommercialUsage = UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalNonProfit; + break; + default: + throw new NotImplementedException($"{key}: {commercialUsageName}"); + } + } + break; + + case "otherPermissionUrl": otherPermissionUrl = kv.Value.GetString(); break; + case "otherLicenseUrl": otherLicenseUrl = kv.Value.GetString(); break; + + case "licenseName": + { + // TODO + // CreditNotation = CreditNotationType.required, + } + break; + + default: + Debug.LogWarning($"[meta migration] unknown key: {key}"); + break; + } // switch + } // foreach + + // + // OtherLicenseUrl migrate + // OtherPermissionURL removed + // + if (!string.IsNullOrEmpty(otherLicenseUrl) && !string.IsNullOrEmpty(otherPermissionUrl)) + { + if (otherLicenseUrl == otherPermissionUrl) + { + // OK + meta.OtherLicenseUrl = otherLicenseUrl; + } + else + { + // https://github.com/vrm-c/UniVRM/issues/1611 + // 両方を記述しエラーとしない + meta.OtherLicenseUrl = $"'{otherLicenseUrl}', '{otherPermissionUrl}'"; + } + } + else if (!string.IsNullOrEmpty(otherLicenseUrl)) + { + meta.OtherLicenseUrl = otherLicenseUrl; + } + else if (!string.IsNullOrEmpty(otherPermissionUrl)) + { + // otherPermissionUrl => otherLicenseUrl + meta.OtherLicenseUrl = otherPermissionUrl; + } + else + { + // null + } + + return meta; + } + + public static string GetLicenseUrl(JsonNode vrm0) + { + string l0 = default; + string l1 = default; + foreach (var kv in vrm0.ObjectItems()) + { + switch (kv.Key.GetString()) + { + case "otherLicenseUrl": + l0 = kv.Value.GetString(); + break; + + case "otherPermissionUrl": + l1 = kv.Value.GetString(); + break; + } + } + if (!string.IsNullOrWhiteSpace(l0)) + { + return l0; + } + if (!string.IsNullOrWhiteSpace(l1)) + { + return l1; + } + return ""; + } + + static bool IsSingleList(string key, string lhs, List rhs) + { + if (rhs.Count != 1) throw new MigrationException(key, $"{rhs.Count}"); + return lhs == rhs[0]; + } + + static string AvatarPermission(string key, UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType x) + { + switch (x) + { + case UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.everyone: return "Everyone"; + // case AvatarPermissionType.onlyAuthor: return "OnlyAuthor"; + // case AvatarPermissionType.explicitlyLicensedPerson: return "Explicited"; + } + throw new MigrationException(key, $"{x}"); + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Meta vrm1) + { + if (vrm0["title"].GetString() != vrm1.Name) throw new MigrationException("meta.title", vrm1.Name); + if (vrm0["version"].GetString() != vrm1.Version) throw new MigrationException("meta.version", vrm1.Version); + if (!IsSingleList("meta.author", vrm0["author"].GetString(), vrm1.Authors)) throw new MigrationException("meta.author", $"{vrm1.Authors}"); + if (vrm0["contactInformation"].GetString() != vrm1.ContactInformation) throw new MigrationException("meta.contactInformation", vrm1.ContactInformation); + if (!IsSingleList("meta.reference", vrm0["reference"].GetString(), vrm1.References)) throw new MigrationException("meta.reference", $"{vrm1.References}"); + if (vrm0["texture"].GetInt32() != vrm1.ThumbnailImage) throw new MigrationException("meta.texture", $"{vrm1.ThumbnailImage}"); + + if (vrm0["allowedUserName"].GetString() != AvatarPermission("meta.allowedUserName", vrm1.AvatarPermission)) throw new MigrationException("meta.allowedUserName", $"{vrm1.AvatarPermission}"); + if (vrm0["violentUssageName"].GetString() == "Allow" != vrm1.AllowExcessivelyViolentUsage) throw new MigrationException("meta.violentUssageName", $"{vrm1.AllowExcessivelyViolentUsage}"); + if (vrm0["sexualUssageName"].GetString() == "Allow" != vrm1.AllowExcessivelySexualUsage) throw new MigrationException("meta.sexualUssageName", $"{vrm1.AllowExcessivelyViolentUsage}"); + + if (vrm0["commercialUssageName"].GetString() == "Allow") + { + if (vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalNonProfit) + { + throw new MigrationException("meta.commercialUssageName", $"{vrm1.CommercialUsage}"); + } + } + else + { + if (vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.corporation + || vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalProfit) + { + throw new MigrationException("meta.commercialUssageName", $"{vrm1.CommercialUsage}"); + } + } + + if (MigrationVrmMeta.GetLicenseUrl(vrm0) != vrm1.OtherLicenseUrl) throw new MigrationException("meta.otherLicenseUrl", vrm1.OtherLicenseUrl); + + switch (vrm0["licenseName"].GetString()) + { + case "Other": + { + if (vrm1.Modification != UniGLTF.Extensions.VRMC_vrm.ModificationType.prohibited) throw new MigrationException("meta.licenceName", $"{vrm1.Modification}"); + if (vrm1.AllowRedistribution.Value) throw new MigrationException("meta.liceneName", $"{vrm1.Modification}"); + break; + } + + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmMeta.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationVrmMeta.cs.meta new file mode 100644 index 000000000..66442ddfb --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmMeta.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb019cd042148c2428f4e48b9391c448 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs b/Assets/External/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs new file mode 100644 index 000000000..a298ed352 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs @@ -0,0 +1,330 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF.Extensions.VRMC_springBone; +using UniJSON; + +namespace UniVRM10 +{ + public static class MigrationVrmSpringBone + { + class SpringBoneGroupMigrator + { + UniGLTF.glTF _gltf; + + string _comment; + float _dragForce; + float[] _gravityDir; + float _gravityPower; + float _hitRadius; + float _stiffness; + int[] _colliderGroups; + int? _center; + + List _springs = new List(); + public IReadOnlyList Springs => _springs; + + public SpringBoneGroupMigrator(UniGLTF.glTF gltf, JsonNode vrm0BoneGroup) + { + _gltf = gltf; + + _comment = vrm0BoneGroup.GetObjectValueOrDefault("comment", ""); + _dragForce = vrm0BoneGroup["dragForce"].GetSingle(); + _gravityDir = MigrateVector3.Migrate(vrm0BoneGroup["gravityDir"]); + _gravityPower = vrm0BoneGroup["gravityPower"].GetSingle(); + _hitRadius = vrm0BoneGroup["hitRadius"].GetSingle(); + _stiffness = vrm0BoneGroup["stiffiness"].GetSingle(); + _colliderGroups = vrm0BoneGroup["colliderGroups"].ArrayItems().Select(z => z.GetInt32()).ToArray(); + + var center = vrm0BoneGroup["center"].GetInt32(); + if (center >= 0) + { + _center = center; + } + + if (vrm0BoneGroup.ContainsKey("bones")) + { + foreach (var vrm0Bone in vrm0BoneGroup["bones"].ArrayItems()) + { + MigrateRootBone(vrm0Bone.GetInt32()); + } + } + + // fallback. default spring names + foreach (var spring in _springs) + { + if (string.IsNullOrEmpty(spring.Name) && spring.Joints.Count > 0 && spring.Joints[0].Node.HasValue) + { + var i = spring.Joints[0].Node.Value; + if (i >= 0 && i < _gltf.nodes.Count) + { + spring.Name = _gltf.nodes[i].name; + } + } + } + if (string.IsNullOrEmpty(_comment) && _springs.Count > 0) + { + _comment = _springs[0].Name; + } + } + + Spring CreateSpring() + { + var spring = new Spring + { + Name = _comment, + ColliderGroups = _colliderGroups, + Joints = new List(), + Center = _center, + }; + _springs.Add(spring); + return spring; + } + + SpringBoneJoint CreateJoint(int node) + { + return new SpringBoneJoint + { + Node = node, + DragForce = _dragForce, + GravityDir = _gravityDir, + GravityPower = _gravityPower, + HitRadius = _hitRadius, + Stiffness = _stiffness, + }; + } + + void MigrateRootBone(int rootBoneIndex) + { + if (rootBoneIndex >= 0 && rootBoneIndex < _gltf.nodes.Count) + { + // root + CreateJointsRecursive(_gltf.nodes[rootBoneIndex], 1); + } + } + + /// + /// + /// + /// + /// children[0] のみカウントアップする。その他は0にリセットする + /// + void CreateJointsRecursive(UniGLTF.glTFNode node, int level, Spring spring = null) + { + if (spring == null && level > 0) + { + // 2番目以降の子ノードの子から新しい Spring を作る。 + spring = CreateSpring(); + } + if (spring != null) + { + // level==0 のとき(2番目以降の兄弟ボーン)は飛ばす + spring.Joints.Add(CreateJoint(_gltf.nodes.IndexOf(node))); + } + + if (node.children != null && node.children.Length > 0) + { + for (int i = 0; i < node.children.Length; ++i) + { + var childIndex = node.children[i]; + if (childIndex < 0 || childIndex >= _gltf.nodes.Count) + { + // -1 など? + continue; + } + + if (i == 0) + { + // spring に joint を追加する + CreateJointsRecursive(_gltf.nodes[childIndex], level + 1, spring); + } + else + { + // 再帰 + CreateJointsRecursive(_gltf.nodes[childIndex], 0); + } + } + } + else + { + + if (spring != null && spring.Joints.Count > 0) + { + var last = spring.Joints.Last().Node; + if (last.HasValue) + { + var tailJoint = AddTail7cm(last.Value); + spring.Joints.Add(tailJoint); + } + } + } + } + + // https://github.com/vrm-c/vrm-specification/pull/255 + // 1.0 では末端に7cmの遠さに joint を追加する動作をしなくなった。 + // その差異に対応して、7cmの遠さに node を追加する。 + SpringBoneJoint AddTail7cm(int lastIndex) + { + var last = _gltf.nodes[lastIndex]; + var name = last.name ?? ""; + var v1 = new UnityEngine.Vector3(last.translation[0], last.translation[1], last.translation[2]); + var delta = v1.normalized * 0.07f; // 7cm + var tail = new UniGLTF.glTFNode + { + name = name + "_end", + translation = new float[] { + delta.x, + delta.y, + delta.z + }, + }; + var tail_index = _gltf.nodes.Count; + _gltf.nodes.Add(tail); + if (last.children != null && last.children.Length > 0) + { + throw new System.Exception(); + } + last.children = new[] { tail_index }; + + // 1.0 では、head + tail のペアでスプリングを表し、 + // 揺れ挙動のパラメーターは head の方に入る。 + // 要するに 末端の joint では Node しか使われない。 + return new SpringBoneJoint + { + Node = tail_index, + }; + } + } + + /// + /// { + /// "colliderGroups": [ + /// ], + /// "boneGroups": [ + /// ], + /// } + /// + /// + /// + /// + public static VRMC_springBone Migrate(UniGLTF.glTF gltf, JsonNode vrm0) + { + var springBone = new VRMC_springBone + { + SpecVersion = Vrm10Exporter.SPRINGBONE_SPEC_VERSION, + Colliders = new List(), + ColliderGroups = new List(), + Springs = new List(), + }; + + // NOTE: ColliderGroups をマイグレーションする. + // ColliderGroup は Spring から index で参照されているため、順序を入れ替えたり増減させてはいけない. + foreach (var vrm0ColliderGroup in vrm0["colliderGroups"].ArrayItems()) + { + // { + // "node": 14, + // "colliders": [ + // { + // "offset": { + // "x": 0.025884293, + // "y": -0.120000005, + // "z": 0 + // }, + // "radius": 0.05 + // }, + // { + // "offset": { + // "x": -0.02588429, + // "y": -0.120000005, + // "z": 0 + // }, + // "radius": 0.05 + // }, + // { + // "offset": { + // "x": 0, + // "y": -0.0220816135, + // "z": 0 + // }, + // "radius": 0.08 + // } + // ] + // }, + + // NOTE: 1.0 では ColliderGroup は Collider の実体ではなく index を参照する. + var colliderIndices = new List(); + if (vrm0ColliderGroup.ContainsKey("node") && vrm0ColliderGroup.ContainsKey("colliders")) + { + var nodeIndex = vrm0ColliderGroup["node"].GetInt32(); + // NOTE: ColliderGroup に含まれる Collider をマイグレーションする. + foreach (var vrm0Collider in vrm0ColliderGroup["colliders"].ArrayItems()) + { + if (!vrm0Collider.ContainsKey("offset")) continue; + if (!vrm0Collider.ContainsKey("radius")) continue; + + colliderIndices.Add(springBone.Colliders.Count); + springBone.Colliders.Add(new Collider + { + Node = nodeIndex, + Shape = new ColliderShape + { + Sphere = new ColliderShapeSphere + { + Offset = MigrateVector3.Migrate(vrm0Collider["offset"]), + Radius = vrm0Collider["radius"].GetSingle() + } + } + }); + } + } + var colliderGroup = new ColliderGroup() + { + Colliders = colliderIndices.ToArray(), + }; + if (colliderGroup.Colliders.Length > 0 && springBone.Colliders[colliderGroup.Colliders[0]].Node.HasValue) + { + var i = springBone.Colliders[colliderGroup.Colliders[0]].Node.Value; + if (i >= 0 && i < gltf.nodes.Count) + { + var node = gltf.nodes[i]; + colliderGroup.Name = node.name; + } + } + springBone.ColliderGroups.Add(colliderGroup); + } + + foreach (var vrm0BoneGroup in vrm0["boneGroups"].ArrayItems()) + { + // { + // "comment": "", + // "stiffiness": 2, + // "gravityPower": 0, + // "gravityDir": { + // "x": 0, + // "y": -1, + // "z": 0 + // }, + // "dragForce": 0.7, + // "center": -1, + // "hitRadius": 0.02, + // "bones": [ + // 97, + // 99, + // 101, + // 113, + // 114 + // ], + // "colliderGroups": [ + // 3, + // 4, + // 5 + // ] + // }, + var migrator = new SpringBoneGroupMigrator(gltf, vrm0BoneGroup); + springBone.Springs.AddRange(migrator.Springs); + } + + return springBone; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs.meta b/Assets/External/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs.meta new file mode 100644 index 000000000..b0cd38a45 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 885e9b1534dc2ea49ac8e50e519d4b15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/Migrator.cs b/Assets/External/VRM10/Runtime/Migration/Migrator.cs new file mode 100644 index 000000000..548cf9269 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Migrator.cs @@ -0,0 +1,31 @@ +using System; + +namespace UniVRM10 +{ + public static class Migrator + { + /// + /// マイグレーションの公開API + /// + /// MigrationVrm とその関連実装は、internal で runtime import 専用 + /// + /// + /// (必須)外部から供給されるライセンス情報 + /// + public static byte[] Migrate(byte[] vrm0bytes, VRM10ObjectMeta meta, Action modGltf = null) + { + if (meta == null) + { + throw new ArgumentNullException("meta"); + } + foreach (var validation in meta.Validate()) + { + if (!validation.CanExport) + { + throw new ArgumentException(validation.Message); + } + } + return MigrationVrm.Migrate(vrm0bytes, meta, modGltf); + } + } +} \ No newline at end of file diff --git a/Assets/External/VRM10/Runtime/Migration/Migrator.cs.meta b/Assets/External/VRM10/Runtime/Migration/Migrator.cs.meta new file mode 100644 index 000000000..ddc6160ae --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Migrator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: db393ac50cf8db343a6cf58ed69687f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/RotateY180.cs b/Assets/External/VRM10/Runtime/Migration/RotateY180.cs new file mode 100644 index 000000000..c0b1890a7 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/RotateY180.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using UniGLTF; + +namespace UniVRM10 +{ + public class UnNormalizedException : Exception + { + + } + + /// + /// x, y, z => -x, y, -z + /// + public static class RotateY180 + { + public static void Rotate(glTFNode node) + { + if (node.matrix != null && node.matrix.Length == 16) + { + throw new NotImplementedException("matrix not implemented !"); + } + else + { + if (node.translation != null && node.translation.Length == 3) + { + // rotate 180 degrees around the Y axis + var t = node.translation; + t[0] = -t[0]; + t[2] = -t[2]; + } + if (node.rotation != null && node.rotation.Length == 4) + { + if (node.rotation[0] == 0 && node.rotation[1] == 0 && node.rotation[2] == 0 && node.rotation[3] == 1) + { + // indentity + } + else + { + throw new UnNormalizedException(); + } + } + if (node.scale != null && node.scale.Length == 3) + { + // do nothing + } + } + } + + static void ReverseVector3Array(GltfData data, int accessorIndex, HashSet used) + { + if (accessorIndex == -1) + { + return; + } + + if (!used.Add(accessorIndex)) + { + return; + } + + var accessor = data.GLTF.accessors[accessorIndex]; + var bufferViewIndex = -1; + if (accessor.bufferView.HasValue) + { + bufferViewIndex = accessor.bufferView.Value; + } + else if (accessor.sparse?.values != null && accessor.sparse.values.bufferView != -1) + { + bufferViewIndex = accessor.sparse.values.bufferView; + } + + if (bufferViewIndex != -1) + { + var buffer = data.GetBytesFromBufferView(bufferViewIndex); + var span = buffer.Reinterpret(1); + for (int i = 0; i < span.Length; ++i) + { + span[i] = span[i].RotateY180(); + } + } + } + + /// + /// シーンをY軸で180度回転する + /// + /// + public static void Rotate(GltfData data) + { + foreach (var node in data.GLTF.nodes) + { + Rotate(node); + } + + // mesh の回転のみでよい + var used = new HashSet(); + foreach (var mesh in data.GLTF.meshes) + { + foreach (var prim in mesh.primitives) + { + ReverseVector3Array(data, prim.attributes.POSITION, used); + ReverseVector3Array(data, prim.attributes.NORMAL, used); + foreach (var target in prim.targets) + { + ReverseVector3Array(data, target.POSITION, used); + ReverseVector3Array(data, target.NORMAL, used); + } + } + } + + foreach (var skin in data.GLTF.skins) + { + if (used.Add(skin.inverseBindMatrices)) + { + var accessor = data.GLTF.accessors[skin.inverseBindMatrices]; + var buffer = data.GetBytesFromBufferView(accessor.bufferView.Value); + var span = buffer.Reinterpret(1); + for (int i = 0; i < span.Length; ++i) + { + span[i] = span[i].RotateY180(); + } + } + } + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/RotateY180.cs.meta b/Assets/External/VRM10/Runtime/Migration/RotateY180.cs.meta new file mode 100644 index 000000000..1faf0b6c2 --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/RotateY180.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c20dfda77d1e2db4997ba27593ade0c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/Vrm0Meta.cs b/Assets/External/VRM10/Runtime/Migration/Vrm0Meta.cs new file mode 100644 index 000000000..8cc99fbee --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Vrm0Meta.cs @@ -0,0 +1,109 @@ +using System; +using UniJSON; + +namespace UniVRM10.Migration +{ + public enum AllowedUser + { + OnlyAuthor, + ExplicitlyLicensedPerson, + Everyone, + } + + public enum LicenseType + { + Redistribution_Prohibited, + CC0, + CC_BY, + CC_BY_NC, + CC_BY_SA, + CC_BY_NC_SA, + CC_BY_ND, + CC_BY_NC_ND, + Other + } + + public enum UsageLicense + { + Disallow, + Allow, + } + + /// + /// VRM0.x version meta. This class has meta before migrate. + /// + public class Vrm0Meta + { + public string title; + public string version; + public string author; + public string contactInformation; + public string reference; + public int texture = -1; + public AllowedUser allowedUser = AllowedUser.OnlyAuthor; + public bool violentUsage = false; + public bool sexualUsage = false; + public bool commercialUsage = false; + public string otherPermissionUrl; + public LicenseType licenseType = LicenseType.Redistribution_Prohibited; + public string otherLicenseUrl; + + public static Vrm0Meta FromJsonBytes(UniJSON.JsonNode glTF) + { + var oldMeta = new Vrm0Meta(); + var extensions = glTF["extensions"]; + var vrm = extensions["VRM"]; + var meta = vrm["meta"]; + foreach (var kv in meta.ObjectItems()) + { + var key = kv.Key.GetString(); + switch (key) + { + case "title": + oldMeta.title = kv.Value.GetString(); + break; + case "version": + oldMeta.version = kv.Value.GetString(); + break; + case "author": + oldMeta.author = kv.Value.GetString(); + break; + case "contactInformation": + oldMeta.contactInformation = kv.Value.GetString(); + break; + case "reference": + oldMeta.reference = kv.Value.GetString(); + break; + case "texture": + oldMeta.texture = kv.Value.GetInt32(); + break; + case "allowedUserName": + oldMeta.allowedUser = (AllowedUser)Enum.Parse(typeof(AllowedUser), kv.Value.GetString(), true); + break; + case "violentUssageName": + oldMeta.violentUsage = kv.Value.GetString() == "Allow"; + break; + case "sexualUssageName": + oldMeta.sexualUsage = kv.Value.GetString() == "Allow"; + break; + case "commercialUssageName": + oldMeta.commercialUsage = kv.Value.GetString() == "Allow"; + break; + case "otherPermissionUrl": + oldMeta.otherPermissionUrl = kv.Value.GetString(); + break; + case "licenseName": + oldMeta.licenseType = (LicenseType)Enum.Parse(typeof(LicenseType), kv.Value.GetString(), true); + break; + case "otherLicenseUrl": + oldMeta.otherLicenseUrl = kv.Value.GetString(); + break; + default: + UnityEngine.Debug.Log($"{key}"); + break; + } + } + return oldMeta; + } + } +} diff --git a/Assets/External/VRM10/Runtime/Migration/Vrm0Meta.cs.meta b/Assets/External/VRM10/Runtime/Migration/Vrm0Meta.cs.meta new file mode 100644 index 000000000..1c0fe23bc --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Vrm0Meta.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09c88afc4ee72dc4099b705970f5a13e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/VRM10/Runtime/Migration/Vrm0XVersion.cs b/Assets/External/VRM10/Runtime/Migration/Vrm0XVersion.cs new file mode 100644 index 000000000..81d0500cb --- /dev/null +++ b/Assets/External/VRM10/Runtime/Migration/Vrm0XVersion.cs @@ -0,0 +1,87 @@ +using System; +using System.Text.RegularExpressions; + +namespace UniVRM10 +{ + internal static class Vrm0XVersion + { + public static bool IsNewer(string newer, string older) + { + Version newerVersion; + if (!ParseVersion(newer, out newerVersion)) + { + return false; + } + + Version olderVersion; + if (!ParseVersion(older, out olderVersion)) + { + return false; + } + + return IsNewer(newerVersion, olderVersion); + } + + public static bool IsNewer(Version newerVersion, Version olderVersion) + { + if (newerVersion.Major > olderVersion.Major) + { + return true; + } + + if (newerVersion.Minor > olderVersion.Minor) + { + return true; + } + + if (newerVersion.Patch > olderVersion.Patch) + { + return true; + } + + if (string.CompareOrdinal(newerVersion.Pre, olderVersion.Pre) > 0) + { + return true; + } + + return false; + } + + private static readonly Regex VersionSpec = + new Regex(@"(?\d+)\.(?\d+)(\.(?\d+))?(-(?
[0-9A-Za-z-]+))?");
+
+        public static bool ParseVersion(string version, out Version v)
+        {
+            var match = VersionSpec.Match(version);
+            if (!match.Success)
+            {
+                v = new Version();
+                return false;
+            }
+
+            v = new Version();
+            try
+            {
+                v.Major = int.Parse(match.Groups["major"].Value);
+                v.Minor = int.Parse(match.Groups["minor"].Value);
+                v.Patch = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0;
+                v.Pre = match.Groups["pre"].Success ? match.Groups["pre"].Value : "";
+
+                return true;
+            }
+            catch (Exception)
+            {
+                return false;
+            }
+        }
+
+        public struct Version
+        {
+            public int Major;
+            public int Minor;
+            public int Patch;
+            public string Pre;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/Runtime/Migration/Vrm0XVersion.cs.meta b/Assets/External/VRM10/Runtime/Migration/Vrm0XVersion.cs.meta
new file mode 100644
index 000000000..79b3033b8
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Migration/Vrm0XVersion.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 69916d48e7b54a8ea6aae72ab2efc817
+timeCreated: 1667805384
\ No newline at end of file
diff --git a/Assets/External/VRM10/Runtime/Scenes.meta b/Assets/External/VRM10/Runtime/Scenes.meta
new file mode 100644
index 000000000..9847d8385
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Scenes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 43b4b86fab4c0d1428f8123259478c42
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Runtime/Scenes/Sample.cs b/Assets/External/VRM10/Runtime/Scenes/Sample.cs
new file mode 100644
index 000000000..f3468a243
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Scenes/Sample.cs
@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using UnityEngine;
+using VrmLib;
+using UniGLTF;
+
+
+namespace UniVRM10.Sample
+{
+
+    public class Sample : MonoBehaviour
+    {
+        [SerializeField]
+        string m_vrmPath = "Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm";
+
+        // Start is called before the first frame update
+        void OnEnable()
+        {
+            Run();
+        }
+
+        async void Run()
+        {
+            var src = new FileInfo(m_vrmPath);
+            var instance = await Vrm10.LoadPathAsync(m_vrmPath, true);
+
+            var exportedBytes = Vrm10Exporter.Export(instance.gameObject);
+
+            // Import 1.0
+            var vrm10 = await Vrm10.LoadBytesAsync(exportedBytes, false);
+            var pos = vrm10.transform.position;
+            pos.x += 1.5f;
+            vrm10.transform.position = pos;
+            vrm10.name = vrm10.name + "_Imported_v1_0";
+
+            // write
+            var path = Path.GetFullPath("vrm10.vrm");
+            Debug.Log($"write : {path}");
+            File.WriteAllBytes(path, exportedBytes);
+        }
+
+        static void Printmatrices(Model model)
+        {
+            var matrices = model.Skins[0].InverseMatrices.GetSpan();
+            var sb = new System.Text.StringBuilder();
+            for (int i = 0; i < matrices.Length; ++i)
+            {
+                var m = matrices[i];
+                sb.AppendLine($"#{i:00}[{m.M11:.00}, {m.M12:.00}, {m.M13:.00}, {m.M14:.00}][{m.M21:.00}, {m.M22:.00}, {m.M23:.00}, {m.M24:.00}][{m.M31:.00}, {m.M32:.00}, {m.M33:.00}, {m.M34:.00}][{m.M41:.00}, {m.M42:.00}, {m.M43:.00}, {m.M44:.00}]");
+            }
+            Debug.Log(sb.ToString());
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/Runtime/Scenes/Sample.cs.meta b/Assets/External/VRM10/Runtime/Scenes/Sample.cs.meta
new file mode 100644
index 000000000..3c4b0c00a
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Scenes/Sample.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d2dd74f31dd71684da8aa80eaa66390e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Runtime/Scenes/SampleScene.unity b/Assets/External/VRM10/Runtime/Scenes/SampleScene.unity
new file mode 100644
index 000000000..72b9357ea
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Scenes/SampleScene.unity
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:82b733f3f6ddea91d7dd0f11d81eacb840873bd83d7b797a97db853fa89f3bb1
+size 8966
diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/PoseTransfer.unity.meta b/Assets/External/VRM10/Runtime/Scenes/SampleScene.unity.meta
similarity index 74%
rename from Assets/External/UniGLTF/Samples/UniHumanoid/PoseTransfer.unity.meta
rename to Assets/External/VRM10/Runtime/Scenes/SampleScene.unity.meta
index 04c014c8b..eb52b1505 100644
--- a/Assets/External/UniGLTF/Samples/UniHumanoid/PoseTransfer.unity.meta
+++ b/Assets/External/VRM10/Runtime/Scenes/SampleScene.unity.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ae847f673eb3e6f4a95f61b4658b806a
+guid: 25e2f68464c55bf47a9d96514e9d207c
 DefaultImporter:
   externalObjects: {}
   userData: 
diff --git a/Assets/External/VRM10/Runtime/StringExtensions.cs b/Assets/External/VRM10/Runtime/StringExtensions.cs
new file mode 100644
index 000000000..bf790040d
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/StringExtensions.cs
@@ -0,0 +1,77 @@
+using System.IO;
+using UnityEngine;
+
+namespace UniVRM10
+{
+    public static class StringExtensions
+    {
+        public static string ToLowerCamelCase(this string lower)
+        {
+            return lower.Substring(0, 1).ToLower() + lower.Substring(1);
+        }
+        public static string ToUpperCamelCase(this string lower)
+        {
+            return lower.Substring(0, 1).ToUpper() + lower.Substring(1);
+        }
+
+        static string m_unityBasePath;
+        public static string UnityBasePath
+        {
+            get
+            {
+                if (m_unityBasePath == null)
+                {
+                    m_unityBasePath = Path.GetFullPath(Application.dataPath + "/..").Replace("\\", "/");
+                }
+                return m_unityBasePath;
+            }
+        }
+
+        public static string AssetPathToFullPath(this string path)
+        {
+            return UnityBasePath + "/" + path;
+        }
+
+        public static bool StartsWithUnityAssetPath(this string path)
+        {
+            return path.Replace("\\", "/").StartsWith(UnityBasePath + "/Assets");
+        }
+
+        public static string ToUnityRelativePath(this string path)
+        {
+            path = path.Replace("\\", "/");
+            if (path.StartsWith(UnityBasePath))
+            {
+                return path.Substring(UnityBasePath.Length + 1);
+            }
+
+            //Debug.LogWarningFormat("{0} is starts with {1}", path, basePath);
+            return path;
+        }
+
+        static readonly char[] EscapeChars = new char[]
+        {
+            '\\',
+            '/',
+            ':',
+            '*',
+            '?',
+            '"',
+            '<',
+            '>',
+            '|',
+        };
+        public static string EscapeFilePath(this string path)
+        {
+            foreach(var x in EscapeChars)
+            {
+                path = path.Replace(x, '+');
+            }
+            if (path.StartsWith('.'))
+                path = '+' + path;
+            if (path == "")
+                path = "(empty)";
+            return path;
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Runtime/StringExtensions.cs.meta b/Assets/External/VRM10/Runtime/StringExtensions.cs.meta
new file mode 100644
index 000000000..437e2b7e1
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/StringExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fb97f56629365cd48a8ede4bf2a4e634
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Runtime/UnityExtensions.cs b/Assets/External/VRM10/Runtime/UnityExtensions.cs
new file mode 100644
index 000000000..b2c7dc1ee
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/UnityExtensions.cs
@@ -0,0 +1,330 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+
+namespace UniVRM10
+{
+    public struct PosRot
+    {
+        public Vector3 Position;
+        public Quaternion Rotation;
+
+        public static PosRot FromGlobalTransform(Transform t)
+        {
+            return new PosRot
+            {
+                Position = t.position,
+                Rotation = t.rotation,
+            };
+        }
+    }
+
+    public class BlendShape
+    {
+        public string Name;
+
+        public BlendShape(string name)
+        {
+            Name = name;
+        }
+
+        public List Positions = new List();
+        public List Normals = new List();
+        public List Tangents = new List();
+    }
+
+    public static class UnityExtensions
+    {
+        public static Vector4 RotateY180(this Vector4 v)
+        {
+            return new Vector4(-v.x, v.y, -v.z, v.w);
+        }
+
+        public static Vector4 ReverseZ(this Vector4 v)
+        {
+            return new Vector4(v.x, v.y, -v.z, v.w);
+        }
+
+        public static Vector3 RotateY180(this Vector3 v)
+        {
+            return new Vector3(-v.x, v.y, -v.z);
+        }
+
+        public static Vector3 ReverseZ(this Vector3 v)
+        {
+            return new Vector3(v.x, v.y, -v.z);
+        }
+
+        [Obsolete]
+        public static Vector2 ReverseY(this Vector2 v)
+        {
+            return new Vector2(v.x, -v.y);
+        }
+
+        public static Vector2 ReverseUV(this Vector2 v)
+        {
+            return new Vector2(v.x, 1.0f - v.y);
+        }
+
+        public static Quaternion ReverseZ(this Quaternion q)
+        {
+            float angle;
+            Vector3 axis;
+            q.ToAngleAxis(out angle, out axis);
+            return Quaternion.AngleAxis(-angle, ReverseZ(axis));
+        }
+
+        public static Matrix4x4 Matrix4x4FromColumns(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3)
+        {
+#if UNITY_2017_1_OR_NEWER
+            return new Matrix4x4(c0, c1, c2, c3);
+#else
+            var m = default(Matrix4x4);
+            m.SetColumn(0, c0);
+            m.SetColumn(1, c1);
+            m.SetColumn(2, c2);
+            m.SetColumn(3, c3);
+            return m;
+#endif
+        }
+
+        public static Matrix4x4 Matrix4x4FromRotation(Quaternion q)
+        {
+#if UNITY_2017_1_OR_NEWER
+            return Matrix4x4.Rotate(q);
+#else
+            var m = default(Matrix4x4);
+            m.SetTRS(Vector3.zero, q, Vector3.one);
+            return m;
+#endif
+        }
+
+        public static Matrix4x4 RotateY180(this Matrix4x4 m)
+        {
+            // R, R, R, 0
+            // R, R, R, 0
+            // R, R, R, 0
+            // T, T, T, 1
+            var t = m.GetRow(3);
+            var tt = RotateY180(t);
+            m.SetRow(3, tt);
+            return m;
+        }
+
+        public static Matrix4x4 ReverseZ(this Matrix4x4 m)
+        {
+            m.SetTRS(m.ExtractPosition().ReverseZ(), m.ExtractRotation().ReverseZ(), m.ExtractScale());
+            return m;
+        }
+
+        public static Matrix4x4 MatrixFromArray(float[] values)
+        {
+            var m = new Matrix4x4();
+            m.m00 = values[0];
+            m.m10 = values[1];
+            m.m20 = values[2];
+            m.m30 = values[3];
+            m.m01 = values[4];
+            m.m11 = values[5];
+            m.m21 = values[6];
+            m.m31 = values[7];
+            m.m02 = values[8];
+            m.m12 = values[9];
+            m.m22 = values[10];
+            m.m32 = values[11];
+            m.m03 = values[12];
+            m.m13 = values[13];
+            m.m23 = values[14];
+            m.m33 = values[15];
+            return m;
+        }
+
+        // https://forum.unity.com/threads/how-to-assign-matrix4x4-to-transform.121966/
+        public static Quaternion ExtractRotation(this Matrix4x4 matrix)
+        {
+            Vector3 forward;
+            forward.x = matrix.m02;
+            forward.y = matrix.m12;
+            forward.z = matrix.m22;
+
+            Vector3 upwards;
+            upwards.x = matrix.m01;
+            upwards.y = matrix.m11;
+            upwards.z = matrix.m21;
+
+            return Quaternion.LookRotation(forward, upwards);
+        }
+
+        public static Vector3 ExtractPosition(this Matrix4x4 matrix)
+        {
+            Vector3 position;
+            position.x = matrix.m03;
+            position.y = matrix.m13;
+            position.z = matrix.m23;
+            return position;
+        }
+
+        public static Vector3 ExtractScale(this Matrix4x4 matrix)
+        {
+            Vector3 scale;
+            scale.x = new Vector4(matrix.m00, matrix.m10, matrix.m20, matrix.m30).magnitude;
+            scale.y = new Vector4(matrix.m01, matrix.m11, matrix.m21, matrix.m31).magnitude;
+            scale.z = new Vector4(matrix.m02, matrix.m12, matrix.m22, matrix.m32).magnitude;
+            return scale;
+        }
+
+        public static string RelativePathFrom(this Transform self, Transform root)
+        {
+            var path = new List();
+            for (var current = self; current != null; current = current.parent)
+            {
+                if (current == root)
+                {
+                    return String.Join("/", path.ToArray());
+                }
+
+                path.Insert(0, current.name);
+            }
+
+            throw new Exception("no RelativePath");
+        }
+
+        public static Transform GetChildByName(this Transform self, string childName)
+        {
+            foreach (Transform child in self)
+            {
+                if (child.name == childName)
+                {
+                    return child;
+                }
+            }
+
+            throw new KeyNotFoundException();
+        }
+
+        public static Transform GetFromPath(this Transform self, string path)
+        {
+            var current = self;
+
+            var splited = path.Split('/');
+
+            foreach (var childName in splited)
+            {
+                current = current.GetChildByName(childName);
+            }
+
+            return current;
+        }
+
+        public static IEnumerable GetChildren(this Transform self)
+        {
+            foreach (Transform child in self)
+            {
+                yield return child;
+            }
+        }
+
+        public static IEnumerable Traverse(this Transform t)
+        {
+            yield return t;
+            foreach (Transform x in t)
+            {
+                foreach (Transform y in x.Traverse())
+                {
+                    yield return y;
+                }
+            }
+        }
+
+        public static Transform FindDescenedant(this Transform t, string name)
+        {
+            return t.Traverse().First(x => x.name == name);
+        }
+
+        public static IEnumerable Ancestors(this Transform t)
+        {
+            yield return t;
+            if (t.parent != null)
+            {
+                foreach (Transform x in t.parent.Ancestors())
+                {
+                    yield return x;
+                }
+            }
+        }
+
+        public static float[] ToArray(this Quaternion q)
+        {
+            return new float[] { q.x, q.y, q.z, q.w };
+        }
+
+        public static float[] ToArray(this Vector3 v)
+        {
+            return new float[] { v.x, v.y, v.z };
+        }
+
+        public static float[] ToArray(this Vector4 v)
+        {
+            return new float[] { v.x, v.y, v.z, v.w };
+        }
+
+        public static void ReverseZRecursive(this Transform root)
+        {
+            var globalMap = root.Traverse().ToDictionary(x => x, x => PosRot.FromGlobalTransform(x));
+
+            foreach (var x in root.Traverse())
+            {
+                x.position = globalMap[x].Position.ReverseZ();
+                x.rotation = globalMap[x].Rotation.ReverseZ();
+            }
+        }
+
+        public static Mesh GetSharedMesh(this Transform t)
+        {
+            var meshFilter = t.GetComponent();
+            if (meshFilter != null)
+            {
+                return meshFilter.sharedMesh;
+            }
+
+            var skinnedMeshRenderer = t.GetComponent();
+            if (skinnedMeshRenderer != null)
+            {
+                return skinnedMeshRenderer.sharedMesh;
+            }
+
+            return null;
+        }
+
+        public static Material[] GetSharedMaterials(this Transform t)
+        {
+            var renderer = t.GetComponent();
+            if (renderer != null)
+            {
+                return renderer.sharedMaterials;
+            }
+
+            return new Material[] { };
+        }
+
+        public static bool Has(this Transform transform, T t) where T : Component
+        {
+            return transform.GetComponent() == t;
+        }
+
+        public static T GetOrAddComponent(this GameObject go) where T : Component
+        {
+            var c = go.GetComponent();
+            if (c != null)
+            {
+                return c;
+            }
+            return go.AddComponent();
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Runtime/UnityExtensions.cs.meta b/Assets/External/VRM10/Runtime/UnityExtensions.cs.meta
new file mode 100644
index 000000000..a3f1b6a88
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/UnityExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5cb49bc8f0aa24c46b4e36387e1ed308
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Runtime/VRM10.asmdef b/Assets/External/VRM10/Runtime/VRM10.asmdef
new file mode 100644
index 000000000..9c5174d79
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/VRM10.asmdef
@@ -0,0 +1,31 @@
+{
+    "name": "VRM10",
+    "rootNamespace": "",
+    "references": [
+        "GUID:2ef84b520212e174a94668c7a0862d3b",
+        "GUID:a9bc101fb0471f94a8f99fd242fdd934",
+        "GUID:8d76e605759c3f64a957d63ef96ada7c",
+        "GUID:da3e51d19d51a544fa14d43fee843098",
+        "GUID:bce005214fa49654d93927908c15b1f2",
+        "GUID:0aaf403bd13871a44b7127aef2695ff8",
+        "GUID:b7aa47b240b57de44a4b2021c143c9bf",
+        "GUID:f2ca1407928ebdc4bbe7765cc278be44",
+        "GUID:2665a8d13d1b3f18800f46e256720795",
+        "GUID:1cd941934d098654fa21a13f28346412"
+    ],
+    "includePlatforms": [],
+    "excludePlatforms": [],
+    "allowUnsafeCode": false,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [
+        {
+            "name": "com.unity.burst",
+            "expression": "0.0.1",
+            "define": "ENABLE_VRM10_BURST"
+        }
+    ],
+    "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/Runtime/VRM10.asmdef.meta b/Assets/External/VRM10/Runtime/VRM10.asmdef.meta
new file mode 100644
index 000000000..a1b2b094c
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/VRM10.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e47c917724578cc43b5506c17a27e9a0
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Runtime/Version.meta b/Assets/External/VRM10/Runtime/Version.meta
new file mode 100644
index 000000000..8e4ebc6c3
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Version.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1324c667b838ac543a6780bd7e258c7b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Runtime/Version/VRMSpecVersion.cs b/Assets/External/VRM10/Runtime/Version/VRMSpecVersion.cs
new file mode 100644
index 000000000..149013e2d
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Version/VRMSpecVersion.cs
@@ -0,0 +1,13 @@
+
+namespace UniVRM10
+{
+    public static partial class VRM10SpecVersion
+    {
+        public const int MAJOR = 1;
+        public const int MINOR = 0;
+        public const int PATCH = 0;
+        public const string PRE_ID = "";
+
+        const string VERSION = "1.0.0";
+    }
+}
diff --git a/Assets/External/VRM10/Runtime/Version/VRMSpecVersion.cs.meta b/Assets/External/VRM10/Runtime/Version/VRMSpecVersion.cs.meta
new file mode 100644
index 000000000..6345e6eaf
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Version/VRMSpecVersion.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 34998e0a5a307d847a66bc4de26fbf33
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM/Runtime/Format/VRMVersionPartial.cs b/Assets/External/VRM10/Runtime/Version/VRMSpecVersionPartial.cs
similarity index 94%
rename from Assets/External/VRM/Runtime/Format/VRMVersionPartial.cs
rename to Assets/External/VRM10/Runtime/Version/VRMSpecVersionPartial.cs
index 2fe04e6da..6d5e26472 100644
--- a/Assets/External/VRM/Runtime/Format/VRMVersionPartial.cs
+++ b/Assets/External/VRM10/Runtime/Version/VRMSpecVersionPartial.cs
@@ -1,9 +1,9 @@
 using System;
 using System.Text.RegularExpressions;
 
-namespace VRM
+namespace UniVRM10
 {
-    public static partial class VRMVersion
+    public static partial class VRM10SpecVersion
     {
         /// 
         /// Returns true if a passed version is newer than current UniVRM.
@@ -99,7 +99,6 @@ namespace VRM
             public string Pre;
         }
 
-        public const string VRM_VERSION = "UniVRM-" + VERSION;
-        public const string MENU = "VRM0";
+        public const string MENU = "VRM1";
     }
 }
diff --git a/Assets/External/VRM10/Runtime/Version/VRMSpecVersionPartial.cs.meta b/Assets/External/VRM10/Runtime/Version/VRMSpecVersionPartial.cs.meta
new file mode 100644
index 000000000..83deb9556
--- /dev/null
+++ b/Assets/External/VRM10/Runtime/Version/VRMSpecVersionPartial.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 83197292b727c684ea74bbdbf6d40ef0
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests.meta b/Assets/External/VRM10/Tests.meta
new file mode 100644
index 000000000..b65ccd843
--- /dev/null
+++ b/Assets/External/VRM10/Tests.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 34fff503c3487b140a29c3da6538d6f6
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/ApiSampleTests.cs b/Assets/External/VRM10/Tests/ApiSampleTests.cs
new file mode 100644
index 000000000..a53b0dfdb
--- /dev/null
+++ b/Assets/External/VRM10/Tests/ApiSampleTests.cs
@@ -0,0 +1,57 @@
+using System.IO;
+using NUnit.Framework;
+using UniGLTF;
+using UniGLTF.Extensions.VRMC_vrm;
+using UnityEngine;
+using VRMShaders;
+
+namespace UniVRM10.Test
+{
+    public class ApiSampleTests
+    {
+        VrmLib.Model ReadModel(string path)
+        {
+            var bytes = MigrationVrm.Migrate(File.ReadAllBytes(path));
+
+            var data = new GlbLowLevelParser(path, bytes).Parse();
+
+            var model = ModelReader.Read(data);
+            return model;
+        }
+
+        GameObject BuildGameObject(Vrm10Data data, bool showMesh)
+        {
+            using (var loader = new Vrm10Importer(data, null))
+            {
+                var loaded = loader.Load();
+                if (showMesh)
+                {
+                    loaded.ShowMeshes();
+                }
+                loaded.EnableUpdateWhenOffscreen();
+                return loaded.gameObject;
+            }
+        }
+
+        [Test]
+        public void Sample()
+        {
+            var path = "Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm";
+            Debug.Log($"load: {path}");
+
+            using (var data = new GlbFileParser(path).Parse())
+            using (var migrated = Vrm10Data.Migrate(data, out Vrm10Data result, out MigrationData migration))
+            {
+                Assert.NotNull(result);
+
+                var go = BuildGameObject(result, true);
+                Debug.Log(go);
+
+                // export
+                var vrmBytes = Vrm10Exporter.Export(go, new EditorTextureSerializer());
+
+                Debug.Log($"export {vrmBytes.Length} bytes");
+            }
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Tests/ApiSampleTests.cs.meta b/Assets/External/VRM10/Tests/ApiSampleTests.cs.meta
new file mode 100644
index 000000000..16861ae48
--- /dev/null
+++ b/Assets/External/VRM10/Tests/ApiSampleTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c937dce0cf7760a4b9c26ea23c3e567c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/ExpressionKeyTests.cs b/Assets/External/VRM10/Tests/ExpressionKeyTests.cs
new file mode 100644
index 000000000..ea7491ea4
--- /dev/null
+++ b/Assets/External/VRM10/Tests/ExpressionKeyTests.cs
@@ -0,0 +1,41 @@
+using NUnit.Framework;
+
+namespace UniVRM10.Test
+{
+    public sealed class ExpressionKeyTests
+    {
+        [Test]
+        public void InvalidExpressionKey()
+        {
+            Assert.Catch(() => ExpressionKey.CreateCustom(""));
+            Assert.Catch(() => ExpressionKey.CreateCustom(null));
+            Assert.Catch(() => ExpressionKey.CreateFromPreset(ExpressionPreset.custom));
+        }
+
+        [Test]
+        public void ExpressionKeyEquality()
+        {
+            var happy = ExpressionKey.CreateFromPreset(ExpressionPreset.happy);
+            Assert.AreEqual(happy, ExpressionKey.CreateFromPreset(ExpressionPreset.happy));
+            Assert.AreNotEqual(happy, ExpressionKey.CreateFromPreset(ExpressionPreset.sad));
+            Assert.AreNotEqual(happy, ExpressionKey.CreateFromPreset(ExpressionPreset.aa));
+            Assert.AreNotEqual(happy, ExpressionKey.CreateCustom("happy"));
+            Assert.AreNotEqual(happy, ExpressionKey.CreateCustom("my_custom"));
+
+            var custom = ExpressionKey.CreateCustom("my_custom");
+            Assert.AreEqual(custom, ExpressionKey.CreateCustom("my_custom"));
+            Assert.AreNotEqual(custom, ExpressionKey.CreateCustom("my_custom_2"));
+            Assert.AreNotEqual(custom, ExpressionKey.CreateFromPreset(ExpressionPreset.happy));
+        }
+
+        [Test]
+        public void ExpressionKeyName()
+        {
+            var happy = ExpressionKey.CreateFromPreset(ExpressionPreset.happy);
+            Assert.AreEqual("happy", happy.Name);
+
+            var custom = ExpressionKey.CreateCustom("my_custom");
+            Assert.AreEqual("my_custom", custom.Name);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/Tests/ExpressionKeyTests.cs.meta b/Assets/External/VRM10/Tests/ExpressionKeyTests.cs.meta
new file mode 100644
index 000000000..f339a9639
--- /dev/null
+++ b/Assets/External/VRM10/Tests/ExpressionKeyTests.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 370f4995d6964d059eb63ee5f9c97439
+timeCreated: 1692083961
\ No newline at end of file
diff --git a/Assets/External/VRM10/Tests/ExpressionTests.cs b/Assets/External/VRM10/Tests/ExpressionTests.cs
new file mode 100644
index 000000000..f097d503d
--- /dev/null
+++ b/Assets/External/VRM10/Tests/ExpressionTests.cs
@@ -0,0 +1,62 @@
+using System.Linq;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace UniVRM10.Test
+{
+    public class ExpressionTests
+    {
+        [Test]
+        public void DuplicatedMaterialColorBindings()
+        {
+            var controller = TestAsset.LoadAlicia();
+
+            var src = controller.Vrm.Expression.Aa.MaterialColorBindings.ToList();
+
+            var renderers = controller.GetComponentsInChildren();
+            var name = renderers[0].sharedMaterials[0].name;
+
+            // add duplicate key
+            src.Add(new MaterialColorBinding
+            {
+                BindType = UniGLTF.Extensions.VRMC_vrm.MaterialColorType.color,
+                MaterialName = name,
+                TargetValue = default,
+            });
+            src.Add(new MaterialColorBinding
+            {
+                BindType = UniGLTF.Extensions.VRMC_vrm.MaterialColorType.color,
+                MaterialName = name,
+                TargetValue = default,
+            });
+            controller.Vrm.Expression.Aa.MaterialColorBindings = src.ToArray();
+
+            // ok if no exception
+            var r = new Vrm10Runtime(controller, useControlRig: false);
+        }
+
+        [Test]
+        public void DuplicatedMaterialUVBindings()
+        {
+            var controller = TestAsset.LoadAlicia();
+
+            var renderers = controller.GetComponentsInChildren();
+            var name = renderers[0].sharedMaterials[0].name;
+
+            // add duplicate key
+            var src = controller.Vrm.Expression.Aa.MaterialUVBindings.ToList();
+            src.Add(new MaterialUVBinding
+            {
+                MaterialName = name,
+            });
+            src.Add(new MaterialUVBinding
+            {
+                MaterialName = name,
+            });
+            controller.Vrm.Expression.Aa.MaterialUVBindings = src.ToArray();
+
+            // ok if no exception
+            var r = new Vrm10Runtime(controller, useControlRig: false);
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Tests/ExpressionTests.cs.meta b/Assets/External/VRM10/Tests/ExpressionTests.cs.meta
new file mode 100644
index 000000000..98a7dcfd4
--- /dev/null
+++ b/Assets/External/VRM10/Tests/ExpressionTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4df0165d166ce5941b38f43b0f9e3633
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/LoadTests.cs b/Assets/External/VRM10/Tests/LoadTests.cs
new file mode 100644
index 000000000..652e5a146
--- /dev/null
+++ b/Assets/External/VRM10/Tests/LoadTests.cs
@@ -0,0 +1,29 @@
+using NUnit.Framework;
+using UniGLTF;
+
+namespace UniVRM10.Test
+{
+    public class LoadTests
+    {
+        [Test]
+        public void EmptyThumbnailName()
+        {
+            using (var data = new GlbFileParser(TestAsset.AliciaPath).Parse())
+            using (var migrated = Vrm10Data.Migrate(data, out var vrm1Data, out var migration))
+            {
+                // Vrm10Data.ParseOrMigrate(TestAsset.AliciaPath, true, out Vrm10Data vrm, out MigrationData migration))
+                Assert.NotNull(vrm1Data);
+
+                var index = vrm1Data.VrmExtension.Meta.ThumbnailImage.Value;
+
+                // empty thumbnail name
+                vrm1Data.Data.GLTF.images[index].name = null;
+
+                using (var loader = new Vrm10Importer(vrm1Data))
+                {
+                    loader.LoadAsync(new VRMShaders.ImmediateCaller()).Wait();
+                }
+            }
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Tests/LoadTests.cs.meta b/Assets/External/VRM10/Tests/LoadTests.cs.meta
new file mode 100644
index 000000000..2dc13ac5f
--- /dev/null
+++ b/Assets/External/VRM10/Tests/LoadTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c9a9a3ce2deae9c4791d816aa189df3d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/MaterialImportTests.cs b/Assets/External/VRM10/Tests/MaterialImportTests.cs
new file mode 100644
index 000000000..a1737c3c4
--- /dev/null
+++ b/Assets/External/VRM10/Tests/MaterialImportTests.cs
@@ -0,0 +1,53 @@
+using System.IO;
+using System.Linq;
+using NUnit.Framework;
+using UniGLTF;
+using UnityEngine;
+using VRMShaders;
+
+namespace UniVRM10
+{
+    public class MaterialImporterTests
+    {
+        static string AliciaPath
+        {
+            get
+            {
+                return Path.GetFullPath(Application.dataPath + "/../Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm")
+                    .Replace("\\", "/");
+            }
+        }
+
+        [Test]
+        public void MaterialImporterTest()
+        {
+            var migratedBytes = MigrationVrm.Migrate(File.ReadAllBytes(AliciaPath));
+            using (var data = new GlbLowLevelParser(AliciaPath, migratedBytes).Parse())
+            {
+
+                var matDesc = new BuiltInVrm10MaterialDescriptorGenerator().Get(data, 0);
+                Assert.AreEqual("Alicia_body", matDesc.Name);
+                Assert.AreEqual("VRM10/MToon10", matDesc.Shader.name);
+                Assert.AreEqual("Alicia_body", matDesc.TextureSlots["_MainTex"].UnityObjectName);
+                Assert.AreEqual("Alicia_body", matDesc.TextureSlots["_ShadeTex"].UnityObjectName);
+
+                AreColorEqualApproximately(new Color(1, 1, 1, 1), matDesc.Colors["_Color"]);
+                ColorUtility.TryParseHtmlString("#FFDDD6", out var shadeColor);
+                AreColorEqualApproximately(shadeColor, matDesc.Colors["_ShadeColor"]);
+
+                Assert.AreEqual(1.0f - 0.1f, matDesc.FloatValues["_GiEqualization"]);
+
+                var (key, value) = matDesc.EnumerateSubAssetKeyValue().First();
+                Assert.AreEqual(new SubAssetKey(typeof(Texture2D), "Alicia_body"), key);
+            }
+        }
+
+        private void AreColorEqualApproximately(Color expected, Color actual)
+        {
+            Assert.AreEqual(Mathf.RoundToInt(expected.r * 255), Mathf.RoundToInt(actual.r * 255));
+            Assert.AreEqual(Mathf.RoundToInt(expected.g * 255), Mathf.RoundToInt(actual.g * 255));
+            Assert.AreEqual(Mathf.RoundToInt(expected.b * 255), Mathf.RoundToInt(actual.b * 255));
+            Assert.AreEqual(Mathf.RoundToInt(expected.a * 255), Mathf.RoundToInt(actual.a * 255));
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Tests/MaterialImportTests.cs.meta b/Assets/External/VRM10/Tests/MaterialImportTests.cs.meta
new file mode 100644
index 000000000..086e968df
--- /dev/null
+++ b/Assets/External/VRM10/Tests/MaterialImportTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9609b7e054ece274bbe4a2e1a3405373
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/MigrationTests.cs b/Assets/External/VRM10/Tests/MigrationTests.cs
new file mode 100644
index 000000000..fab6ee3c2
--- /dev/null
+++ b/Assets/External/VRM10/Tests/MigrationTests.cs
@@ -0,0 +1,411 @@
+using System.IO;
+using NUnit.Framework;
+using UnityEngine;
+using UniJSON;
+using System;
+using UniGLTF;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using VRMShaders;
+
+namespace UniVRM10
+{
+    public class MigrationTests
+    {
+        static string AliciaPath
+        {
+            get
+            {
+                return Path.GetFullPath(Application.dataPath + "/../Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm")
+                    .Replace("\\", "/");
+            }
+        }
+
+        static JsonNode GetVRM0(byte[] bytes)
+        {
+            using (var glb = new GlbBinaryParser(bytes, "vrm0").Parse())
+            {
+                var json = glb.Json.ParseAsJson();
+                return json["extensions"]["VRM"];
+            }
+        }
+
+        T GetExtension(UniGLTF.glTFExtension extensions, UniJSON.Utf8String key, Func deserializer)
+        {
+            if (extensions is UniGLTF.glTFExtensionImport import)
+            {
+                foreach (var kv in import.ObjectItems())
+                {
+                    if (kv.Key.GetUtf8String() == key)
+                    {
+                        return deserializer(kv.Value);
+                    }
+                }
+            }
+
+            return default;
+        }
+
+        [Test]
+        public void Migrate0to1()
+        {
+            var vrm0Bytes = File.ReadAllBytes(AliciaPath);
+            var vrm0Json = GetVRM0(vrm0Bytes);
+
+            var vrm1 = MigrationVrm.Migrate(vrm0Bytes);
+            using (var glb = new GlbBinaryParser(vrm1, "vrm1").Parse())
+            {
+                var json = glb.Json.ParseAsJson();
+                var gltf = UniGLTF.GltfDeserializer.Deserialize(json);
+
+                MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.ExtensionNameUtf8,
+                    UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.Deserialize), MigrationVrm.CreateMeshToNode(gltf));
+                MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.ExtensionNameUtf8,
+                    UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.Deserialize), gltf.nodes);
+            }
+        }
+
+        const float EPS = 1e-4f;
+
+        static bool Nearly(float l, float r)
+        {
+            return Mathf.Abs(l - r) <= EPS;
+        }
+
+        static bool Nearly(Vector3 l, Vector3 r)
+        {
+            if (!Nearly(l.x, r.x)) return false;
+            if (!Nearly(l.y, r.y)) return false;
+            if (!Nearly(l.z, r.z)) return false;
+            return true;
+        }
+
+        [Test]
+        public void RotateY180Test()
+        {
+            var euler = new Vector3(0, 10, 20);
+            var r = Quaternion.Euler(euler);
+            var node = new glTFNode
+            {
+                translation = new float[] { 1, 2, 3 },
+                // rotation = new float[] { r.x, r.y, r.z, r.w },
+                scale = new float[] { 1, 2, 3 },
+            };
+            RotateY180.Rotate(node);
+
+            Assert.AreEqual(new Vector3(-1, 2, -3), node.translation.ToVector3());
+            Assert.AreEqual(new Vector3(1, 2, 3), node.scale.ToVector3());
+
+            // var result = node.rotation.ToQuaternion().ToUnityQuaternion().eulerAngles;
+            // Debug.LogFormat($"{result}");
+
+            // Assert.True(Nearly(0, result.x));
+            // Assert.True(Nearly(10, result.y));
+            // Assert.True(Nearly(20, result.z));
+        }
+
+        [Test]
+        public void UnityEngineMatrixTest()
+        {
+            var u = new UnityEngine.Matrix4x4();
+            u.m00 = 0;
+            u.m01 = 1;
+            u.m02 = 2;
+            u.m03 = 3;
+            u.m10 = 4;
+            u.m11 = 5;
+            u.m12 = 6;
+            u.m13 = 7;
+            u.m20 = 8;
+            u.m21 = 9;
+            u.m22 = 10;
+            u.m23 = 11;
+            u.m30 = 12;
+            u.m31 = 13;
+            u.m32 = 14;
+            u.m33 = 15;
+            Assert.AreEqual(new UnityEngine.Vector4(0, 1, 2, 3), u.GetRow(0));
+            var bytes = new Byte[64];
+            SafeMarshalCopy.CopyArrayToToBytes(new[] { u }, new ArraySegment(bytes));
+            Assert.AreEqual(1.0f, BitConverter.ToSingle(bytes, 16));
+        }
+
+        [Test]
+        public void NumericMatrixTest()
+        {
+            var u = new System.Numerics.Matrix4x4();
+            u.M11 = 0;
+            u.M12 = 1;
+            u.M13 = 2;
+            u.M14 = 3;
+            u.M21 = 4;
+            u.M22 = 5;
+            u.M23 = 6;
+            u.M24 = 7;
+            u.M31 = 8;
+            u.M32 = 9;
+            u.M33 = 10;
+            u.M34 = 11;
+            u.M41 = 12;
+            u.M42 = 13;
+            u.M43 = 14;
+            u.M44 = 15;
+            var bytes = new Byte[64];
+            SafeMarshalCopy.CopyArrayToToBytes(new[] { u }, new ArraySegment(bytes));
+            Assert.AreEqual(1.0f, BitConverter.ToSingle(bytes, 4));
+        }
+
+        static IEnumerable EnumerateGltfFiles(DirectoryInfo dir)
+        {
+            if (dir.Name == ".git")
+            {
+                yield break;
+            }
+
+            foreach (var child in dir.EnumerateDirectories())
+            {
+                foreach (var x in EnumerateGltfFiles(child))
+                {
+                    yield return x;
+                }
+            }
+
+            foreach (var child in dir.EnumerateFiles())
+            {
+                switch (child.Extension.ToLower())
+                {
+                    case ".vrm":
+                        yield return child;
+                        break;
+                }
+            }
+        }
+
+        [Test]
+        public void Migrate_VrmTestModels()
+        {
+            var env = System.Environment.GetEnvironmentVariable("VRM_TEST_MODELS");
+            if (string.IsNullOrEmpty(env))
+            {
+                return;
+            }
+            var root = new DirectoryInfo(env);
+            if (!root.Exists)
+            {
+                return;
+            }
+
+            foreach (var gltf in EnumerateGltfFiles(root))
+            {
+                try
+                {
+                    Vrm10.LoadPathAsync(gltf.FullName, true, controlRigGenerationOption: ControlRigGenerationOption.None).Wait();
+                }
+                catch (UnNormalizedException)
+                {
+                    Debug.LogWarning($"[Not Normalized] {gltf}");
+                }
+            }
+        }
+
+        /// 
+        /// migration で x が反転することを確認
+        /// 
+        [Test]
+        public void Migrate_SpringBoneTest()
+        {
+            //
+            // vrm0 のオリジナルの値
+            //
+            var VALUE = new Vector3(-0.0359970331f, -0.0188314915f, 0.00566166639f);
+            var bytes0 = File.ReadAllBytes(AliciaPath);
+            int groupIndex = default;
+            using (var data0 = new GlbLowLevelParser(AliciaPath, bytes0).Parse())
+            {
+                var json0 = data0.Json.ParseAsJson();
+                groupIndex = json0["extensions"]["VRM"]["secondaryAnimation"]["boneGroups"][0]["colliderGroups"][0].GetInt32();
+                var x = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["x"].GetSingle();
+                var y = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["y"].GetSingle();
+                var z = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["z"].GetSingle();
+                Assert.AreEqual(VALUE.x, x);
+                Assert.AreEqual(VALUE.y, y);
+                Assert.AreEqual(VALUE.z, z);
+            }
+
+            //
+            // vrm1 に migrate
+            //
+            var bytes1 = MigrationVrm.Migrate(bytes0);
+            using (var data1 = new GlbLowLevelParser(AliciaPath, bytes1).Parse())
+            {
+                Assert.True(UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.TryGet(data1.GLTF.extensions, out UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone));
+                var spring = springBone.Springs[0];
+                // var colliderNodeIndex = spring.ColliderGroups[0];
+                // x軸だけが反転する
+
+                var colliderIndex = 0;
+                for (int i = 0; i < groupIndex; ++i)
+                {
+                    colliderIndex += springBone.ColliderGroups[i].Colliders.Length;
+                }
+
+                Assert.AreEqual(-VALUE.x, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[0]);
+                Assert.AreEqual(VALUE.y, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[1]);
+                Assert.AreEqual(VALUE.z, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[2]);
+            }
+        }
+
+        [Test]
+        public void MigrateMeta()
+        {
+            using (var data = new GlbFileParser(AliciaPath).Parse())
+            {
+                using (var migrated = Vrm10Data.Migrate(data, out Vrm10Data vrm, out MigrationData migration))
+                {
+                    Assert.NotNull(vrm);
+                    Assert.NotNull(migration);
+                }
+            }
+        }
+
+        class TempFile : IDisposable
+        {
+            public string Path { get; }
+
+            TempFile(string path)
+            {
+                Path = path;
+            }
+
+            public void Dispose()
+            {
+                // File.Delete(Path);
+            }
+
+            public static TempFile Create(string path, byte[] bytes)
+            {
+                File.WriteAllBytes(path, bytes);
+                return new TempFile(path);
+            }
+        }
+
+        [Test]
+        public void GltfValidator()
+        {
+            if (!VRMShaders.PathObject.TryGetFromEnvironmentVariable("GLTF_VALIDATOR", out var exe))
+            {
+                return;
+            }
+            if (!exe.Exists)
+            {
+                return;
+            }
+            using (var data = new GlbFileParser(AliciaPath).Parse())
+            using (var migrated = Vrm10Data.Migrate(data, out Vrm10Data vrm, out MigrationData migration))
+            {
+                var json = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(migrated.Json);
+                var glb = Glb.Create(json, new ArraySegment(migrated.Bin.ToArray())).ToBytes();
+                using (var tmp = TempFile.Create("GltfValidator_tmp.glb", glb))
+                {
+                    var processStartInfo = new System.Diagnostics.ProcessStartInfo(exe.FullPath, $"{tmp.Path} -o")
+                    {
+                        CreateNoWindow = true,
+                        UseShellExecute = false,
+                        RedirectStandardOutput = true,
+                        RedirectStandardError = true,
+                    };
+
+                    var process = System.Diagnostics.Process.Start(processStartInfo);
+                    string standardOutput = process.StandardOutput.ReadToEnd();
+                    string standardError = process.StandardError.ReadToEnd();
+                    int exitCode = process.ExitCode;
+                    Debug.Log($"{exitCode}\n{standardOutput}\n{standardError}\n");
+                    Assert.AreEqual(0, exitCode);
+                }
+            }
+        }
+
+        [Test]
+        public void MigrateMaterials()
+        {
+            // NOTE: Standard Shader の emission の値がそのまま gamma value として emissiveFactor に出力されていた v0.106.0 のファイル
+            var model106 = File.ReadAllBytes(Path.Combine(Application.dataPath, "../Tests/Models/Materials/EmissionMigration_v0.106.0.vrm"));
+            // NOTE: Standard Shader の emission の値が linear value に変換されて emissiveFactor に出力される v0.107.0 のファイル
+            var model107 = File.ReadAllBytes(Path.Combine(Application.dataPath, "../Tests/Models/Materials/EmissionMigration_v0.107.0.vrm"));
+
+            var materialCount = 6;
+
+            var correctMaterialNames = new string[]
+            {
+                "Unlit_SRGB_0.5",
+                "Standard_Emission_0.5",
+                "Standard_Emission_2.0",
+                "Unlit_Linear_0.5",
+                "MToon_Emission_0.5",
+                "MToon_Emission_2.0",
+            };
+            var correctShaderNames = new string[]
+            {
+                "UniGLTF/UniUnlit",
+                "Standard",
+                "Standard",
+                "UniGLTF/UniUnlit",
+                "VRM10/MToon10",
+                "VRM10/MToon10",
+            };
+            var colorName = "_Color";
+            var correctColors = new Color[]
+            {
+                new Color(0.5f, 0.5f, 0.5f, 1),
+                new Color(0f, 0f, 0f, 1),
+                new Color(0f, 0f, 0f, 1),
+                new Color(Mathf.LinearToGammaSpace(0.5f), Mathf.LinearToGammaSpace(0.5f), Mathf.LinearToGammaSpace(0.5f), 1),
+                new Color(0f, 0f, 0f, 1),
+                new Color(0f, 0f, 0f, 1),
+            };
+            var emissionName = "_EmissionColor";
+            var correctEmissions = new Color?[]
+            {
+                null,
+                new Color(0.5f, 0.5f, 0.5f, 1),
+                new Color(2.0f, 2.0f, 2.0f, 1),
+                null,
+                new Color(0.5f, 0.5f, 0.5f, 1),
+                new Color(2.0f, 2.0f, 2.0f, 1),
+            };
+
+            var instance106 = Vrm10.LoadBytesAsync(model106, awaitCaller: new ImmediateCaller()).Result;
+            var materials106 = instance106.GetComponent().Materials;
+            Assert.AreEqual(materialCount, materials106.Count);
+            for (var idx = 0; idx < materialCount; ++idx)
+            {
+                var material = materials106[idx];
+                Assert.AreEqual(correctMaterialNames[idx], material.name);
+                Assert.AreEqual(correctShaderNames[idx], material.shader.name);
+                AssertAreApproximatelyEqualColor(correctColors[idx], material.GetColor(colorName));
+                if (correctEmissions[idx].HasValue) AssertAreApproximatelyEqualColor(correctEmissions[idx].Value, material.GetColor(emissionName));
+            }
+
+            var instance107 = Vrm10.LoadBytesAsync(model107, awaitCaller: new ImmediateCaller()).Result;
+            var materials107 = instance107.GetComponent().Materials;
+            Assert.AreEqual(materialCount, materials107.Count);
+            for (var idx = 0; idx < materialCount; ++idx)
+            {
+                var material = materials107[idx];
+                Assert.AreEqual(correctMaterialNames[idx], material.name);
+                Assert.AreEqual(correctShaderNames[idx], material.shader.name);
+                AssertAreApproximatelyEqualColor(correctColors[idx], material.GetColor(colorName));
+                if (correctEmissions[idx].HasValue) AssertAreApproximatelyEqualColor(correctEmissions[idx].Value, material.GetColor(emissionName));
+            }
+        }
+
+        private void AssertAreApproximatelyEqualColor(Color expected, Color actual)
+        {
+            const float colorEpsilon = 0.5f / 255f;
+
+            Assert.That(actual.r, Is.EqualTo(expected.r).Within(colorEpsilon));
+            Assert.That(actual.g, Is.EqualTo(expected.g).Within(colorEpsilon));
+            Assert.That(actual.b, Is.EqualTo(expected.b).Within(colorEpsilon));
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Tests/MigrationTests.cs.meta b/Assets/External/VRM10/Tests/MigrationTests.cs.meta
new file mode 100644
index 000000000..2bfe03e08
--- /dev/null
+++ b/Assets/External/VRM10/Tests/MigrationTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 856d7b1293642ed4dbce5341b397b74e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/SerializationTests.cs b/Assets/External/VRM10/Tests/SerializationTests.cs
new file mode 100644
index 000000000..1b7f2c6de
--- /dev/null
+++ b/Assets/External/VRM10/Tests/SerializationTests.cs
@@ -0,0 +1,274 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using UniGLTF;
+using UniJSON;
+using UnityEditor;
+using UnityEngine;
+
+
+namespace UniVRM10
+{
+    public class SerializationTests
+    {
+        static string Serialize(T value, Action seri)
+        {
+            var f = new JsonFormatter();
+            seri(f, value);
+            var b = f.GetStoreBytes();
+            return Encoding.UTF8.GetString(b.Array, b.Offset, b.Count);
+        }
+
+        [Test]
+        public void MaterialTest()
+        {
+            var q = "\"";
+
+            {
+                var data = new UniGLTF.glTFMaterial
+                {
+                    name = "Some",
+                };
+
+                var json = Serialize(data, UniGLTF.GltfSerializer.Serialize_gltf_materials_ITEM);
+                Assert.AreEqual($"{{{q}name{q}:{q}Some{q},{q}pbrMetallicRoughness{q}:{{{q}baseColorFactor{q}:[1,1,1,1],{q}metallicFactor{q}:1,{q}roughnessFactor{q}:1}},{q}doubleSided{q}:false}}", json);
+            }
+
+            {
+                var data = new UniGLTF.glTF();
+                data.textures.Add(new UniGLTF.glTFTexture
+                {
+
+                });
+
+                var json = Serialize(data, UniGLTF.GltfSerializer.Serialize);
+                // Assert.Equal($"{{ {q}name{q}: {q}Some{q} }}", json);
+            }
+
+            {
+                var data = new UniGLTF.glTFMaterial
+                {
+                    name = "Alicia_body",
+                    pbrMetallicRoughness = new UniGLTF.glTFPbrMetallicRoughness
+                    {
+                        // BaseColorFactor = new[] { 1, 1, 1, 1 },
+                        // BaseColorTexture= { }, 
+                        metallicFactor = 0,
+                        roughnessFactor = 0.9f
+                    },
+                    alphaMode = "OPAQUE",
+                    alphaCutoff = 0.5f,
+                    extensions = new UniGLTF.glTFExtensionExport().Add(
+                        UniGLTF.glTF_KHR_materials_unlit.ExtensionName,
+                        new ArraySegment(UniGLTF.glTF_KHR_materials_unlit.Raw))
+                };
+
+                var json = Serialize(data, UniGLTF.GltfSerializer.Serialize_gltf_materials_ITEM);
+                // Assert.Equal($"{{ {q}name{q}: {q}Some{q} }}", json);
+            }
+        }
+
+        static void CompareUnityMaterial(Material lhs, Material rhs)
+        {
+            Assert.AreEqual(lhs.name, rhs.name);
+            Assert.AreEqual(lhs.shader, rhs.shader);
+            var sb = new StringBuilder();
+            for (int i = 0; i < ShaderUtil.GetPropertyCount(lhs.shader); ++i)
+            {
+                var prop = ShaderUtil.GetPropertyName(lhs.shader, i);
+                if (s_ignoreProps.Contains(prop))
+                {
+                    continue;
+                }
+
+                switch (ShaderUtil.GetPropertyType(lhs.shader, i))
+                {
+                    case UnityEditor.ShaderUtil.ShaderPropertyType.Color:
+                    case UnityEditor.ShaderUtil.ShaderPropertyType.Vector:
+                        {
+                            var l = lhs.GetVector(prop);
+                            var r = rhs.GetVector(prop);
+                            if (l != r)
+                            {
+                                sb.AppendLine($"{prop} {l}!={r}");
+                            }
+                        }
+                        break;
+
+                    case UnityEditor.ShaderUtil.ShaderPropertyType.Float:
+                    case UnityEditor.ShaderUtil.ShaderPropertyType.Range:
+                        {
+                            var l = lhs.GetFloat(prop);
+                            var r = rhs.GetFloat(prop);
+                            if (l != r)
+                            {
+                                sb.AppendLine($"{prop} {l}!={r}");
+                            }
+                        }
+                        break;
+
+                    case UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv:
+                        {
+                            var l = lhs.GetTextureOffset(prop);
+                            var r = rhs.GetTextureOffset(prop);
+                            if (l != r)
+                            {
+                                sb.AppendLine($"{prop} {l}!={r}");
+                            }
+                        }
+                        break;
+
+                    default:
+                        throw new NotImplementedException(prop);
+                }
+            }
+            if (sb.Length > 0)
+            {
+                Debug.LogWarning(sb.ToString());
+            }
+            Assert.AreEqual(0, sb.Length);
+        }
+
+        static string[] s_ignoreKeys = new string[]
+        {
+            "(MToonMaterial).Definition.MetaDefinition.VersionNumber",
+        };
+
+        static string[] s_ignoreProps = new string[]
+        {
+            "_ReceiveShadowRate",
+            "_ShadingGradeRate",
+            "_MToonVersion",
+            "_Glossiness", // Gloss is burned into the texture and changed to the default value (1.0)
+        };
+
+        // /// Unity material を export => import して元の material と一致するか
+        // [Test]
+        // [TestCase("TestMToon", typeof(UniGLTF.Extensions.VRMC_vrm.MToonMaterial))]
+        // [TestCase("TestUniUnlit", typeof(UniGLTF.Extensions.VRMC_vrm.UnlitMaterial))]
+        // [TestCase("TestStandard", typeof(UniGLTF.Extensions.VRMC_vrm.PBRMaterial))]
+        // [TestCase("TestUnlitColor", typeof(UniGLTF.Extensions.VRMC_vrm.UnlitMaterial), false)]
+        // [TestCase("TestUnlitTexture", typeof(UniGLTF.Extensions.VRMC_vrm.UnlitMaterial), false)]
+        // [TestCase("TestUnlitTransparent", typeof(UniGLTF.Extensions.VRMC_vrm.UnlitMaterial), false)]
+        // [TestCase("TestUnlitCutout", typeof(UniGLTF.Extensions.VRMC_vrm.UnlitMaterial), false)]
+        // public void UnityMaterialTest(string materialName, Type vrmLibMaterialType, bool sameShader = true)
+        // {
+        //     // asset (cerate copy for avoid modify asset)
+        //     var src = new Material(Resources.Load(materialName));
+
+        //     // asset => vrmlib
+        //     var converter = new UniVRM10.RuntimeVrmConverter();
+        //     // var vrmLibMaterial = converter.Export10(src, (a, b, c, d) => null);
+        //     // Assert.AreEqual(vrmLibMaterialType, vrmLibMaterial.GetType());
+
+        //     // // vrmlib => gltf
+        //     // var textures = new List();
+        //     // var (gltfMaterial, hasKhrUnlit) = ToProtobufMaterial(vrmLibMaterial, textures);
+        //     // if (gltfMaterial.extensions != null)
+        //     // {
+        //     //     gltfMaterial.extensions = gltfMaterial.extensions.Deserialize();
+        //     // }
+        //     // Assert.AreEqual(hasKhrUnlit, glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
+
+        //     // // gltf => json
+        //     // var jsonMaterial = Serialize(gltfMaterial, UniGLTF.GltfSerializer.Serialize_gltf_materials_ITEM);
+
+        //     // // gltf <= json
+        //     // var deserialized = UniGLTF.GltfDeserializer.Deserialize_gltf_materials_LIST(jsonMaterial.ParseAsJson());
+
+        //     // // vrmlib <= gltf
+        //     // var loaded = deserialized.FromGltf(textures);
+        //     // // var context = ModelDiffContext.Create();
+        //     // // ModelDiffExtensions.MaterialEquals(context, vrmLibMaterial, loaded);
+        //     // // var diff = context.List
+        //     // // .Where(x => !s_ignoreKeys.Contains(x.Context))
+        //     // // .ToArray();
+        //     // // if (diff.Length > 0)
+        //     // // {
+        //     // //     Debug.LogWarning(string.Join("\n", diff.Select(x => $"{x.Context}: {x.Message}")));
+        //     // // }
+        //     // // Assert.AreEqual(0, diff.Length);
+
+        //     // // <= vrmlib
+        //     // var map = new Dictionary();
+        //     // var dst = UniVRM10.RuntimeUnityMaterialBuilder.CreateMaterialAsset(loaded, hasVertexColor: false, map);
+        //     // dst.name = src.name;
+
+        //     // if (sameShader)
+        //     // {
+        //     //     CompareUnityMaterial(src, dst);
+        //     // }
+        // }
+
+        [Test]
+        public void ExpressionTest()
+        {
+            var q = "\"";
+
+            {
+                var data = new UniGLTF.Extensions.VRMC_vrm.Expression();
+                data.OverrideBlink = UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.block;
+                data.MorphTargetBinds = new List{
+                    new UniGLTF.Extensions.VRMC_vrm.MorphTargetBind{
+                        Weight=1.0f
+                    }
+                };
+
+                var json = Serialize(data, UniGLTF.Extensions.VRMC_vrm.GltfSerializer.__expressions_Serialize_Custom_ITEM);
+                Assert.AreEqual($"{{{q}morphTargetBinds{q}:[{{{q}weight{q}:1}}],{q}overrideBlink{q}:{q}block{q},{q}overrideLookAt{q}:{q}none{q},{q}overrideMouth{q}:{q}none{q}}}", json);
+            }
+
+            {
+                // var expression = new UniGLTF.Extensions.VRMC_vrm.Expression(UniGLTF.Extensions.VRMC_vrm.ExpressionPreset.Blink, "blink", true)
+                // {
+                //     OverrideBlink = UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.None,
+                //     OverrideLookAt = UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.Block,
+                //     OverrideMouth = UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.Blend,
+                // };
+
+                // // export
+                // var gltf = UniVRM10.ExpressionAdapter.ToGltf(expression, new List(), new List());
+                // Assert.AreEqual(UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.none, gltf.OverrideBlink);
+                // Assert.AreEqual(UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.block, gltf.OverrideLookAt);
+                // Assert.AreEqual(UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.blend, gltf.OverrideMouth);
+
+                // // import
+                // var imported = UniVRM10.ExpressionAdapter.FromGltf(gltf, new List(), new List());
+                // Assert.AreEqual(UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.None, imported.OverrideBlink);
+                // Assert.AreEqual(UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.Block, imported.OverrideLookAt);
+                // Assert.AreEqual(UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.Blend, imported.OverrideMouth);
+            }
+
+            {
+                // // export
+                // foreach (var preset in Enum.GetValues(typeof(UniGLTF.Extensions.VRMC_vrm.ExpressionPreset)) as UniGLTF.Extensions.VRMC_vrm.ExpressionPreset[])
+                // {
+                //     var expression = new UniGLTF.Extensions.VRMC_vrm.Expression(preset, "", false);
+
+                //     // expect no exception
+                //     var gltf = ExpressionAdapter.ToGltf(
+                //         expression, 
+                //         new List(),
+                //         new List());
+                // }
+
+                // // import 
+                // foreach (var preset in Enum.GetValues(typeof(UniGLTF.Extensions.VRMC_vrm.ExpressionPreset)) as UniGLTF.Extensions.VRMC_vrm.ExpressionPreset[])
+                // {
+                //     var gltf = new UniGLTF.Extensions.VRMC_vrm.Expression
+                //     {
+                //         Preset = preset,
+                //     };
+
+                //     // expect no exception
+                //     ExpressionAdapter.FromGltf(
+                //         gltf,
+                //         new List(),
+                //         new List());
+                // }
+            }
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Tests/SerializationTests.cs.meta b/Assets/External/VRM10/Tests/SerializationTests.cs.meta
new file mode 100644
index 000000000..685a3987e
--- /dev/null
+++ b/Assets/External/VRM10/Tests/SerializationTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4b12f97cab9de774ca44ae4061361529
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/TestAsset.cs b/Assets/External/VRM10/Tests/TestAsset.cs
new file mode 100644
index 000000000..6077c2c44
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAsset.cs
@@ -0,0 +1,26 @@
+using System.IO;
+using UnityEngine;
+
+namespace UniVRM10
+{
+    public static class TestAsset
+    {
+        public static string AliciaPath
+        {
+            get
+            {
+                return Path.GetFullPath(Application.dataPath + "/../Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm")
+                    .Replace("\\", "/");
+            }
+        }
+
+        public static Vrm10Instance LoadAlicia()
+        {
+            var task = Vrm10.LoadPathAsync(AliciaPath, canLoadVrm0X: true);
+            task.Wait();
+            var instance = task.Result;
+
+            return instance.GetComponent();
+        }
+    }
+}
diff --git a/Assets/External/VRM10/Tests/TestAsset.cs.meta b/Assets/External/VRM10/Tests/TestAsset.cs.meta
new file mode 100644
index 000000000..f9145dda7
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAsset.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b18f57dcd7d3c19469aa4842b2ee6ae1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/TestAssets.meta b/Assets/External/VRM10/Tests/TestAssets.meta
new file mode 100644
index 000000000..9dc585a90
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAssets.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8bde762829a19de49a51317236684982
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/TestAssets/TestMToon.mat b/Assets/External/VRM10/Tests/TestAssets/TestMToon.mat
new file mode 100644
index 000000000..fa3b36734
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAssets/TestMToon.mat
@@ -0,0 +1,131 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: TestMToon
+  m_Shader: {fileID: 4800000, guid: 1a97144e4ad27a04aafd70f7b915cedb, type: 3}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap:
+    RenderType: Opaque
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OutlineWidthTexture:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ReceiveShadowTexture:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _RimTexture:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ShadeTexture:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ShadingGradeTexture:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _SphereAdd:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _UvAnimMaskTexture:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BlendMode: 0
+    - _BumpScale: 1
+    - _CullMode: 2
+    - _Cutoff: 0.5
+    - _DebugMode: 0
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _IndirectLightIntensity: 0.1
+    - _LightColorAttenuation: 0
+    - _MToonVersion: 32
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _OutlineColorMode: 0
+    - _OutlineCullMode: 1
+    - _OutlineLightingMix: 1
+    - _OutlineScaledMaxDistance: 1
+    - _OutlineWidth: 0.5
+    - _OutlineWidthMode: 0
+    - _Parallax: 0.02
+    - _ReceiveShadowRate: 1
+    - _RimFresnelPower: 1
+    - _RimLift: 0
+    - _RimLightingMix: 0
+    - _ShadeShift: 0
+    - _ShadeToony: 0.9
+    - _ShadingGradeRate: 1
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _UvAnimRotation: 0
+    - _UvAnimScrollX: 0
+    - _UvAnimScrollY: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+    - _OutlineColor: {r: 0, g: 0, b: 0, a: 1}
+    - _RimColor: {r: 0, g: 0, b: 0, a: 1}
+    - _ShadeColor: {r: 0.96999997, g: 0.81, b: 0.86, a: 1}
diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/a.mat.meta b/Assets/External/VRM10/Tests/TestAssets/TestMToon.mat.meta
similarity index 64%
rename from Assets/External/UniGLTF/Samples/ScreenSpace/a.mat.meta
rename to Assets/External/VRM10/Tests/TestAssets/TestMToon.mat.meta
index 99a39296b..97ca6f87f 100644
--- a/Assets/External/UniGLTF/Samples/ScreenSpace/a.mat.meta
+++ b/Assets/External/VRM10/Tests/TestAssets/TestMToon.mat.meta
@@ -1,8 +1,8 @@
 fileFormatVersion: 2
-guid: 17618f7c446af114e8ac672f1e992954
+guid: 93bec9f866ef2fa4186c45f5b3868941
 NativeFormatImporter:
   externalObjects: {}
-  mainObjectFileID: 2100000
+  mainObjectFileID: 0
   userData: 
   assetBundleName: 
   assetBundleVariant: 
diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/target.mat b/Assets/External/VRM10/Tests/TestAssets/TestStandard.mat
similarity index 93%
rename from Assets/External/UniGLTF/Samples/UniHumanoid/target.mat
rename to Assets/External/VRM10/Tests/TestAssets/TestStandard.mat
index 1136c07c9..09becda2b 100644
--- a/Assets/External/UniGLTF/Samples/UniHumanoid/target.mat
+++ b/Assets/External/VRM10/Tests/TestAssets/TestStandard.mat
@@ -5,8 +5,9 @@ Material:
   serializedVersion: 6
   m_ObjectHideFlags: 0
   m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInternal: {fileID: 0}
-  m_Name: target
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: TestStandard
   m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
   m_ShaderKeywords: 
   m_LightmapFlags: 4
@@ -72,5 +73,5 @@ Material:
     - _UVSec: 0
     - _ZWrite: 1
     m_Colors:
-    - _Color: {r: 0.60773194, g: 0.8584906, b: 0.14983091, a: 1}
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
     - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/b.mat.meta b/Assets/External/VRM10/Tests/TestAssets/TestStandard.mat.meta
similarity index 64%
rename from Assets/External/UniGLTF/Samples/ScreenSpace/b.mat.meta
rename to Assets/External/VRM10/Tests/TestAssets/TestStandard.mat.meta
index 10982cd63..939c50031 100644
--- a/Assets/External/UniGLTF/Samples/ScreenSpace/b.mat.meta
+++ b/Assets/External/VRM10/Tests/TestAssets/TestStandard.mat.meta
@@ -1,8 +1,8 @@
 fileFormatVersion: 2
-guid: 7c53fd18a7678ca488df002b2d136438
+guid: cc57fbf5564e47d4b841435ced7e680d
 NativeFormatImporter:
   externalObjects: {}
-  mainObjectFileID: 2100000
+  mainObjectFileID: 0
   userData: 
   assetBundleName: 
   assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/TestAssets/TestUniUnlit.mat b/Assets/External/VRM10/Tests/TestAssets/TestUniUnlit.mat
new file mode 100644
index 000000000..4f9469585
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUniUnlit.mat
@@ -0,0 +1,81 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: TestUniUnlit
+  m_Shader: {fileID: 4800000, guid: 8c17b56f4bf084c47872edcb95237e4a, type: 3}
+  m_ShaderKeywords: _ALPHATEST_ON
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: 2450
+  stringTagMap:
+    RenderType: TransparentCutout
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 0, y: 0}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BlendMode: 1
+    - _BumpScale: 1
+    - _CullMode: 0
+    - _Cutoff: 0.3
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _VColBlendMode: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 0.8301887, g: 0.25845498, b: 0.25845498, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/Assets/External/UniGLTF/Samples/UniHumanoid/target.mat.meta b/Assets/External/VRM10/Tests/TestAssets/TestUniUnlit.mat.meta
similarity index 64%
rename from Assets/External/UniGLTF/Samples/UniHumanoid/target.mat.meta
rename to Assets/External/VRM10/Tests/TestAssets/TestUniUnlit.mat.meta
index 133fed931..00d13a418 100644
--- a/Assets/External/UniGLTF/Samples/UniHumanoid/target.mat.meta
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUniUnlit.mat.meta
@@ -1,8 +1,8 @@
 fileFormatVersion: 2
-guid: 94b4b45712e88334c9e7c5ecc53c50e6
+guid: 9f4a2b6e842dd8e419d0440cbb3f272d
 NativeFormatImporter:
   externalObjects: {}
-  mainObjectFileID: 2100000
+  mainObjectFileID: 0
   userData: 
   assetBundleName: 
   assetBundleVariant: 
diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/a.mat b/Assets/External/VRM10/Tests/TestAssets/TestUnlitColor.mat
similarity index 90%
rename from Assets/External/UniGLTF/Samples/ScreenSpace/a.mat
rename to Assets/External/VRM10/Tests/TestAssets/TestUnlitColor.mat
index 3d0106f8f..94c0cbf4b 100644
--- a/Assets/External/UniGLTF/Samples/ScreenSpace/a.mat
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUnlitColor.mat
@@ -7,8 +7,8 @@ Material:
   m_CorrespondingSourceObject: {fileID: 0}
   m_PrefabInstance: {fileID: 0}
   m_PrefabAsset: {fileID: 0}
-  m_Name: a
-  m_Shader: {fileID: 4800000, guid: 1480dc3335b60e24fac1c62736559733, type: 3}
+  m_Name: TestUnlitColor
+  m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
   m_ShaderKeywords: 
   m_LightmapFlags: 4
   m_EnableInstancingVariants: 0
@@ -40,7 +40,7 @@ Material:
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     - _MainTex:
-        m_Texture: {fileID: 2800000, guid: c5d5d944a6503a348af34f68dfa868d4, type: 3}
+        m_Texture: {fileID: 0}
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     - _MetallicGlossMap:
@@ -56,7 +56,9 @@ Material:
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     m_Floats:
+    - _BlendMode: 0
     - _BumpScale: 1
+    - _CullMode: 2
     - _Cutoff: 0.5
     - _DetailNormalMapScale: 1
     - _DstBlend: 0
@@ -71,6 +73,7 @@ Material:
     - _SpecularHighlights: 1
     - _SrcBlend: 1
     - _UVSec: 0
+    - _VColBlendMode: 0
     - _ZWrite: 1
     m_Colors:
     - _Color: {r: 1, g: 1, b: 1, a: 1}
diff --git a/Assets/External/UniGLTF/Runtime/Resources/I-Pose.pose.asset.meta b/Assets/External/VRM10/Tests/TestAssets/TestUnlitColor.mat.meta
similarity index 64%
rename from Assets/External/UniGLTF/Runtime/Resources/I-Pose.pose.asset.meta
rename to Assets/External/VRM10/Tests/TestAssets/TestUnlitColor.mat.meta
index d6275c955..0cb79d341 100644
--- a/Assets/External/UniGLTF/Runtime/Resources/I-Pose.pose.asset.meta
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUnlitColor.mat.meta
@@ -1,8 +1,8 @@
 fileFormatVersion: 2
-guid: c4b8a69c9f45e384d92846d5b5081c1a
+guid: f7f4d0051179dea4abb0a5cc1e06868f
 NativeFormatImporter:
   externalObjects: {}
-  mainObjectFileID: 11400000
+  mainObjectFileID: 0
   userData: 
   assetBundleName: 
   assetBundleVariant: 
diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/b.mat b/Assets/External/VRM10/Tests/TestAssets/TestUnlitCutout.mat
similarity index 90%
rename from Assets/External/UniGLTF/Samples/ScreenSpace/b.mat
rename to Assets/External/VRM10/Tests/TestAssets/TestUnlitCutout.mat
index bde183f5b..b4e7b5296 100644
--- a/Assets/External/UniGLTF/Samples/ScreenSpace/b.mat
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUnlitCutout.mat
@@ -7,8 +7,8 @@ Material:
   m_CorrespondingSourceObject: {fileID: 0}
   m_PrefabInstance: {fileID: 0}
   m_PrefabAsset: {fileID: 0}
-  m_Name: b
-  m_Shader: {fileID: 4800000, guid: 1480dc3335b60e24fac1c62736559733, type: 3}
+  m_Name: TestUnlitCutout
+  m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
   m_ShaderKeywords: 
   m_LightmapFlags: 4
   m_EnableInstancingVariants: 0
@@ -40,7 +40,7 @@ Material:
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     - _MainTex:
-        m_Texture: {fileID: 2800000, guid: 6e9a09d0d9f0a894ab333e0ea709810e, type: 3}
+        m_Texture: {fileID: 0}
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     - _MetallicGlossMap:
@@ -56,7 +56,9 @@ Material:
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     m_Floats:
+    - _BlendMode: 0
     - _BumpScale: 1
+    - _CullMode: 2
     - _Cutoff: 0.5
     - _DetailNormalMapScale: 1
     - _DstBlend: 0
@@ -71,6 +73,7 @@ Material:
     - _SpecularHighlights: 1
     - _SrcBlend: 1
     - _UVSec: 0
+    - _VColBlendMode: 0
     - _ZWrite: 1
     m_Colors:
     - _Color: {r: 1, g: 1, b: 1, a: 1}
diff --git a/Assets/External/VRM10/Tests/TestAssets/TestUnlitCutout.mat.meta b/Assets/External/VRM10/Tests/TestAssets/TestUnlitCutout.mat.meta
new file mode 100644
index 000000000..48bd52a47
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUnlitCutout.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4fb31f9c7e0666b4bbfe0d6e3e8e147b
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/TestAssets/TestUnlitTexture.mat b/Assets/External/VRM10/Tests/TestAssets/TestUnlitTexture.mat
new file mode 100644
index 000000000..575b6cf64
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUnlitTexture.mat
@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: TestUnlitTexture
+  m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BlendMode: 0
+    - _BumpScale: 1
+    - _CullMode: 2
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _VColBlendMode: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/Assets/External/VRM10/Tests/TestAssets/TestUnlitTexture.mat.meta b/Assets/External/VRM10/Tests/TestAssets/TestUnlitTexture.mat.meta
new file mode 100644
index 000000000..c078c996f
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUnlitTexture.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 618c113d7622d0e4f9a08d1180ea4c18
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/TestAssets/TestUnlitTransparent.mat b/Assets/External/VRM10/Tests/TestAssets/TestUnlitTransparent.mat
new file mode 100644
index 000000000..bca08f422
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUnlitTransparent.mat
@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: TestUnlitTransparent
+  m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BlendMode: 0
+    - _BumpScale: 1
+    - _CullMode: 2
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _VColBlendMode: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/Assets/External/VRM10/Tests/TestAssets/TestUnlitTransparent.mat.meta b/Assets/External/VRM10/Tests/TestAssets/TestUnlitTransparent.mat.meta
new file mode 100644
index 000000000..d8d0201c5
--- /dev/null
+++ b/Assets/External/VRM10/Tests/TestAssets/TestUnlitTransparent.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ae4a2672b95a4b1469e195db2e3967ab
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/Tests/VRM10.Tests.asmdef b/Assets/External/VRM10/Tests/VRM10.Tests.asmdef
new file mode 100644
index 000000000..c045e954b
--- /dev/null
+++ b/Assets/External/VRM10/Tests/VRM10.Tests.asmdef
@@ -0,0 +1,27 @@
+{
+    "name": "VRM10.Tests",
+    "references": [
+        "GUID:2ef84b520212e174a94668c7a0862d3b",
+        "GUID:e47c917724578cc43b5506c17a27e9a0",
+        "GUID:8d76e605759c3f64a957d63ef96ada7c",
+        "GUID:da3e51d19d51a544fa14d43fee843098",
+        "GUID:7da8a75dcade2144aab699032d7d7987",
+        "GUID:27619889b8ba8c24980f49ee34dbb44a",
+        "GUID:0acc523941302664db1f4e527237feb3"
+    ],
+    "includePlatforms": [
+        "Editor"
+    ],
+    "excludePlatforms": [],
+    "allowUnsafeCode": false,
+    "overrideReferences": true,
+    "precompiledReferences": [
+        "nunit.framework.dll"
+    ],
+    "autoReferenced": false,
+    "defineConstraints": [
+        "UNITY_INCLUDE_TESTS"
+    ],
+    "versionDefines": [],
+    "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/Tests/VRM10.Tests.asmdef.meta b/Assets/External/VRM10/Tests/VRM10.Tests.asmdef.meta
new file mode 100644
index 000000000..f1c979f86
--- /dev/null
+++ b/Assets/External/VRM10/Tests/VRM10.Tests.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 095fd7f56eebd62498fdadd5a60ed11b
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/package.json b/Assets/External/VRM10/package.json
new file mode 100644
index 000000000..8dd8388b8
--- /dev/null
+++ b/Assets/External/VRM10/package.json
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:509c9eb20cd550530a9d3a03c1d949e356590424992a58aab10003367258407e
+size 685
diff --git a/Assets/External/VRM10/package.json.meta b/Assets/External/VRM10/package.json.meta
new file mode 100644
index 000000000..f5a5576f2
--- /dev/null
+++ b/Assets/External/VRM10/package.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: c54b3fc67ad3e4a498b3edc13e695bd7
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib.meta b/Assets/External/VRM10/vrmlib.meta
new file mode 100644
index 000000000..be3114e95
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b19bf01847aebbb4c919173b7da4dc23
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/README.md b/Assets/External/VRM10/vrmlib/README.md
new file mode 100644
index 000000000..424e5dc73
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/README.md
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:22ed0b51f05804d053005f12ed34fd323c27d438a5a89b591517ff1107af5c32
+size 38
diff --git a/Assets/External/VRM10/vrmlib/README.md.meta b/Assets/External/VRM10/vrmlib/README.md.meta
new file mode 100644
index 000000000..92385aaf4
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/README.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ada41fcec802ec7418eb2d39939fc9f5
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime.meta b/Assets/External/VRM10/vrmlib/Runtime.meta
new file mode 100644
index 000000000..6d0185ab2
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1cc5482841b076d469e32bef81ef4056
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Coordinates.cs b/Assets/External/VRM10/vrmlib/Runtime/Coordinates.cs
new file mode 100644
index 000000000..575d3c64e
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Coordinates.cs
@@ -0,0 +1,55 @@
+namespace VrmLib
+{
+    public enum GeometryCoordinates
+    {
+        Unknown,
+
+        /// VRM-0
+        XYZ_RightUpBack_RH,
+
+        /// VRM-1
+        XYZ_RightUpForward_RH,
+
+        /// D3D standard(Unity)
+        XYZ_RightUpForward_LH,
+    }
+
+    public enum TextureOrigin
+    {
+        Unknown,
+
+        // GLTF
+        LeftTop,
+
+        // Unity
+        LeftBottom,
+    }
+
+    public struct Coordinates
+    {
+        public GeometryCoordinates Geometry;
+        public TextureOrigin Texture;
+
+        public static Coordinates Vrm0 => new Coordinates
+        {
+            Geometry = GeometryCoordinates.XYZ_RightUpBack_RH,
+            Texture = TextureOrigin.LeftTop,
+        };
+        public bool IsVrm0 => this.Equals(Vrm0);
+
+        public static Coordinates Vrm1 => new Coordinates
+        {
+            Geometry = GeometryCoordinates.XYZ_RightUpForward_RH,
+            Texture = TextureOrigin.LeftTop,
+        };
+        public bool IsVrm1 => this.Equals(Vrm1);
+
+        public static Coordinates Unity => new Coordinates
+        {
+            Geometry = GeometryCoordinates.XYZ_RightUpForward_LH,
+            Texture = TextureOrigin.LeftBottom,
+        };
+
+        public bool IsUnity => this.Equals(Unity);
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Coordinates.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Coordinates.cs.meta
new file mode 100644
index 000000000..851eb4f7b
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Coordinates.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 77774615c3e654941bfbbe546cba08b5
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/ExportArgs.cs b/Assets/External/VRM10/vrmlib/Runtime/ExportArgs.cs
new file mode 100644
index 000000000..b700666c2
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/ExportArgs.cs
@@ -0,0 +1,81 @@
+using System;
+
+namespace VrmLib
+{
+    [Serializable]
+    public struct ExportArgs
+    {
+        /// 
+        /// 頂点バッファにsparse機能を使うか
+        ///
+        /// struct で初期値をdefault以外にするために
+        /// nullableなpropertyを使っている
+        /// 
+        bool? m_sparse;
+
+        public bool sparse
+        {
+            get
+            {
+                if (!m_sparse.HasValue)
+                {
+                    m_sparse = true;
+                }
+                return m_sparse.Value;
+            }
+            set
+            {
+                m_sparse = value;
+            }
+        }
+
+        /// 
+        /// エクスポート時にmorphTargetから法線を削除するか
+        ///
+        /// struct で初期値をdefault以外にするために
+        /// nullableなpropertyを使っている
+        /// 
+        bool? m_remove_morph_normal;
+
+        public bool removeMorphNormal
+        {
+            get
+            {
+                if (!m_remove_morph_normal.HasValue)
+                {
+                    // TODO: Importerの修正が取り込まれたらtrueにする
+                    m_remove_morph_normal = false;
+                }
+                return m_remove_morph_normal.Value;
+            }
+            set
+            {
+                m_remove_morph_normal = value;
+            }
+        }
+
+        /// 
+        /// エクスポート時にtangentを削除するか
+        ///
+        /// struct で初期値をdefault以外にするために
+        /// nullableなpropertyを使っている
+        /// 
+        bool? m_remove_tangent;
+
+        public bool removeTangent
+        {
+            get
+            {
+                if (!m_remove_tangent.HasValue)
+                {
+                    m_remove_tangent = true;
+                }
+                return m_remove_tangent.Value;
+            }
+            set
+            {
+                m_remove_tangent = value;
+            }
+        }
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/ExportArgs.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/ExportArgs.cs.meta
new file mode 100644
index 000000000..3923b5125
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/ExportArgs.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f4cd67059531eda4e9aa740ba07e8204
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Extensions.meta b/Assets/External/VRM10/vrmlib/Runtime/Extensions.meta
new file mode 100644
index 000000000..04cd2e335
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Extensions.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: cfb8b86e925ee9d46bdb4409d91e96b4
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Extensions/ListExtensions.cs b/Assets/External/VRM10/vrmlib/Runtime/Extensions/ListExtensions.cs
new file mode 100644
index 000000000..fe23d84d7
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Extensions/ListExtensions.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+
+namespace VrmLib
+{
+    public static class ListExtensions
+    {
+        public static int IndexOfThrow(this List list, T target)
+        {
+            var index = list.IndexOf(target);
+            if (index == -1)
+            {
+                throw new KeyNotFoundException();
+            }
+            return index;
+        }
+
+        public static int? IndexOfNullable(this List list, T target)
+        {
+            var index = list.IndexOf(target);
+            if (index == -1)
+            {
+                return default;
+            }
+            return index;
+        }
+     }
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Extensions/ListExtensions.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Extensions/ListExtensions.cs.meta
new file mode 100644
index 000000000..7e9faf8b7
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Extensions/ListExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cb448ffdf669ef74c84625b12fa691de
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/GltfId.cs b/Assets/External/VRM10/vrmlib/Runtime/GltfId.cs
new file mode 100644
index 000000000..163d776ed
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/GltfId.cs
@@ -0,0 +1,22 @@
+namespace VrmLib
+{
+    /// 
+    /// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/schema/glTFid.schema.json
+    ///
+    /// ImportとExportでなるべく順番を維持するべく導入。下記のベースクラスとした
+    ///
+    /// * Image, Texture, Material
+    /// * Animation
+    /// * Node, Skin, Mesh
+    ///
+    /// 
+    public class GltfId
+    {
+        public int? GltfIndex;
+
+        /// 
+        /// 未指定は後ろに送る
+        /// 
+        public int SortOrder => GltfIndex.GetValueOrDefault(int.MaxValue);
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/GltfId.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/GltfId.cs.meta
new file mode 100644
index 000000000..1fb899220
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/GltfId.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 94bf75bb38754154592dec46de49410b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid.meta b/Assets/External/VRM10/vrmlib/Runtime/Humanoid.meta
new file mode 100644
index 000000000..a04e05a34
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0d05c6ea4a073fc49b7f5b47373def99
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid/Humanoid.cs b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/Humanoid.cs
new file mode 100644
index 000000000..332a5c9bf
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/Humanoid.cs
@@ -0,0 +1,519 @@
+using System;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+using UniGLTF.Utils;
+using UnityEngine;
+
+
+/// 
+/// * 胴体: hips, spine, chest, upperChest, neck, head => 6
+/// * 腕: shoulder, upperArm, lowerArm, hand => 4 x 2
+/// * 脚: upperLeg, lowerLeg, foot, toes => 4 x 2
+///     = 22
+/// * 指: proximal, inetermediate, distal => 3 x 5 x 2 = 30
+/// 
+namespace VrmLib
+{
+    public struct HumanoidHead
+    {
+        // required
+        public Node Head;
+        public Node Jaw;
+        public Node LeftEye;
+        public Node RightEye;
+
+        public bool HasRequiredBones => Head != null;
+    };
+
+    public struct HumanoidArm
+    {
+        public Node Shoulder;
+        // required
+        public Node Upper;
+        // required
+        public Node Lower;
+        // required
+        public Node Hand;
+
+        public bool HasRequiredBones => Upper != null && Lower != null && Hand != null;
+
+        public Vector3 Direction
+        {
+            get
+            {
+                if (Shoulder != null)
+                {
+                    return Vector3.Normalize(Hand.Translation - Shoulder.Translation);
+                }
+                else
+                {
+                    return Vector3.Normalize(Hand.Translation - Upper.Translation);
+                }
+            }
+        }
+
+        public void DirectTo(Vector3 dir)
+        {
+            if (Shoulder != null)
+            {
+                Shoulder.RotateFromTo(Upper.Translation - Shoulder.Translation, dir);
+            }
+            Upper.RotateFromTo(Lower.Translation - Upper.Translation, dir);
+            Lower.RotateFromTo(Hand.Translation - Lower.Translation, dir);
+        }
+    };
+
+    public struct HumanoidLeg
+    {
+        public Node Upper;
+        public Node Lower;
+        public Node Foot;
+        public Node Toe;
+    };
+
+    struct HumanoidFinger
+    {
+        public Node Proximal;
+        public Node Intermediate;
+        public Node Distal;
+    }
+
+    struct HumanoidThumb
+    {
+        public Node Metacarpal;
+        public Node Proximal;
+        public Node Distal;
+    }
+
+
+    struct HumanoidFingers
+    {
+        public HumanoidThumb Thumb;
+        public HumanoidFinger Index;
+        public HumanoidFinger Middle;
+        public HumanoidFinger Ring;
+        public HumanoidFinger Little;
+    };
+
+    /// 
+    /// ヒューマノイドの姿勢を制御する
+    /// 
+    public class Humanoid : IDictionary
+    {
+        public Node Hips;
+        public Node Spine;
+        public Node Chest;
+        public Node UpperChest;
+        public Node Neck;
+
+        HumanoidHead Head;
+
+        HumanoidArm LeftArm;
+        HumanoidFingers LeftFingers;
+
+        HumanoidArm RightArm;
+        HumanoidFingers RightFingers;
+
+        HumanoidLeg LeftLeg;
+        HumanoidLeg RightLeg;
+
+        public bool HasRequiredBones
+        {
+            get
+            {
+                if (Hips == null) return false;
+                if (Spine == null) return false;
+                if (!Head.HasRequiredBones) return false;
+                if (!LeftArm.HasRequiredBones) return false;
+                if (!RightArm.HasRequiredBones) return false;
+
+                // TODO
+                return true;
+            }
+        }
+
+        ICollection IDictionary.Keys => throw new System.NotImplementedException();
+
+        ICollection IDictionary.Values => throw new System.NotImplementedException();
+
+        int ICollection>.Count => this.Select(_ => _).Count();
+
+        bool ICollection>.IsReadOnly => throw new System.NotImplementedException();
+
+        Node IDictionary.this[HumanoidBones key] { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
+
+        public Humanoid()
+        {
+        }
+
+        public Humanoid(Node root)
+        {
+            Assign(root);
+        }
+
+        public void Assign(Node root)
+        {
+            foreach (var node in root.Traverse())
+            {
+                if (node.HumanoidBone.HasValue)
+                {
+                    Add(node.HumanoidBone.Value, node);
+                }
+            }
+        }
+
+        void CopyTraverse(Node src, Node dst)
+        {
+            dst.HumanoidBone = src.HumanoidBone;
+            dst.LocalScaling = src.LocalScaling;
+            dst.LocalRotation = src.LocalRotation;
+            dst.LocalTranslation = src.LocalTranslation;
+            foreach (var child in src.Children)
+            {
+                var dstChild = new Node(child.Name /*+ ".copy"*/);
+                dst.Add(dstChild);
+                CopyTraverse(child, dstChild);
+            }
+        }
+
+        public Humanoid CopyNodes()
+        {
+            // ヒエラルキーのコピーを作成する
+            var hips = new Node(Hips.Name /*+ ".copy"*/);
+            CopyTraverse(Hips, hips);
+
+            var humanoid = new Humanoid(hips);
+            return humanoid;
+        }
+
+        // Y軸180度回転
+        public (bool, string) Y180()
+        {
+            var sb = new System.Text.StringBuilder();
+            Hips.LocalRotation = Quaternion.Euler(0, MathFWrap.PI, 0);
+            Hips.CalcWorldMatrix();
+            return (true, sb.ToString());
+        }
+
+        /// 
+        /// 上半身のTPose
+        /// 
+        public (bool, string) MakeTPose()
+        {
+            var sb = new System.Text.StringBuilder();
+            bool modified = false;
+
+            // hipsのforward を -Z に向ける
+            // hipsのforward は (left.leg - right.leg) cross (0, 1, 0)
+            var left = Vector3.Normalize(LeftLeg.Upper.Translation - RightLeg.Upper.Translation);
+            var forward = Vector3.Cross(left, Vector3.up);
+            if (Vector3.Dot(forward, -Vector3.forward) < 1.0f - 0.1f)
+            {
+                Hips.RotateFromTo(forward, -Vector3.forward);
+                modified = true;
+            }
+
+            if (Vector3.Dot(LeftArm.Direction, -Vector3.right) < 1.0f - 0.1f)
+            {
+                LeftArm.DirectTo(-Vector3.right);
+                sb.Append("(fix left arm)");
+                modified = true;
+            }
+            if (Vector3.Dot(RightArm.Direction, Vector3.right) < 1.0f - 0.1f)
+            {
+                RightArm.DirectTo(Vector3.right);
+                sb.Append("(fix right arm)");
+                modified = true;
+            }
+
+            Hips.CalcWorldMatrix();
+            return (modified, sb.ToString());
+        }
+
+        public void RetargetTo(Humanoid srcTPose, Humanoid dst)
+        {
+            foreach (var kv in this)
+            {
+                var tposeNode = srcTPose[kv.Key];
+                if (dst.TryGetValue(kv.Key, out Node node))
+                {
+                    // var t = tposeNode.LocalRotation;
+                    // var t = Quaternion.identity;
+                    // node.LocalRotationWithoutUpdate = Quaternion.Inverse(t) * kv.Value.LocalRotation;
+                    // node.LocalRotationWithoutUpdate = kv.Value.LocalRotation * Quaternion.Inverse(t);
+
+                    var t = tposeNode.Rotation;
+                    // node.Rotation = Quaternion.Inverse(t) * kv.Value.Rotation;
+                    node.Rotation = kv.Value.Rotation * Quaternion.Inverse(t);
+                    // node.LocalRotationWithoutUpdate = kv.Value.LocalRotation * Quaternion.Inverse(t);
+                }
+                else
+                {
+                    Console.WriteLine($"{kv.Key} not found");
+                }
+            }
+            dst.Hips.CalcWorldMatrix();
+        }
+
+        #region interface
+        public void Add(KeyValuePair item)
+        {
+            Add(item.Key, item.Value);
+        }
+
+        public void Add(HumanoidBones key, Node node)
+        {
+            if (key == HumanoidBones.unknown)
+            {
+                throw new ArgumentException();
+            }
+
+            node.HumanoidBone = key;
+
+            switch (node.HumanoidBone.Value)
+            {
+                case HumanoidBones.hips: Hips = node; break;
+                case HumanoidBones.spine: Spine = node; break;
+                case HumanoidBones.chest: Chest = node; break;
+                case HumanoidBones.upperChest: UpperChest = node; break;
+                case HumanoidBones.neck: Neck = node; break;
+                case HumanoidBones.head: Head.Head = node; break;
+                case HumanoidBones.jaw: Head.Jaw = node; break;
+                case HumanoidBones.leftEye: Head.LeftEye = node; break;
+                case HumanoidBones.rightEye: Head.RightEye = node; break;
+
+                case HumanoidBones.leftShoulder: LeftArm.Shoulder = node; break;
+                case HumanoidBones.leftUpperArm: LeftArm.Upper = node; break;
+                case HumanoidBones.leftLowerArm: LeftArm.Lower = node; break;
+                case HumanoidBones.leftHand: LeftArm.Hand = node; break;
+
+                case HumanoidBones.rightShoulder: RightArm.Shoulder = node; break;
+                case HumanoidBones.rightUpperArm: RightArm.Upper = node; break;
+                case HumanoidBones.rightLowerArm: RightArm.Lower = node; break;
+                case HumanoidBones.rightHand: RightArm.Hand = node; break;
+
+                case HumanoidBones.leftUpperLeg: LeftLeg.Upper = node; break;
+                case HumanoidBones.leftLowerLeg: LeftLeg.Lower = node; break;
+                case HumanoidBones.leftFoot: LeftLeg.Foot = node; break;
+                case HumanoidBones.leftToes: LeftLeg.Toe = node; break;
+
+                case HumanoidBones.rightUpperLeg: RightLeg.Upper = node; break;
+                case HumanoidBones.rightLowerLeg: RightLeg.Lower = node; break;
+                case HumanoidBones.rightFoot: RightLeg.Foot = node; break;
+                case HumanoidBones.rightToes: RightLeg.Toe = node; break;
+
+                case HumanoidBones.leftThumbMetacarpal: LeftFingers.Thumb.Metacarpal = node; break;
+                case HumanoidBones.leftThumbProximal: LeftFingers.Thumb.Proximal = node; break;
+                case HumanoidBones.leftThumbDistal: LeftFingers.Thumb.Distal = node; break;
+                case HumanoidBones.leftIndexProximal: LeftFingers.Index.Proximal = node; break;
+                case HumanoidBones.leftIndexIntermediate: LeftFingers.Index.Intermediate = node; break;
+                case HumanoidBones.leftIndexDistal: LeftFingers.Index.Distal = node; break;
+                case HumanoidBones.leftMiddleProximal: LeftFingers.Middle.Proximal = node; break;
+                case HumanoidBones.leftMiddleIntermediate: LeftFingers.Middle.Intermediate = node; break;
+                case HumanoidBones.leftMiddleDistal: LeftFingers.Middle.Distal = node; break;
+                case HumanoidBones.leftRingProximal: LeftFingers.Ring.Proximal = node; break;
+                case HumanoidBones.leftRingIntermediate: LeftFingers.Ring.Intermediate = node; break;
+                case HumanoidBones.leftRingDistal: LeftFingers.Ring.Distal = node; break;
+                case HumanoidBones.leftLittleProximal: LeftFingers.Little.Proximal = node; break;
+                case HumanoidBones.leftLittleIntermediate: LeftFingers.Little.Intermediate = node; break;
+                case HumanoidBones.leftLittleDistal: LeftFingers.Little.Distal = node; break;
+
+                case HumanoidBones.rightThumbMetacarpal: RightFingers.Thumb.Metacarpal = node; break;
+                case HumanoidBones.rightThumbProximal: RightFingers.Thumb.Proximal = node; break;
+                case HumanoidBones.rightThumbDistal: RightFingers.Thumb.Distal = node; break;
+                case HumanoidBones.rightIndexProximal: RightFingers.Index.Proximal = node; break;
+                case HumanoidBones.rightIndexIntermediate: RightFingers.Index.Intermediate = node; break;
+                case HumanoidBones.rightIndexDistal: RightFingers.Index.Distal = node; break;
+                case HumanoidBones.rightMiddleProximal: RightFingers.Middle.Proximal = node; break;
+                case HumanoidBones.rightMiddleIntermediate: RightFingers.Middle.Intermediate = node; break;
+                case HumanoidBones.rightMiddleDistal: RightFingers.Middle.Distal = node; break;
+                case HumanoidBones.rightRingProximal: RightFingers.Ring.Proximal = node; break;
+                case HumanoidBones.rightRingIntermediate: RightFingers.Ring.Intermediate = node; break;
+                case HumanoidBones.rightRingDistal: RightFingers.Ring.Distal = node; break;
+                case HumanoidBones.rightLittleProximal: RightFingers.Little.Proximal = node; break;
+                case HumanoidBones.rightLittleIntermediate: RightFingers.Little.Intermediate = node; break;
+                case HumanoidBones.rightLittleDistal: RightFingers.Little.Distal = node; break;
+
+                default: throw new NotImplementedException();
+            }
+        }
+
+        public bool ContainsKey(HumanoidBones key)
+        {
+            return TryGetValue(key, out Node _);
+        }
+
+        public bool Remove(HumanoidBones key)
+        {
+            if (!ContainsKey(key))
+            {
+                return false;
+            }
+            Add(key, null);
+            return true;
+        }
+
+        public Node this[HumanoidBones key]
+        {
+            get
+            {
+                if (TryGetValue(key, out Node node))
+                {
+                    return node;
+                }
+                else
+                {
+                    throw new KeyNotFoundException();
+                }
+            }
+        }
+
+        public Node this[Node node]
+        {
+            get
+            {
+                if (node.HumanoidBone.HasValue && node.HumanoidBone.Value != HumanoidBones.unknown)
+                {
+                    return this[node.HumanoidBone.Value];
+                }
+                else
+                {
+                    // とりあえず
+                    return Hips.Traverse().First(x => x.Name == node.Name);
+                }
+            }
+        }
+
+        public bool TryGetValue(HumanoidBones key, out Node value)
+        {
+            switch (key)
+            {
+                case HumanoidBones.hips: value = Hips; return true;
+                case HumanoidBones.spine: value = Spine; return true;
+                case HumanoidBones.chest: value = Chest; return true;
+                case HumanoidBones.upperChest: value = UpperChest; return true;
+                case HumanoidBones.neck: value = Neck; return true;
+                case HumanoidBones.head: value = Head.Head; return true;
+                case HumanoidBones.jaw: value = Head.Jaw; return true;
+                case HumanoidBones.leftEye: value = Head.LeftEye; return true;
+                case HumanoidBones.rightEye: value = Head.RightEye; return true;
+
+                case HumanoidBones.leftShoulder: value = LeftArm.Shoulder; return true;
+                case HumanoidBones.leftUpperArm: value = LeftArm.Upper; return true;
+                case HumanoidBones.leftLowerArm: value = LeftArm.Lower; return true;
+                case HumanoidBones.leftHand: value = LeftArm.Hand; return true;
+
+                case HumanoidBones.rightShoulder: value = RightArm.Shoulder; return true;
+                case HumanoidBones.rightUpperArm: value = RightArm.Upper; return true;
+                case HumanoidBones.rightLowerArm: value = RightArm.Lower; return true;
+                case HumanoidBones.rightHand: value = RightArm.Hand; return true;
+
+                case HumanoidBones.leftUpperLeg: value = LeftLeg.Upper; return true;
+                case HumanoidBones.leftLowerLeg: value = LeftLeg.Lower; return true;
+                case HumanoidBones.leftFoot: value = LeftLeg.Foot; return true;
+                case HumanoidBones.leftToes: value = LeftLeg.Toe; return true;
+
+                case HumanoidBones.rightUpperLeg: value = RightLeg.Upper; return true;
+                case HumanoidBones.rightLowerLeg: value = RightLeg.Lower; return true;
+                case HumanoidBones.rightFoot: value = RightLeg.Foot; return true;
+                case HumanoidBones.rightToes: value = RightLeg.Toe; return true;
+
+                case HumanoidBones.leftThumbMetacarpal: value = LeftFingers.Thumb.Metacarpal; return true;
+                case HumanoidBones.leftThumbProximal: value = LeftFingers.Thumb.Proximal; return true;
+                case HumanoidBones.leftThumbDistal: value = LeftFingers.Thumb.Distal; return true;
+                case HumanoidBones.leftIndexProximal: value = LeftFingers.Index.Proximal; return true;
+                case HumanoidBones.leftIndexIntermediate: value = LeftFingers.Index.Intermediate; return true;
+                case HumanoidBones.leftIndexDistal: value = LeftFingers.Index.Distal; return true;
+                case HumanoidBones.leftMiddleProximal: value = LeftFingers.Middle.Proximal; return true;
+                case HumanoidBones.leftMiddleIntermediate: value = LeftFingers.Middle.Intermediate; return true;
+                case HumanoidBones.leftMiddleDistal: value = LeftFingers.Middle.Distal; return true;
+                case HumanoidBones.leftRingProximal: value = LeftFingers.Ring.Proximal; return true;
+                case HumanoidBones.leftRingIntermediate: value = LeftFingers.Ring.Intermediate; return true;
+                case HumanoidBones.leftRingDistal: value = LeftFingers.Ring.Distal; return true;
+                case HumanoidBones.leftLittleProximal: value = LeftFingers.Little.Proximal; return true;
+                case HumanoidBones.leftLittleIntermediate: value = LeftFingers.Little.Intermediate; return true;
+                case HumanoidBones.leftLittleDistal: value = LeftFingers.Little.Distal; return true;
+
+                case HumanoidBones.rightThumbProximal: value = LeftFingers.Thumb.Proximal; return true;
+                case HumanoidBones.rightThumbMetacarpal: value = LeftFingers.Thumb.Metacarpal; return true;
+                case HumanoidBones.rightThumbDistal: value = LeftFingers.Thumb.Distal; return true;
+                case HumanoidBones.rightIndexProximal: value = LeftFingers.Index.Proximal; return true;
+                case HumanoidBones.rightIndexIntermediate: value = LeftFingers.Index.Intermediate; return true;
+                case HumanoidBones.rightIndexDistal: value = LeftFingers.Index.Distal; return true;
+                case HumanoidBones.rightMiddleProximal: value = LeftFingers.Middle.Proximal; return true;
+                case HumanoidBones.rightMiddleIntermediate: value = LeftFingers.Middle.Intermediate; return true;
+                case HumanoidBones.rightMiddleDistal: value = LeftFingers.Middle.Distal; return true;
+                case HumanoidBones.rightRingProximal: value = LeftFingers.Ring.Proximal; return true;
+                case HumanoidBones.rightRingIntermediate: value = LeftFingers.Ring.Intermediate; return true;
+                case HumanoidBones.rightRingDistal: value = LeftFingers.Ring.Distal; return true;
+                case HumanoidBones.rightLittleProximal: value = LeftFingers.Little.Proximal; return true;
+                case HumanoidBones.rightLittleIntermediate: value = LeftFingers.Little.Intermediate; return true;
+                case HumanoidBones.rightLittleDistal: value = LeftFingers.Little.Distal; return true;
+            }
+
+            value = null;
+            return false;
+        }
+
+        public void Clear()
+        {
+            foreach (HumanoidBones key in CachedEnum.GetValues())
+            {
+                Add(key, null);
+            }
+        }
+
+        public IEnumerator> GetEnumerator()
+        {
+            if (Hips != null) yield return new KeyValuePair(HumanoidBones.hips, Hips);
+            if (Spine != null) yield return new KeyValuePair(HumanoidBones.spine, Spine);
+            if (Chest != null) yield return new KeyValuePair(HumanoidBones.chest, Chest);
+            if (UpperChest != null) yield return new KeyValuePair(HumanoidBones.upperChest, UpperChest);
+            if (Neck != null) yield return new KeyValuePair(HumanoidBones.neck, Neck);
+            if (Head.Head != null) yield return new KeyValuePair(HumanoidBones.head, Head.Head);
+
+            if (LeftArm.Shoulder != null) yield return new KeyValuePair(HumanoidBones.leftShoulder, LeftArm.Shoulder);
+            if (LeftArm.Upper != null) yield return new KeyValuePair(HumanoidBones.leftUpperArm, LeftArm.Upper);
+            if (LeftArm.Lower != null) yield return new KeyValuePair(HumanoidBones.leftLowerArm, LeftArm.Lower);
+            if (LeftArm.Hand != null) yield return new KeyValuePair(HumanoidBones.leftHand, LeftArm.Hand);
+
+            if (RightArm.Shoulder != null) yield return new KeyValuePair(HumanoidBones.rightShoulder, RightArm.Shoulder);
+            if (RightArm.Upper != null) yield return new KeyValuePair(HumanoidBones.rightUpperArm, RightArm.Upper);
+            if (RightArm.Lower != null) yield return new KeyValuePair(HumanoidBones.rightLowerArm, RightArm.Lower);
+            if (RightArm.Hand != null) yield return new KeyValuePair(HumanoidBones.rightHand, RightArm.Hand);
+
+            if (LeftLeg.Upper != null) yield return new KeyValuePair(HumanoidBones.leftUpperLeg, LeftLeg.Upper);
+            if (LeftLeg.Lower != null) yield return new KeyValuePair(HumanoidBones.leftLowerLeg, LeftLeg.Lower);
+            if (LeftLeg.Foot != null) yield return new KeyValuePair(HumanoidBones.leftFoot, LeftLeg.Foot);
+
+            if (RightLeg.Upper != null) yield return new KeyValuePair(HumanoidBones.rightUpperLeg, RightLeg.Upper);
+            if (RightLeg.Lower != null) yield return new KeyValuePair(HumanoidBones.rightLowerLeg, RightLeg.Lower);
+            if (RightLeg.Foot != null) yield return new KeyValuePair(HumanoidBones.rightFoot, RightLeg.Foot);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        #region NotImplement
+        bool ICollection>.Contains(KeyValuePair item)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        bool ICollection>.Remove(KeyValuePair item)
+        {
+            throw new System.NotImplementedException();
+        }
+        #endregion
+
+        #endregion
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid/Humanoid.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/Humanoid.cs.meta
new file mode 100644
index 000000000..e85ea96b6
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/Humanoid.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 95f837b865335a34fb1bcd7d057fbabc
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid/HumanoidBones.cs b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/HumanoidBones.cs
new file mode 100644
index 000000000..43be66f0c
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/HumanoidBones.cs
@@ -0,0 +1,105 @@
+using System;
+
+namespace VrmLib
+{
+    /// 
+    /// Required for skeleton.
+    /// 15 bones.
+    /// 
+    public class BoneRequiredAttribute : Attribute
+    {
+    }
+
+    /// 
+    /// hips -> spine -> (chest) -> (heck) -> head: Y+
+    /// 
+    public enum HumanoidBones
+    {
+        unknown,
+
+        [BoneRequired]
+        hips,
+
+        #region leg
+        [BoneRequired]
+        leftUpperLeg,
+        [BoneRequired]
+        rightUpperLeg,
+        [BoneRequired]
+        leftLowerLeg,
+        [BoneRequired]
+        rightLowerLeg,
+        [BoneRequired]
+        leftFoot,
+        [BoneRequired]
+        rightFoot,
+        #endregion
+
+        #region spine
+        [BoneRequired]
+        spine,
+        chest,
+        neck,
+        [BoneRequired]
+        head,
+        #endregion
+
+        #region arm
+        leftShoulder,
+        rightShoulder,
+        [BoneRequired]
+        leftUpperArm,
+        [BoneRequired]
+        rightUpperArm,
+        [BoneRequired]
+        leftLowerArm,
+        [BoneRequired]
+        rightLowerArm,
+        [BoneRequired]
+        leftHand,
+        [BoneRequired]
+        rightHand,
+        #endregion
+
+        leftToes,
+        rightToes,
+        leftEye,
+        rightEye,
+        jaw,
+
+        #region fingers
+        leftThumbMetacarpal,
+        leftThumbProximal,
+        leftThumbDistal,
+        leftIndexProximal,
+        leftIndexIntermediate,
+        leftIndexDistal,
+        leftMiddleProximal,
+        leftMiddleIntermediate,
+        leftMiddleDistal,
+        leftRingProximal,
+        leftRingIntermediate,
+        leftRingDistal,
+        leftLittleProximal,
+        leftLittleIntermediate,
+        leftLittleDistal,
+        rightThumbMetacarpal,
+        rightThumbProximal,
+        rightThumbDistal,
+        rightIndexProximal,
+        rightIndexIntermediate,
+        rightIndexDistal,
+        rightMiddleProximal,
+        rightMiddleIntermediate,
+        rightMiddleDistal,
+        rightRingProximal,
+        rightRingIntermediate,
+        rightRingDistal,
+        rightLittleProximal,
+        rightLittleIntermediate,
+        rightLittleDistal,
+        #endregion
+
+        upperChest,
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid/HumanoidBones.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/HumanoidBones.cs.meta
new file mode 100644
index 000000000..ff41d2822
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/HumanoidBones.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dd11adf32300d3e4d8a51e126b88ee8d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonEstimator.cs b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonEstimator.cs
new file mode 100644
index 000000000..6303a93b3
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonEstimator.cs
@@ -0,0 +1,434 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace VrmLib
+{
+    public static class SkeletonEstimator
+    {
+        static Node GetRoot(IReadOnlyList bones)
+        {
+            var hips = bones.Where(x => x.Parent == null).ToArray();
+            if (hips.Length != 1)
+            {
+                throw new System.Exception("Require unique root");
+            }
+            return hips[0];
+        }
+
+        static Node SelectBone(Func pred, Node parent)
+        {
+            var bones = parent.Children;
+            if (bones == null || bones.Count == 0) throw new Exception("no bones");
+            foreach (var bone in bones)
+            {
+                if (pred(bone, parent))
+                {
+                    return bone;
+                }
+            }
+
+            throw new Exception("not found");
+        }
+
+        static void GetSpineAndHips(Node hips, out Node spine, out Node leg_L, out Node leg_R)
+        {
+            if (hips.Children.Count != 3) throw new System.Exception("Hips require 3 children");
+            spine = SelectBone((l, r) => l.CenterOfDescendant().y > r.SkeletonLocalPosition.y, hips);
+            var s = spine;
+            try
+            {
+                leg_L = SelectBone((l, r) => !l.Equals(s) && l.CenterOfDescendant().x < r.SkeletonLocalPosition.x, hips);
+                leg_R = SelectBone((l, r) => !l.Equals(s) && l.CenterOfDescendant().x > r.SkeletonLocalPosition.x, hips);
+            }
+            catch (Exception)
+            {
+                // Z軸で左右を代用
+                leg_L = SelectBone((l, r) => !l.Equals(s) && l.CenterOfDescendant().z < r.SkeletonLocalPosition.z, hips);
+                leg_R = SelectBone((l, r) => !l.Equals(s) && l.CenterOfDescendant().z > r.SkeletonLocalPosition.z, hips);
+            }
+        }
+
+        static void GetNeckAndArms(Node chest, out Node neck, out Node arm_L, out Node arm_R, Func isLeft)
+        {
+            if (chest.Children.Count != 3) throw new System.Exception("Chest require 3 children");
+            neck = SelectBone((l, r) => l.CenterOfDescendant().y > r.SkeletonLocalPosition.y, chest);
+            var n = neck;
+            arm_L = SelectBone((l, r) => !l.Equals(n) && isLeft(l.CenterOfDescendant(), r.SkeletonLocalPosition), chest);
+            arm_R = SelectBone((l, r) => !l.Equals(n) && !isLeft(l.CenterOfDescendant(), r.SkeletonLocalPosition), chest);
+        }
+
+        struct Arm
+        {
+            public Node Shoulder;
+            public Node UpperArm;
+            public Node LowerArm;
+            public Node Hand;
+        }
+
+        static Arm GetArm(Node shoulder)
+        {
+            var bones = shoulder.Traverse().ToArray();
+            switch (bones.Length)
+            {
+                case 0:
+                case 1:
+                case 2:
+                    throw new NotImplementedException();
+
+                case 3:
+                    return new Arm
+                    {
+                        UpperArm = bones[0],
+                        LowerArm = bones[1],
+                        Hand = bones[2],
+                    };
+
+                default:
+                    return new Arm
+                    {
+                        Shoulder = bones[0],
+                        UpperArm = bones[1],
+                        LowerArm = bones[2],
+                        Hand = bones[3],
+                    };
+            }
+        }
+
+        struct Leg
+        {
+            public Node UpperLeg;
+            public Node LowerLeg;
+            public Node Foot;
+            public Node Toes;
+        }
+
+        static Leg GetLeg(Node leg)
+        {
+            var bones = leg.Traverse().Where(x => string.IsNullOrEmpty(x.Name) || !x.Name.ToLower().Contains("buttock")).ToArray();
+            switch (bones.Length)
+            {
+                case 0:
+                case 1:
+                case 2:
+                    throw new NotImplementedException();
+
+                case 3:
+                    return new Leg
+                    {
+                        UpperLeg = bones[0],
+                        LowerLeg = bones[1],
+                        Foot = bones[2],
+                    };
+
+                default:
+                    return new Leg
+                    {
+                        UpperLeg = bones[bones.Length - 4],
+                        LowerLeg = bones[bones.Length - 3],
+                        Foot = bones[bones.Length - 2],
+                        Toes = bones[bones.Length - 1],
+                    };
+            }
+        }
+
+        static public Dictionary DetectByName(Node root, Dictionary map)
+        {
+            var dictionary = new Dictionary();
+            foreach (var bone in root.Traverse())
+            {
+                if (map.TryGetValue(bone.Name, out HumanoidBones humanbone))
+                {
+                    if (humanbone != HumanoidBones.unknown)
+                    {
+                        dictionary.Add(humanbone, bone);
+                    }
+                }
+                else if (Enum.TryParse(bone.Name, true, out HumanoidBones result))
+                {
+                    humanbone = (HumanoidBones)result;
+                    dictionary.Add(humanbone, bone);
+                }
+                else
+                {
+                    // throw new NotImplementedException();
+                }
+            }
+            return dictionary;
+        }
+
+        static public Dictionary DetectByPosition(Node root)
+        {
+            var hips = root.Traverse().First(x =>
+            {
+                // 3分岐以上で
+                //
+                // 子孫が以下の構成持ちうるもの
+                //
+                // spine, head, (upper, lower, hand) x 2
+                // (upper, lower, foot)
+                // (upper, lower, foot)
+                return x.Children.Where(y => y.Traverse().Count() >= 3).Count() >= 3;
+            });
+
+            Node spine, hip_L, hip_R;
+            GetSpineAndHips(hips, out spine, out hip_L, out hip_R);
+            if (hip_L.Equals(hip_R))
+            {
+                throw new Exception();
+            }
+            var legLeft = GetLeg(hip_L);
+            var legRight = GetLeg(hip_R);
+
+            var spineToChest = new List();
+            foreach (var x in spine.Traverse())
+            {
+                spineToChest.Add(x);
+                if (x.Children.Count == 3) break;
+            }
+
+            Func isLeft = default(Func);
+            if (legLeft.UpperLeg.SkeletonLocalPosition.z == legRight.UpperLeg.SkeletonLocalPosition.z)
+            {
+                isLeft = (l, r) => l.x < r.x;
+            }
+            else
+            {
+                isLeft = (l, r) => l.z < r.z;
+            }
+
+            Node neck, shoulder_L, shoulder_R;
+            GetNeckAndArms(spineToChest.Last(), out neck, out shoulder_L, out shoulder_R, isLeft);
+            var armLeft = GetArm(shoulder_L);
+            var armRight = GetArm(shoulder_R);
+
+            var neckToHead = neck.Traverse().ToArray();
+
+            //
+            //  set result
+            //
+            var skeleton = new Dictionary();
+            Action AddBoneToSkeleton = (b, t) =>
+            {
+                if (t != null)
+                {
+                    t.HumanoidBone = b;
+                    skeleton[b] = t;
+                }
+            };
+
+            AddBoneToSkeleton(HumanoidBones.hips, hips);
+
+            switch (spineToChest.Count)
+            {
+                case 0:
+                    throw new Exception();
+
+                case 1:
+                    AddBoneToSkeleton(HumanoidBones.spine, spineToChest[0]);
+                    break;
+
+                case 2:
+                    AddBoneToSkeleton(HumanoidBones.spine, spineToChest[0]);
+                    AddBoneToSkeleton(HumanoidBones.chest, spineToChest[1]);
+                    break;
+
+                case 3:
+                    AddBoneToSkeleton(HumanoidBones.spine, spineToChest[0]);
+                    AddBoneToSkeleton(HumanoidBones.chest, spineToChest[1]);
+                    AddBoneToSkeleton(HumanoidBones.upperChest, spineToChest[2]);
+                    break;
+
+                default:
+                    AddBoneToSkeleton(HumanoidBones.spine, spineToChest[0]);
+                    AddBoneToSkeleton(HumanoidBones.chest, spineToChest[1]);
+                    AddBoneToSkeleton(HumanoidBones.upperChest, spineToChest.Last());
+                    break;
+            }
+
+            switch (neckToHead.Length)
+            {
+                case 0:
+                    throw new Exception();
+
+                case 1:
+                    AddBoneToSkeleton(HumanoidBones.head, neckToHead[0]);
+                    break;
+
+                case 2:
+                    AddBoneToSkeleton(HumanoidBones.neck, neckToHead[0]);
+                    AddBoneToSkeleton(HumanoidBones.head, neckToHead[1]);
+                    break;
+
+                default:
+                    AddBoneToSkeleton(HumanoidBones.neck, neckToHead[0]);
+                    AddBoneToSkeleton(HumanoidBones.head, neckToHead.Where(x => x.Parent.Children.Count == 1).Last());
+                    break;
+            }
+
+            AddBoneToSkeleton(HumanoidBones.leftUpperLeg, legLeft.UpperLeg);
+            AddBoneToSkeleton(HumanoidBones.leftLowerLeg, legLeft.LowerLeg);
+            AddBoneToSkeleton(HumanoidBones.leftFoot, legLeft.Foot);
+            AddBoneToSkeleton(HumanoidBones.leftToes, legLeft.Toes);
+
+            AddBoneToSkeleton(HumanoidBones.rightUpperLeg, legRight.UpperLeg);
+            AddBoneToSkeleton(HumanoidBones.rightLowerLeg, legRight.LowerLeg);
+            AddBoneToSkeleton(HumanoidBones.rightFoot, legRight.Foot);
+            AddBoneToSkeleton(HumanoidBones.rightToes, legRight.Toes);
+
+            AddBoneToSkeleton(HumanoidBones.leftShoulder, armLeft.Shoulder);
+            AddBoneToSkeleton(HumanoidBones.leftUpperArm, armLeft.UpperArm);
+            AddBoneToSkeleton(HumanoidBones.leftLowerArm, armLeft.LowerArm);
+            AddBoneToSkeleton(HumanoidBones.leftHand, armLeft.Hand);
+
+            AddBoneToSkeleton(HumanoidBones.rightShoulder, armRight.Shoulder);
+            AddBoneToSkeleton(HumanoidBones.rightUpperArm, armRight.UpperArm);
+            AddBoneToSkeleton(HumanoidBones.rightLowerArm, armRight.LowerArm);
+            AddBoneToSkeleton(HumanoidBones.rightHand, armRight.Hand);
+
+            return skeleton;
+        }
+
+        // MVN
+        static Dictionary s_nameBoneMap = new Dictionary
+        {
+            {"Spine1", HumanoidBones.chest},
+            {"Spine2", HumanoidBones.upperChest},
+            {"LeftShoulder", HumanoidBones.leftShoulder},
+            {"LeftArm", HumanoidBones.leftUpperArm},
+            {"LeftForeArm", HumanoidBones.leftLowerArm},
+            {"RightShoulder", HumanoidBones.rightShoulder},
+            {"RightArm", HumanoidBones.rightUpperArm},
+            {"RightForeArm", HumanoidBones.rightLowerArm},
+            {"LeftUpLeg", HumanoidBones.leftUpperLeg},
+            {"LeftLeg", HumanoidBones.leftLowerLeg},
+            {"LeftToeBase", HumanoidBones.leftToes},
+            {"RightUpLeg", HumanoidBones.rightUpperLeg},
+            {"RightLeg", HumanoidBones.rightLowerLeg},
+            {"RightToeBase", HumanoidBones.rightToes},
+        };
+
+        static Dictionary s_nameBoneMapLA = new Dictionary
+        {
+            { "Chest", HumanoidBones.spine},
+            { "Chest2", HumanoidBones.chest},
+            { "LeftCollar", HumanoidBones.leftShoulder},
+            { "LeftShoulder", HumanoidBones.leftUpperArm},
+            { "LeftElbow", HumanoidBones.leftLowerArm},
+            { "LeftWrist", HumanoidBones.leftHand},
+            { "RightCollar", HumanoidBones.rightShoulder},
+            { "RightShoulder", HumanoidBones.rightUpperArm},
+            { "RightElbow", HumanoidBones.rightLowerArm},
+            { "RightWrist", HumanoidBones.rightHand},
+            { "LeftHip", HumanoidBones.leftUpperLeg},
+            { "LeftKnee", HumanoidBones.leftLowerLeg},
+            { "LeftAnkle", HumanoidBones.leftFoot},
+            { "RightHip", HumanoidBones.rightUpperLeg},
+            { "RightKnee", HumanoidBones.rightLowerLeg},
+            { "RightAnkle", HumanoidBones.rightFoot},
+        };
+
+        static Dictionary s_nameBoneMapAccad = new Dictionary
+        {
+            { "root", HumanoidBones.hips},
+            { "lowerback", HumanoidBones.spine},
+            { "upperback", HumanoidBones.chest},
+            { "thorax", HumanoidBones.upperChest},
+            { "neck", HumanoidBones.neck},
+            { "head", HumanoidBones.head},
+            { "lshoulderjoint", HumanoidBones.leftShoulder},
+            { "lhumerus", HumanoidBones.leftUpperArm},
+            { "lradius", HumanoidBones.leftLowerArm},
+            { "lhand", HumanoidBones.leftHand},
+            { "rshoulderjoint", HumanoidBones.rightShoulder},
+            { "rhumerus", HumanoidBones.rightUpperArm},
+            { "rradius", HumanoidBones.rightLowerArm},
+            { "rhand", HumanoidBones.rightHand},
+            { "rfemur", HumanoidBones.rightUpperLeg},
+            { "rtibia", HumanoidBones.rightLowerLeg},
+            { "rfoot", HumanoidBones.rightFoot},
+            { "rtoes", HumanoidBones.rightToes},
+            { "lfemur", HumanoidBones.leftUpperLeg},
+            { "ltibia", HumanoidBones.leftLowerLeg},
+            { "lfoot", HumanoidBones.leftFoot},
+            { "ltoes", HumanoidBones.leftToes},
+        };
+
+        static HumanoidBones[] RequiredBones = new HumanoidBones[]
+        {
+            HumanoidBones.hips,
+            HumanoidBones.spine,
+            HumanoidBones.head,
+            HumanoidBones.leftUpperArm,
+            HumanoidBones.leftLowerArm,
+            HumanoidBones.leftHand,
+            HumanoidBones.leftUpperLeg,
+            HumanoidBones.leftLowerLeg,
+            HumanoidBones.leftFoot,
+            HumanoidBones.rightUpperArm,
+            HumanoidBones.rightLowerArm,
+            HumanoidBones.rightHand,
+            HumanoidBones.rightUpperLeg,
+            HumanoidBones.rightLowerLeg,
+            HumanoidBones.rightFoot,
+         };
+
+        static bool HasAllHumanRequiredBone(Dictionary dict)
+        {
+            foreach (var bone in RequiredBones)
+            {
+                if (!dict.ContainsKey(bone))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        static Dictionary _Detect(Node root)
+        {
+            var list = new List>();
+            foreach (var map in new[] { s_nameBoneMap, s_nameBoneMapLA, s_nameBoneMapAccad })
+            {
+                try
+                {
+                    var result = DetectByName(root, map);
+                    if (result != null)
+                    {
+                        list.Add(result);
+                    }
+                }
+                catch (Exception)
+                { }
+            }
+
+            foreach (var map in list.OrderByDescending(x => x.Count))
+            {
+                if (HasAllHumanRequiredBone(map))
+                {
+                    return map;
+                }
+            }
+
+            return DetectByPosition(root);
+        }
+
+        static public Dictionary Detect(Node root)
+        {
+            try
+            {
+                var dict = _Detect(root);
+                foreach (var kv in dict)
+                {
+                    kv.Value.HumanoidBone = kv.Key;
+                }
+                return dict;
+            }
+            catch
+            {
+                return null;
+            }
+        }
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonEstimator.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonEstimator.cs.meta
new file mode 100644
index 000000000..a37f8ed97
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonEstimator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: eba33276386fae64fa0a02ab6408c295
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonMeshUtility.cs b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonMeshUtility.cs
new file mode 100644
index 000000000..d43a1bad3
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonMeshUtility.cs
@@ -0,0 +1,236 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace VrmLib
+{
+#pragma warning disable 0649
+    struct BoneWeight
+    {
+        public int boneIndex0;
+        public int boneIndex1;
+        public int boneIndex2;
+        public int boneIndex3;
+
+        public float weight0;
+        public float weight1;
+        public float weight2;
+        public float weight3;
+    }
+#pragma warning restore
+
+    class MeshBuilder
+    {
+        public static BoneHeadTail[] Bones = new BoneHeadTail[]
+        {
+            new BoneHeadTail(HumanoidBones.hips, HumanoidBones.spine, 0.1f, 0.06f),
+            new BoneHeadTail(HumanoidBones.spine, HumanoidBones.chest),
+            new BoneHeadTail(HumanoidBones.chest, HumanoidBones.neck, 0.1f, 0.06f),
+            new BoneHeadTail(HumanoidBones.neck, HumanoidBones.head, 0.03f, 0.03f),
+            new BoneHeadTail(HumanoidBones.head, new Vector3(0, 0.1f, 0), 0.1f, 0.1f),
+
+            new BoneHeadTail(HumanoidBones.leftShoulder, HumanoidBones.leftUpperArm),
+            new BoneHeadTail(HumanoidBones.leftUpperArm, HumanoidBones.leftLowerArm),
+            new BoneHeadTail(HumanoidBones.leftLowerArm, HumanoidBones.leftHand),
+            new BoneHeadTail(HumanoidBones.leftHand, new Vector3(-0.1f, 0, 0)),
+
+            new BoneHeadTail(HumanoidBones.leftUpperLeg, HumanoidBones.leftLowerLeg),
+            new BoneHeadTail(HumanoidBones.leftLowerLeg, HumanoidBones.leftFoot),
+            new BoneHeadTail(HumanoidBones.leftFoot, HumanoidBones.leftToes),
+            new BoneHeadTail(HumanoidBones.leftToes, new Vector3(0, 0, 0.1f)),
+
+            new BoneHeadTail(HumanoidBones.rightShoulder, HumanoidBones.rightUpperArm),
+            new BoneHeadTail(HumanoidBones.rightUpperArm, HumanoidBones.rightLowerArm),
+            new BoneHeadTail(HumanoidBones.rightLowerArm, HumanoidBones.rightHand),
+            new BoneHeadTail(HumanoidBones.rightHand, new Vector3(0.1f, 0, 0)),
+
+            new BoneHeadTail(HumanoidBones.rightUpperLeg, HumanoidBones.rightLowerLeg),
+            new BoneHeadTail(HumanoidBones.rightLowerLeg, HumanoidBones.rightFoot),
+            new BoneHeadTail(HumanoidBones.rightFoot, HumanoidBones.rightToes),
+            new BoneHeadTail(HumanoidBones.rightToes, new Vector3(0, 0, 0.1f)),
+        };
+
+        public void Build(List bones)
+        {
+            foreach (var headTail in Bones)
+            {
+                var head = bones.FirstOrDefault(x => x.HumanoidBone == headTail.Head);
+                if (head != null)
+                {
+                    Node tail = default(Node);
+                    if (headTail.Tail != HumanoidBones.unknown)
+                    {
+                        tail = bones.FirstOrDefault(x => x.HumanoidBone == headTail.Tail);
+                    }
+
+                    if (tail != null)
+                    {
+                        AddBone(head.SkeletonLocalPosition, tail.SkeletonLocalPosition, bones.IndexOf(head), headTail.XWidth, headTail.ZWidth);
+                    }
+                    else if (headTail.TailOffset != Vector3.zero)
+                    {
+                        AddBone(head.SkeletonLocalPosition, head.SkeletonLocalPosition + headTail.TailOffset, bones.IndexOf(head), headTail.XWidth, headTail.ZWidth);
+                    }
+                }
+                else
+                {
+                    Console.Error.WriteLine($"{headTail.Head} not found");
+                }
+            }
+        }
+
+        List m_positioins = new List();
+        List m_indices = new List();
+        List m_boneWeights = new List();
+
+        void AddBone(Vector3 head, Vector3 tail, int boneIndex, float xWidth, float zWidth)
+        {
+            var yaxis = (tail - head).normalized;
+            Vector3 xaxis;
+            Vector3 zaxis;
+            if (Vector3.Dot(yaxis, Vector3.forward) >= 1.0f - float.Epsilon)
+            {
+                // ほぼZ軸
+                xaxis = Vector3.right;
+                zaxis = -Vector3.up;
+            }
+            else
+            {
+                xaxis = Vector3.Normalize(Vector3.Cross(yaxis, Vector3.forward));
+                zaxis = Vector3.forward;
+            }
+            AddBox((head + tail) * 0.5f,
+                xaxis * xWidth,
+                (tail - head) * 0.5f,
+                zaxis * zWidth,
+                boneIndex);
+        }
+
+        void AddBox(Vector3 center, Vector3 xaxis, Vector3 yaxis, Vector3 zaxis, int boneIndex)
+        {
+            AddQuad(
+                center - yaxis - xaxis - zaxis,
+                center - yaxis + xaxis - zaxis,
+                center - yaxis + xaxis + zaxis,
+                center - yaxis - xaxis + zaxis,
+                boneIndex);
+            AddQuad(
+                center + yaxis - xaxis - zaxis,
+                center + yaxis + xaxis - zaxis,
+                center + yaxis + xaxis + zaxis,
+                center + yaxis - xaxis + zaxis,
+                boneIndex, true);
+            AddQuad(
+                center - xaxis - yaxis - zaxis,
+                center - xaxis + yaxis - zaxis,
+                center - xaxis + yaxis + zaxis,
+                center - xaxis - yaxis + zaxis,
+                boneIndex, true);
+            AddQuad(
+                center + xaxis - yaxis - zaxis,
+                center + xaxis + yaxis - zaxis,
+                center + xaxis + yaxis + zaxis,
+                center + xaxis - yaxis + zaxis,
+                boneIndex);
+            AddQuad(
+                center - zaxis - xaxis - yaxis,
+                center - zaxis + xaxis - yaxis,
+                center - zaxis + xaxis + yaxis,
+                center - zaxis - xaxis + yaxis,
+                boneIndex, true);
+            AddQuad(
+                center + zaxis - xaxis - yaxis,
+                center + zaxis + xaxis - yaxis,
+                center + zaxis + xaxis + yaxis,
+                center + zaxis - xaxis + yaxis,
+                boneIndex);
+        }
+
+        void AddQuad(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3, int boneIndex, bool reverse = false)
+        {
+            var i = m_positioins.Count;
+            if (float.IsNaN(v0.x) || float.IsNaN(v0.y) || float.IsNaN(v0.z))
+            {
+                throw new Exception();
+            }
+            m_positioins.Add(v0);
+
+            if (float.IsNaN(v1.x) || float.IsNaN(v1.y) || float.IsNaN(v1.z))
+            {
+                throw new Exception();
+            }
+            m_positioins.Add(v1);
+
+            if (float.IsNaN(v2.x) || float.IsNaN(v2.y) || float.IsNaN(v2.z))
+            {
+                throw new Exception();
+            }
+            m_positioins.Add(v2);
+
+            if (float.IsNaN(v3.x) || float.IsNaN(v3.y) || float.IsNaN(v3.z))
+            {
+                throw new Exception();
+            }
+            m_positioins.Add(v3);
+
+            var bw = new BoneWeight
+            {
+                boneIndex0 = boneIndex,
+                weight0 = 1.0f,
+            };
+            m_boneWeights.Add(bw);
+            m_boneWeights.Add(bw);
+            m_boneWeights.Add(bw);
+            m_boneWeights.Add(bw);
+
+            if (reverse)
+            {
+                m_indices.Add(i + 3);
+                m_indices.Add(i + 2);
+                m_indices.Add(i + 1);
+
+                m_indices.Add(i + 1);
+                m_indices.Add(i);
+                m_indices.Add(i + 3);
+            }
+            else
+            {
+                m_indices.Add(i);
+                m_indices.Add(i + 1);
+                m_indices.Add(i + 2);
+
+                m_indices.Add(i + 2);
+                m_indices.Add(i + 3);
+                m_indices.Add(i);
+            }
+        }
+    }
+
+    struct BoneHeadTail
+    {
+        public HumanoidBones Head;
+        public HumanoidBones Tail;
+        public Vector3 TailOffset;
+        public float XWidth;
+        public float ZWidth;
+
+        public BoneHeadTail(HumanoidBones head, HumanoidBones tail, float xWidth = 0.05f, float zWidth = 0.05f)
+        {
+            Head = head;
+            Tail = tail;
+            TailOffset = Vector3.zero;
+            XWidth = xWidth;
+            ZWidth = zWidth;
+        }
+
+        public BoneHeadTail(HumanoidBones head, Vector3 tailOffset, float xWidth = 0.05f, float zWidth = 0.05f)
+        {
+            Head = head;
+            Tail = HumanoidBones.unknown;
+            TailOffset = tailOffset;
+            XWidth = xWidth;
+            ZWidth = zWidth;
+        }
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonMeshUtility.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonMeshUtility.cs.meta
new file mode 100644
index 000000000..82f98c366
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Humanoid/SkeletonMeshUtility.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a8f1deadd49c23a40b05e95f5d5fcfe6
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/MathFWrap.cs b/Assets/External/VRM10/vrmlib/Runtime/MathFWrap.cs
new file mode 100644
index 000000000..c818e01c5
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/MathFWrap.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace VrmLib
+{
+    public static class MathFWrap
+    {
+        public static readonly float PI = (float)System.Math.PI;
+
+        public static float Clamp(float src, float min, float max)
+        {
+            return Math.Max(Math.Min(src, min), max);
+        }
+        public static int Clamp(int src, int min, int max)
+        {
+            return Math.Max(Math.Min(src, min), max);
+        }
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/MathFWrap.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/MathFWrap.cs.meta
new file mode 100644
index 000000000..28bd46ee4
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/MathFWrap.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cc3c6cd57620b5e408c8f982fc3f320b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Mesh.cs b/Assets/External/VRM10/vrmlib/Runtime/Mesh.cs
new file mode 100644
index 000000000..ceb69e45e
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Mesh.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UniGLTF;
+using UnityEngine;
+
+namespace VrmLib
+{
+    public enum TopologyType : int
+    {
+        Points = 0,
+        Lines = 1,
+        LineLoop = 2,
+        LineStrip = 3,
+        Triangles = 4,
+        TriangleStrip = 5,
+        TriangleFan = 6,
+    }
+
+    public struct Triangle
+    {
+        public int Vertex0;
+        public int Vertex1;
+        public int Vertex2;
+
+        public Triangle(int v0, int v1, int v2)
+        {
+            Vertex0 = v0;
+            Vertex1 = v1;
+            Vertex2 = v2;
+        }
+    }
+
+    public class Submesh
+    {
+        public int Offset;
+        public int DrawCount;
+        public int Material;
+
+        public override string ToString()
+        {
+            return $"{Material}({DrawCount})";
+        }
+
+        public Submesh(int material) : this(0, 0, material)
+        {
+        }
+
+        public Submesh(int offset, int drawCount, int material)
+        {
+            Offset = offset;
+            DrawCount = drawCount;
+            Material = material;
+        }
+    }
+
+    public class Mesh
+    {
+        public VertexBuffer VertexBuffer;
+
+        public BufferAccessor IndexBuffer;
+
+        public TopologyType Topology = TopologyType.Triangles;
+
+        public List Submeshes { private set; get; } = new List();
+
+        public List MorphTargets = new List();
+
+        public override string ToString()
+        {
+            var sb = new System.Text.StringBuilder();
+            foreach (var key in VertexBuffer.Select(x => x.Key))
+            {
+                sb.Append($"[{key}]");
+            }
+            if (IndexBuffer != null)
+            {
+                switch (Topology)
+                {
+                    case TopologyType.Triangles:
+                        sb.Append($" {IndexBuffer.Count / 3} tris");
+                        break;
+
+                    default:
+                        sb.Append($" topology: {Topology}");
+                        break;
+                }
+            }
+            if (MorphTargets.Any())
+            {
+                sb.Append($", {MorphTargets.Count} morphs");
+                foreach (var kv in MorphTargets[0].VertexBuffer)
+                {
+                    sb.Append($"[{kv.Key}]");
+                }
+            }
+
+            var byteLength = VertexBuffer.ByteLength + IndexBuffer.ByteLength + MorphTargets.Sum(x => x.VertexBuffer.ByteLength);
+
+            sb.Append($": expected {byteLength / 1000 / 1000} MB");
+
+            return sb.ToString();
+        }
+
+        public Mesh(TopologyType topology = TopologyType.Triangles)
+        {
+            Topology = topology;
+        }
+
+        // Skin.Normalize
+        public void ApplyRotationAndScaling(Matrix4x4 m)
+        {
+            m.SetColumn(3, new Vector4(0, 0, 0, 1));
+
+            var position = VertexBuffer.Positions.Bytes.Reinterpret(1);
+            var normal = VertexBuffer.Normals.Bytes.Reinterpret(1);
+
+            for (int i = 0; i < position.Length; ++i)
+            {
+                {
+                    position[i] = m.MultiplyPoint(position[i]);
+                }
+                {
+                    normal[i] = m.MultiplyVector(normal[i]);
+                }
+            }
+        }
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Mesh.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Mesh.cs.meta
new file mode 100644
index 000000000..0b8248c2e
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Mesh.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: da35a7338402b7b499b9c0357144fbc8
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/MeshGroup.cs b/Assets/External/VRM10/vrmlib/Runtime/MeshGroup.cs
new file mode 100644
index 000000000..01f0079cd
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/MeshGroup.cs
@@ -0,0 +1,53 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace VrmLib
+{
+    public class MeshGroup : GltfId
+    {
+        public readonly string Name;
+
+        public readonly List Meshes = new List();
+
+        public Skin Skin;
+
+        public override string ToString()
+        {
+            var sb = new StringBuilder();
+            sb.Append(Name);
+            if (Skin != null)
+            {
+                sb.Append("(skinned)");
+            }
+            var isFirst = true;
+            foreach (var mesh in Meshes)
+            {
+                if (isFirst)
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.Append(", ");
+                }
+                sb.Append(mesh);
+            }
+            return sb.ToString();
+        }
+
+        public MeshGroup(string name)
+        {
+            Name = name;
+        }
+
+        /// 
+        /// VRM-0.X 様式の共有頂点バッファを持っているか?
+        /// 
+        /// * vrm-1.0 の Export では共有頂点バッファを使用しない
+        /// * UniVRMの vrm-0.x => vrm-1.0 へのマイグレーション処理では、頂点バッファの様式変更はしない
+        /// 
+        /// マイグレーションしたときのみtrueになる想定
+        /// 
+        public bool HasSharedBuffer => Meshes.Count == 1 && Meshes[0].Submeshes.Count > 1;
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/MeshGroup.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/MeshGroup.cs.meta
new file mode 100644
index 000000000..8afe0600c
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/MeshGroup.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8d578a2f92d3c57439dc109ec5986c13
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Model.cs b/Assets/External/VRM10/vrmlib/Runtime/Model.cs
new file mode 100644
index 000000000..5cb1195f8
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Model.cs
@@ -0,0 +1,548 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UniGLTF;
+using UniGLTF.Utils;
+using Unity.Collections;
+using UnityEngine;
+
+namespace VrmLib
+{
+    /// 
+    /// 処理しやすいようにした中間形式
+    /// * index 参照は実参照
+    /// * accessor, bufferView は実バイト列(ArraySegment)
+    /// * meshは、subMesh方式(indexが offset + length)
+    /// 
+    public class Model
+    {
+        public Model(Coordinates coordinates)
+        {
+            Coordinates = coordinates;
+        }
+
+        public Coordinates Coordinates;
+
+        public string AssetVersion = "2.0";
+        public string AssetGenerator = $"UniVRM-{PackageVersion.VERSION}";
+        public string AssetCopyright;
+        public string AssetMinVersion;
+
+        // gltf/materials
+        public readonly List Materials = new List();
+
+        // gltf/skins
+        public readonly List Skins = new List();
+
+        // gltf/meshes
+        public readonly List MeshGroups = new List();
+
+        // gltf の nodes に含まれない。sceneに相当
+        Node m_root = new Node("__root__");
+
+        public Node Root
+        {
+            get => m_root;
+        }
+        public void SetRoot(Node root)
+        {
+            m_root = root;
+
+            Nodes.Clear();
+            Nodes.AddRange(root.Traverse().Skip(1));
+        }
+
+        // gltf/nodes
+        public List Nodes = new List();
+
+
+        public Dictionary GetBoneMap()
+        {
+            return Root.Traverse()
+                .Where(x => x.HumanoidBone.HasValue)
+                .ToDictionary(x => x.HumanoidBone.Value, x => x);
+        }
+
+        public override string ToString()
+        {
+            var sb = new StringBuilder();
+            sb.Append($"[GLTF] generator: {AssetGenerator}\n");
+
+            for (int i = 0; i < Materials.Count; ++i)
+            {
+                var m = Materials[i];
+                sb.Append($"[Material#{i:00}] {m}\n");
+            }
+            for (int i = 0; i < MeshGroups.Count; ++i)
+            {
+                var m = MeshGroups[i];
+                sb.Append($"[Mesh#{i:00}] {m}\n");
+            }
+            sb.Append($"[Node] {Nodes.Count} nodes\n");
+
+            foreach (var skin in Skins)
+            {
+                sb.Append($"[Skin] {skin}\n");
+            }
+
+            return sb.ToString();
+        }
+
+        /// 
+        /// HumanoidBonesの構成チェック
+        /// 
+        /// 
+        public bool CheckVrmHumanoid()
+        {
+            var vrmhumanoids = new HashSet();
+
+            // HumanoidBonesの重複チェック
+            foreach (var node in Nodes)
+            {
+                if (node.HumanoidBone.HasValue)
+                {
+                    if (vrmhumanoids.Contains(node.HumanoidBone.Value))
+                    {
+                        return false;
+                    }
+                    else
+                    {
+                        vrmhumanoids.Add(node.HumanoidBone.Value);
+                    }
+                }
+            }
+
+            // HumanoidBonesでBoneRequiredAttributeが定義されているものすべてが使われているかどうかを判断
+
+            var boneattributes
+                = CachedEnum.GetValues()
+                    .Select(bone => bone.GetType().GetField(bone.ToString()))
+                    .Select(info => info.GetCustomAttributes(typeof(BoneRequiredAttribute), false) as BoneRequiredAttribute[])
+                    .Where(attributes => attributes.Length > 0);
+
+            var nodeHumanoids
+                = vrmhumanoids
+                    .Select(humanoid => humanoid.GetType().GetField(humanoid.ToString()))
+                    .Select(info => info.GetCustomAttributes(typeof(BoneRequiredAttribute), false) as BoneRequiredAttribute[])
+                    .Where(attributes => attributes.Length > 0);
+
+            if (nodeHumanoids.Count() != boneattributes.Count()) return false;
+
+            return true;
+        }
+
+        public static Node GetNode(Node root, string path)
+        {
+            var splitted = path.Split('/');
+            var it = splitted.Select(x => x).GetEnumerator();
+
+            var current = root;
+            while (it.MoveNext())
+            {
+                current = current.Children.First(x => x.Name == it.Current);
+            }
+
+            return current;
+        }
+
+        /// 
+        /// Node Transform の Rotation, Scaling 成分を除去する
+        /// 
+        public void ApplyRotationAndScale()
+        {
+            // worldPositionを記録する
+            var m_positionMap = Nodes.ToDictionary(x => x, x => x.Translation);
+
+            // 回転・拡縮を除去する
+            // 木構造の根元から実行する
+            // Rootは編集対象外
+            foreach (var node in Root.Traverse().Skip(1))
+            {
+                // 回転・拡縮を除去
+                if (m_positionMap.TryGetValue(node, out Vector3 pos))
+                {
+                    var t = Matrix4x4.Translate(pos);
+                    node.SetMatrix(t, false);
+                }
+            }
+        }
+
+        #region Node
+        public void NodeAdd(Node node, Node parent = null)
+        {
+            if (parent is null)
+            {
+                parent = this.Root;
+            }
+            parent.Add(node);
+            if (this.Nodes.Contains(node))
+            {
+                throw new ArgumentException($"Nodes contain {node}");
+            }
+            this.Nodes.Add(node);
+        }
+
+        public void NodeRemove(Node remove)
+        {
+            foreach (var node in this.Nodes)
+            {
+                if (node.Parent == remove)
+                {
+                    remove.Remove(node);
+                }
+                if (remove.Parent == node)
+                {
+                    node.Remove(remove);
+                }
+            }
+            if (this.Root.Children.Contains(remove))
+            {
+                this.Root.Remove(remove);
+            }
+
+            this.Nodes.Remove(remove);
+        }
+        #endregion
+
+        /// 
+        /// ボーンを含む Node Transform の Rotation, Scaling 成分を除去し、SkinnedMesh の Bind Matrix も再計算する。
+        /// 
+        public string SkinningBake(INativeArrayManager arrayManager)
+        {
+            foreach (var node in this.Nodes)
+            {
+                var meshGroup = node.MeshGroup;
+                if (meshGroup == null)
+                {
+                    continue;
+                }
+
+                if (meshGroup.Skin != null)
+                {
+                    // 正規化されていれば1つしかない
+                    // されていないと Primitive の数だけある
+                    foreach (var mesh in meshGroup.Meshes)
+                    {
+                        {
+                            // Skinningの出力先を自身にすることでBakeする
+                            meshGroup.Skin.Skinning(arrayManager, mesh.VertexBuffer);
+                        }
+
+                        // morphのPositionは相対値が入っているはずなので、手を加えない(正規化されていない場合、二重に補正が掛かる)
+                        /*
+                                                foreach (var morph in mesh.MorphTargets)
+                                                {
+                                                    if (morph.VertexBuffer.Positions != null)
+                                                    {
+                                                        meshGroup.Skin.Skinning(morph.VertexBuffer);
+                                                    }
+                                                }
+                                                */
+                    }
+
+                    meshGroup.Skin.Root = null;
+                    meshGroup.Skin.InverseMatrices = null;
+                }
+                else
+                {
+                    foreach (var mesh in meshGroup.Meshes)
+                    {
+                        // nodeに対して疑似的にSkinningする
+                        // 回転と拡縮を適用し位置は適用しない
+                        mesh.ApplyRotationAndScaling(node.Matrix);
+                    }
+                }
+            }
+
+            // 回転・拡縮を除去する
+            this.ApplyRotationAndScale();
+
+            // inverse matrix の再計算
+            foreach (var node in this.Nodes)
+            {
+                var meshGroup = node.MeshGroup;
+                if (meshGroup == null)
+                {
+                    continue;
+                }
+
+                foreach (var mesh in meshGroup.Meshes)
+                {
+                    if (meshGroup.Skin != null)
+                    {
+                        meshGroup.Skin.CalcInverseMatrices(arrayManager);
+                    }
+                }
+            }
+
+            return "SkinningBake";
+        }
+
+        static void ReverseX(BufferAccessor ba)
+        {
+            if (ba.ComponentType != AccessorValueType.FLOAT)
+            {
+                throw new Exception();
+            }
+            if (ba.AccessorType == AccessorVectorType.VEC3)
+            {
+                var span = ba.Bytes.Reinterpret(1);
+                for (int i = 0; i < span.Length; ++i)
+                {
+                    span[i] = span[i].ReverseX();
+                }
+            }
+            else if (ba.AccessorType == AccessorVectorType.MAT4)
+            {
+                var span = ba.Bytes.Reinterpret(1);
+                for (int i = 0; i < span.Length; ++i)
+                {
+                    span[i] = span[i].ReverseX();
+                }
+            }
+            else
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        static void ReverseZ(BufferAccessor ba)
+        {
+            if (ba.ComponentType != AccessorValueType.FLOAT)
+            {
+                throw new Exception();
+            }
+            if (ba.AccessorType == AccessorVectorType.VEC3)
+            {
+                var span = ba.Bytes.Reinterpret(1);
+                for (int i = 0; i < span.Length; ++i)
+                {
+                    span[i] = span[i].ReverseZ();
+                }
+            }
+            else if (ba.AccessorType == AccessorVectorType.MAT4)
+            {
+                var span = ba.Bytes.Reinterpret(1);
+                for (int i = 0; i < span.Length; ++i)
+                {
+                    span[i] = span[i].ReverseZ();
+                }
+            }
+            else
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        struct Reverser
+        {
+            public Action ReverseBuffer;
+            public Func ReverseVector3;
+            public Func ReverseMatrix;
+        }
+
+        static Reverser ZReverser => new Reverser
+        {
+            ReverseBuffer = ReverseZ,
+            ReverseVector3 = v => v.ReverseZ(),
+            ReverseMatrix = m => m.ReverseZ(),
+        };
+
+        static Reverser XReverser => new Reverser
+        {
+            ReverseBuffer = ReverseX,
+            ReverseVector3 = v => v.ReverseX(),
+            ReverseMatrix = m => m.ReverseX(),
+        };
+
+        /// 
+        /// ignoreVrm: VRM-0.XX では無変換で入出力してた。VRM-1.0 では変換する。
+        /// 
+        public void ConvertCoordinate(Coordinates coordinates, bool ignoreVrm = false)
+        {
+            if (Coordinates.Equals(coordinates))
+            {
+                return;
+            }
+
+            if (Coordinates.IsVrm0 && coordinates.IsUnity)
+            {
+                ReverseAxisAndFlipTriangle(ZReverser, ignoreVrm);
+                UVVerticalFlip();
+                Coordinates = coordinates;
+            }
+            else if (Coordinates.IsUnity && coordinates.IsVrm0)
+            {
+                ReverseAxisAndFlipTriangle(ZReverser, ignoreVrm);
+                UVVerticalFlip();
+                Coordinates = coordinates;
+            }
+            else if (Coordinates.IsVrm1 && coordinates.IsUnity)
+            {
+                ReverseAxisAndFlipTriangle(XReverser, ignoreVrm);
+                UVVerticalFlip();
+                Coordinates = coordinates;
+            }
+            else if (Coordinates.IsUnity && coordinates.IsVrm1)
+            {
+                ReverseAxisAndFlipTriangle(XReverser, ignoreVrm);
+                UVVerticalFlip();
+                Coordinates = coordinates;
+            }
+            else
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        /// 
+        /// UVのVを反転する。 => V = 1.0 - V
+        /// 
+        void UVVerticalFlip()
+        {
+            foreach (var g in MeshGroups)
+            {
+                foreach (var m in g.Meshes)
+                {
+                    var uv = m.VertexBuffer.TexCoords;
+                    if (uv != null)
+                    {
+                        var span = uv.Bytes.Reinterpret(1);
+                        for (int i = 0; i < span.Length; ++i)
+                        {
+                            span[i] = span[i].UVVerticalFlip();
+                        }
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// * Position, Normal の Z座標に -1 を乗算する
+        /// * Rotation => Axis Angle に分解 => Axis の Z座標に -1 を乗算。Angle に -1 を乗算
+        /// * Triangle の index を 0, 1, 2 から 2, 1, 0 に反転する
+        /// 
+        void ReverseAxisAndFlipTriangle(Reverser reverser, bool ignoreVrm)
+        {
+            // 複数の gltf.accessor が別の要素間で共有されている場合に、2回処理されることを防ぐ
+            // edgecase: InverseBindMatrices で遭遇
+            var unique = new HashSet>();
+
+            foreach (var g in MeshGroups)
+            {
+                foreach (var m in g.Meshes)
+                {
+                    foreach (var kv in m.VertexBuffer)
+                    {
+                        var k = kv.Key;
+                        var v = kv.Value;
+                        if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
+                        {
+                            if (unique.Add(v.Bytes))
+                            {
+                                reverser.ReverseBuffer(v);
+                            }
+                        }
+                        else if (k == VertexBuffer.TangentKey)
+                        {
+                            // I don't know
+                        }
+                    }
+
+                    if (unique.Add(m.IndexBuffer.Bytes))
+                    {
+                        switch (m.IndexBuffer.ComponentType)
+                        {
+                            case AccessorValueType.UNSIGNED_BYTE:
+                                FlipTriangle(m.IndexBuffer.Bytes);
+                                break;
+                            case AccessorValueType.UNSIGNED_SHORT:
+                                FlipTriangle(m.IndexBuffer.Bytes.Reinterpret(1));
+                                break;
+                            case AccessorValueType.UNSIGNED_INT:
+                                FlipTriangle(m.IndexBuffer.Bytes.Reinterpret(1));
+                                break;
+                            default:
+                                throw new NotImplementedException();
+                        }
+                    }
+
+                    foreach (var mt in m.MorphTargets)
+                    {
+                        foreach (var kv in mt.VertexBuffer)
+                        {
+                            var k = kv.Key;
+                            var v = kv.Value;
+                            if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
+                            {
+                                if (unique.Add(v.Bytes))
+                                {
+                                    reverser.ReverseBuffer(v);
+                                }
+                            }
+                            if (k == VertexBuffer.TangentKey)
+                            {
+                                // I don't know
+                            }
+                        }
+                    }
+                }
+            }
+
+            // 親から順に処理する
+            // Rootは原点決め打ちのノード(GLTFに含まれない)
+            foreach (var n in Root.Traverse().Skip(1))
+            {
+                n.SetMatrix(reverser.ReverseMatrix(n.Matrix), false);
+            }
+            // 親から順に処理したので不要
+            // Root.CalcWorldMatrix();
+
+            foreach (var s in Skins)
+            {
+                if (s.InverseMatrices != null)
+                {
+                    if (unique.Add(s.InverseMatrices.Bytes))
+                    {
+                        reverser.ReverseBuffer(s.InverseMatrices);
+                    }
+                }
+            }
+        }
+
+        static void FlipTriangle(NativeArray indices)
+        {
+            for (int i = 0; i < indices.Length; i += 3)
+            {
+                // 0, 1, 2 to 2, 1, 0
+                var tmp = indices[i + 2];
+                indices[i + 2] = indices[i];
+                indices[i] = tmp;
+            }
+        }
+
+        static void FlipTriangle(NativeArray indices)
+        {
+            for (int i = 0; i < indices.Length; i += 3)
+            {
+                // 0, 1, 2 to 2, 1, 0
+                var tmp = indices[i + 2];
+                indices[i + 2] = indices[i];
+                indices[i] = tmp;
+            }
+        }
+
+        static void FlipTriangle(NativeArray indices)
+        {
+            for (int i = 0; i < indices.Length; i += 3)
+            {
+                // 0, 1, 2 to 2, 1, 0
+                var tmp = indices[i + 2];
+                indices[i + 2] = indices[i];
+                indices[i] = tmp;
+            }
+        }
+
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Model.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Model.cs.meta
new file mode 100644
index 000000000..e458589f0
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Model.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 988a2640f02f7ff479f717fabdadf436
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/MorphTarget.cs b/Assets/External/VRM10/vrmlib/Runtime/MorphTarget.cs
new file mode 100644
index 000000000..88cd44cd6
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/MorphTarget.cs
@@ -0,0 +1,24 @@
+namespace VrmLib
+{
+    public class MorphTarget
+    {
+        public readonly string Name;
+        public VertexBuffer VertexBuffer;
+
+        public override string ToString()
+        {
+            var sb = new System.Text.StringBuilder();
+            sb.Append(Name);
+            foreach (var kv in VertexBuffer)
+            {
+                sb.Append($"[{kv.Key}]");
+            }
+            return sb.ToString();
+        }
+
+        public MorphTarget(string name)
+        {
+            Name = name;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/vrmlib/Runtime/MorphTarget.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/MorphTarget.cs.meta
new file mode 100644
index 000000000..cc460a3a0
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/MorphTarget.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1adbe1d2bd9bcd3458b01621faae1ff5
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Node.cs b/Assets/External/VRM10/vrmlib/Runtime/Node.cs
new file mode 100644
index 000000000..c5fd43721
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Node.cs
@@ -0,0 +1,364 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UniGLTF;
+
+namespace VrmLib
+{
+    public enum ChildMatrixMode
+    {
+        KeepLocal,
+        KeepWorld,
+    }
+
+    public class Node : GltfId, IEnumerable
+    {
+        static int s_nextUniqueId = 1;
+
+        public readonly int UniqueID;
+
+        public string Name
+        {
+            get;
+            set;
+        }
+
+        public Node(string name)
+        {
+            UniqueID = s_nextUniqueId++;
+            Name = name;
+        }
+
+        #region Transform
+        //
+        // Localで値を保持する
+        //
+        public Vector3 LocalTranslationWithoutUpdate = Vector3.zero;
+        public Vector3 LocalTranslation
+        {
+            get => LocalTranslationWithoutUpdate;
+            set
+            {
+                if (LocalTranslationWithoutUpdate == value) return;
+                LocalTranslationWithoutUpdate = value;
+                CalcWorldMatrix(Parent != null ? Parent.Matrix : Matrix4x4.identity);
+            }
+        }
+
+        public Quaternion LocalRotationWithoutUpdate = Quaternion.identity;
+        public Quaternion LocalRotation
+        {
+            get => LocalRotationWithoutUpdate;
+            set
+            {
+                if (LocalRotationWithoutUpdate == value) return;
+                LocalRotationWithoutUpdate = value;
+                CalcWorldMatrix(Parent != null ? Parent.Matrix : Matrix4x4.identity);
+            }
+        }
+
+        public Vector3 LocalScalingWithoutUpdate = Vector3.one;
+        public Vector3 LocalScaling
+        {
+            get => LocalScalingWithoutUpdate;
+            set
+            {
+                if (LocalScalingWithoutUpdate == value) return;
+                LocalScalingWithoutUpdate = value;
+                CalcWorldMatrix(Parent != null ? Parent.Matrix : Matrix4x4.identity);
+            }
+        }
+
+        public Matrix4x4 LocalMatrix
+        {
+            get => Matrix4x4.Translate(LocalTranslation)
+            * Matrix4x4.Rotate(LocalRotation)
+            * Matrix4x4.Scale(LocalScaling)
+            ;
+        }
+
+        public void SetLocalMatrix(Matrix4x4 value, bool calcWorldMatrix)
+        {
+            (LocalTranslationWithoutUpdate, LocalRotationWithoutUpdate, LocalScalingWithoutUpdate) = value.Decompose();
+            CalcWorldMatrix(Parent != null ? Parent.Matrix : Matrix4x4.identity, calcWorldMatrix);
+        }
+
+        Matrix4x4 m_matrix = Matrix4x4.identity;
+        public Matrix4x4 Matrix
+        {
+            get => m_matrix;
+        }
+
+        public Quaternion Rotation
+        {
+            get
+            {
+                return Matrix.rotation;
+            }
+            set
+            {
+                if (Parent == null)
+                {
+                    LocalRotation = value;
+                }
+                else
+                {
+                    LocalRotation = Quaternion.Inverse(Parent.Rotation) * value;
+                }
+            }
+        }
+
+        public void SetMatrix(Matrix4x4 m, bool calcWorldMatrix)
+        {
+            if (Parent != null)
+            {
+                SetLocalMatrix(Parent.InverseMatrix * m, calcWorldMatrix);
+            }
+            else
+            {
+                SetLocalMatrix(m, calcWorldMatrix);
+            }
+        }
+
+        public Matrix4x4 InverseMatrix
+        {
+            get
+            {
+                return Matrix.inverse;
+            }
+        }
+
+        public void CalcWorldMatrix(bool calcChildren = true)
+        {
+            if (Parent == null)
+            {
+                CalcWorldMatrix(Matrix4x4.identity, calcChildren);
+            }
+            else
+            {
+                CalcWorldMatrix(Parent.Matrix, calcChildren);
+            }
+        }
+
+        public void CalcWorldMatrix(Matrix4x4 parent, bool calcChildren = true)
+        {
+            var value = parent * LocalMatrix;
+            m_matrix = value;
+
+            RaiseMatrixUpdated();
+
+            if (calcChildren)
+            {
+                foreach (var child in Children)
+                {
+                    child.CalcWorldMatrix(m_matrix, calcChildren);
+                }
+            }
+        }
+
+        public event Action MatrixUpdated;
+        void RaiseMatrixUpdated()
+        {
+            var handle = MatrixUpdated;
+            if (handle != null)
+            {
+                handle(Matrix);
+            }
+        }
+
+        public Vector3 Translation
+        {
+            get => Matrix.GetColumn(3);
+            set
+            {
+                if (Parent == null)
+                {
+                    LocalTranslation = value;
+                }
+                else
+                {
+                    LocalTranslation = Parent.InverseMatrix.MultiplyPoint(value);
+                }
+            }
+        }
+
+        public Vector3 SkeletonLocalPosition
+        {
+            get => Translation;
+            set
+            {
+                Translation = value;
+            }
+        }
+        #endregion
+
+        #region Hierarchy
+
+        public Node Parent { get; private set; }
+
+        public IEnumerable Ancestors()
+        {
+            if (Parent == null)
+            {
+                yield break;
+            }
+            yield return Parent;
+            foreach (var x in Parent.Ancestors())
+            {
+                yield return x;
+            }
+        }
+
+        readonly List m_children = new List();
+
+        public void Add(Node child, ChildMatrixMode mode = ChildMatrixMode.KeepLocal)
+        {
+            if (child.Parent != null)
+            {
+                child.Parent.m_children.Remove(child);
+            }
+            m_children.Add(child);
+            child.Parent = this;
+
+            switch (mode)
+            {
+                case ChildMatrixMode.KeepLocal:
+                    child.CalcWorldMatrix(Matrix);
+                    break;
+
+                case ChildMatrixMode.KeepWorld:
+                    child.SetMatrix(child.Matrix, true);
+                    break;
+            }
+        }
+
+        public void Remove(Node child)
+        {
+            child.Parent = null;
+            m_children.Remove(child);
+        }
+
+        public IEnumerable Traverse()
+        {
+            yield return this;
+
+            foreach (var child in Children)
+            {
+                foreach (var x in child.Traverse())
+                {
+                    yield return x;
+                }
+            }
+        }
+
+        public IEnumerator GetEnumerator()
+        {
+            return ((IEnumerable)Children).GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return ((IEnumerable)Children).GetEnumerator();
+        }
+        #endregion
+
+
+        public MeshGroup MeshGroup;
+
+        // VRMでは、Meshes.Count==1
+        public Mesh Mesh => MeshGroup?.Meshes?[0];
+
+        HumanoidBones? m_bone;
+        public HumanoidBones? HumanoidBone
+        {
+            get => m_bone;
+            set
+            {
+                if (m_bone == value)
+                {
+                    return;
+                }
+                if (value == HumanoidBones.unknown)
+                {
+                    return;
+                }
+                m_bone = value;
+            }
+        }
+
+        public IReadOnlyList Children => m_children;
+
+        public Node FindBone(HumanoidBones bone)
+        {
+            return Traverse().FirstOrDefault(x => x.HumanoidBone == bone);
+        }
+
+        public void RotateFromTo(Vector3 worldSrc, Vector3 worldDst)
+        {
+            // world to local
+            var src = Quaternion.Inverse(Rotation) * worldSrc.normalized;
+            var dst = Quaternion.Inverse(Rotation) * worldDst.normalized;
+
+            var dot = Vector3.Dot(src, dst);
+            Quaternion rot;
+            if (Math.Abs(1.0f - dot) < float.Epsilon)
+            {
+                // 0degree
+                rot = Quaternion.identity;
+            }
+            else if (Math.Abs(-1.0f - dot) < float.Epsilon)
+            {
+                // 180degree
+                rot = Quaternion.Euler(0, MathFWrap.PI, 0);
+            }
+            else
+            {
+                var axis = Vector3.Normalize(Vector3.Cross(src, dst));
+                rot = Quaternion.AngleAxis((float)Math.Acos(dot), axis);
+            }
+
+            LocalRotation = rot;
+        }
+
+        public override string ToString()
+        {
+            if (HumanoidBone.HasValue)
+            {
+                return $"{Name}[{HumanoidBone.Value}]: {LocalTranslation.x:0.00}, {LocalTranslation.y:0.00}, {LocalTranslation.z:0.00}";
+            }
+            else
+            {
+                return $"{Name}: {LocalTranslation.x:0.00}, {LocalTranslation.y:0.00}, {LocalTranslation.z:0.00}";
+            }
+        }
+    }
+
+    public static class NodeExtensions
+    {
+        public static IEnumerable Traverse(this Node self)
+        {
+            yield return self;
+            foreach (var child in self.Children)
+            {
+                foreach (var x in child.Traverse())
+                {
+                    yield return x;
+                }
+            }
+        }
+
+        public static Vector3 CenterOfDescendant(this Node self)
+        {
+            var sum = Vector3.zero;
+            int i = 0;
+            foreach (var x in self.Traverse())
+            {
+                sum += x.SkeletonLocalPosition;
+                ++i;
+            }
+            return sum / i;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Node.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Node.cs.meta
new file mode 100644
index 000000000..31dd693fb
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Node.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c23140d8dd58d4e45a7c4798dd577035
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/NodeAnimation.cs b/Assets/External/VRM10/vrmlib/Runtime/NodeAnimation.cs
new file mode 100644
index 000000000..5466d3377
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/NodeAnimation.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+using UniGLTF;
+using UnityEngine;
+
+namespace VrmLib
+{
+    public enum AnimationPathType
+    {
+        Translation,
+        Rotation,
+        Scale,
+        Weights,
+    }
+
+    public class CurveSampler
+    {
+        public BufferAccessor In;
+        public BufferAccessor Out;
+
+        public float LastTime
+        {
+            get
+            {
+                if (In.ComponentType == AccessorValueType.FLOAT)
+                {
+                    var times =  In.Bytes.Reinterpret(1);
+                    return times[times.Length - 1];
+                }
+                else
+                {
+                    throw new NotImplementedException();
+                }
+            }
+        }
+
+        public CurveSampler()
+        {
+        }
+
+        ValueTuple GetRange(float seconds)
+        {
+            var keys = In.GetSpan();
+
+            if (seconds <= keys[0])
+            {
+                return (0, 0, 0);
+            }
+            else if (seconds >= keys[keys.Length - 1])
+            {
+                return (keys.Length - 1, keys.Length - 1, 0);
+            }
+
+            // search range
+            float begin = keys[0];
+            float end;
+            for (int i = 1; i < keys.Length; ++i)
+            {
+                end = keys[i];
+
+                if (seconds == end)
+                {
+                    return (i, i, 0);
+                }
+                else if (seconds < end)
+                {
+                    var ratio = (seconds - begin) / (end - begin);
+                    return (i - 1, i, ratio);
+                }
+
+                begin = end;
+            }
+
+            throw new Exception("not found");
+        }
+
+        public Vector3 GetVector3(TimeSpan elapsed)
+        {
+            var (begin, end, ratio) = GetRange((float)elapsed.TotalSeconds);
+            var values = Out.GetSpan();
+            if (begin == end)
+            {
+                return values[begin];
+            }
+            else
+            {
+                // TODO: curve interpolation
+                return Vector3.Lerp(values[begin], values[end], ratio);
+            }
+        }
+
+        public Quaternion GetQuaternion(TimeSpan elapsed)
+        {
+            var (begin, end, ratio) = GetRange((float)elapsed.TotalSeconds);
+            var values = Out.GetSpan();
+            if (begin == end)
+            {
+                return values[begin];
+            }
+            else
+            {
+                // TODO: curve interpolation
+                return Quaternion.Lerp(values[begin], values[end], ratio);
+            }
+        }
+
+        public void SkipFrame(int skipFrames)
+        {
+            In = In.Skip(skipFrames);
+            Out = Out.Skip(skipFrames);
+        }
+    }
+
+    public class NodeAnimation
+    {
+        public TimeSpan Duration
+        {
+            get
+            {
+                var lastTime = float.NegativeInfinity;
+                foreach (var kv in Curves)
+                {
+                    if (kv.Value.LastTime > lastTime)
+                    {
+                        lastTime = kv.Value.LastTime;
+                    }
+                }
+                return TimeSpan.FromSeconds(lastTime);
+            }
+        }
+
+        public Dictionary Curves = new Dictionary();
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/NodeAnimation.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/NodeAnimation.cs.meta
new file mode 100644
index 000000000..e8fde976a
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/NodeAnimation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9dbb0b339c10c3a4faf4754a406830c1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Skin.cs b/Assets/External/VRM10/vrmlib/Runtime/Skin.cs
new file mode 100644
index 000000000..05baba2d2
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Skin.cs
@@ -0,0 +1,281 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using UniGLTF;
+using Unity.Collections;
+using UnityEngine;
+
+namespace VrmLib
+{
+    // Bone skinning
+    public class Skin : GltfId
+    {
+        public BufferAccessor InverseMatrices;
+
+        public Node Root;
+
+        public List Joints = new List();
+
+        Matrix4x4[] m_matrices;
+        public Matrix4x4[] SkinningMatrices => m_matrices;
+
+        ushort m_indexOfRoot = ushort.MaxValue;
+
+        public Skin()
+        {
+        }
+
+        /// 
+        /// BoneSkinningもしくはMorphTargetの適用
+        /// 
+        public void Skinning(INativeArrayManager arrayManager, VertexBuffer vertexBuffer = null)
+        {
+            m_indexOfRoot = (ushort)Joints.IndexOf(Root);
+            var addRoot = Root != null && m_indexOfRoot == ushort.MaxValue;
+            if (addRoot)
+            {
+                m_indexOfRoot = (ushort)Joints.Count;
+                Joints.Add(Root);
+            }
+
+            if (m_matrices == null)
+            {
+                m_matrices = new Matrix4x4[Joints.Count];
+            }
+
+            if (InverseMatrices == null)
+            {
+                CalcInverseMatrices(arrayManager);
+            }
+            else
+            {
+                if (addRoot)
+                {
+                    var inverseArray = InverseMatrices.Bytes.Reinterpret(1);
+                    var concat = inverseArray.Concat(new[] { Root.InverseMatrix }).ToArray();
+                    InverseMatrices.Assign(concat);
+                }
+            }
+
+            var inverse = InverseMatrices.GetSpan();
+
+            // if (Root != null)
+            // {
+            //     var rootInverse = Root.InverseMatrix;
+            //     var root = Root.Matrix;
+            //     for (int i = 0; i < m_matrices.Length; ++i)
+            //     {
+            //         m_matrices[i] = inverse[i] * Joints[i].Matrix * rootInverse;
+            //     }
+            // }
+            // else
+            {
+                for (int i = 0; i < m_matrices.Length; ++i)
+                {
+                    var inv = i < inverse.Length ? inverse[i] : Joints[i].InverseMatrix;
+                    m_matrices[i] = inv * Joints[i].Matrix;
+                }
+            }
+
+            if (vertexBuffer != null)
+            {
+                Apply(arrayManager, vertexBuffer);
+            }
+        }
+
+        void Apply(INativeArrayManager arrayManager, VertexBuffer vertexBuffer)
+        {
+            var dstPosition = vertexBuffer.Positions.Bytes.Reinterpret(1);
+            // Span emptyNormal = stackalloc Vector3[0];
+            Apply(arrayManager, vertexBuffer, dstPosition, vertexBuffer.Normals != null ? vertexBuffer.Normals.Bytes.Reinterpret(1) : default);
+        }
+
+        public void Apply(INativeArrayManager arrayManager, VertexBuffer vertexBuffer, NativeArray dstPosition, NativeArray dstNormal)
+        {
+            var jointsBuffer = vertexBuffer.Joints;
+            var joints = (jointsBuffer != null || jointsBuffer.Count == 0)
+                ? jointsBuffer.GetAsSkinJointsArray()
+                : arrayManager.CreateNativeArray(vertexBuffer.Count) // when MorphTarget only
+                ;
+
+            var weightsBuffer = vertexBuffer.Weights;
+            var weights = (weightsBuffer != null || weightsBuffer.Count == 0)
+                ? weightsBuffer.GetAsVector4Array()
+                : arrayManager.CreateNativeArray(vertexBuffer.Count) // when MorphTarget only
+                ;
+
+            var positionBuffer = vertexBuffer.Positions;
+            var position = positionBuffer.Bytes.Reinterpret(1);
+
+            bool useNormal = false;
+            if (dstNormal.Length > 0)
+            {
+                useNormal = vertexBuffer.Normals != null && dstNormal.Length == dstPosition.Length;
+            }
+
+            for (int i = 0; i < position.Length; ++i)
+            {
+                var j = joints[i];
+                var w = weights[i];
+
+                var sum = (w.x + w.y + w.z + w.w);
+                float factor;
+                if (sum > 0)
+                {
+                    factor = 1.0f / sum;
+                }
+                else
+                {
+                    factor = 1.0f;
+                    j = new SkinJoints(m_indexOfRoot, 0, 0, 0);
+                    w = new Vector4(1, 0, 0, 0);
+                }
+                if (j.Joint0 == ushort.MaxValue) w.x = 0;
+                if (j.Joint1 == ushort.MaxValue) w.y = 0;
+                if (j.Joint2 == ushort.MaxValue) w.z = 0;
+                if (j.Joint3 == ushort.MaxValue) w.w = 0;
+
+                {
+                    var src = position[i]; // 位置ベクトル
+                    var dst = Vector3.zero;
+                    if (w.x > 0) dst += m_matrices[j.Joint0].MultiplyPoint(src) * w.x * factor;
+                    if (w.y > 0) dst += m_matrices[j.Joint1].MultiplyPoint(src) * w.y * factor;
+                    if (w.z > 0) dst += m_matrices[j.Joint2].MultiplyPoint(src) * w.z * factor;
+                    if (w.w > 0) dst += m_matrices[j.Joint3].MultiplyPoint(src) * w.w * factor;
+                    dstPosition[i] = new Vector3(dst.x, dst.y, dst.z);
+                }
+                if (useNormal)
+                {
+                    var normalBuffer = vertexBuffer.Normals;
+                    var normal = normalBuffer != null ? normalBuffer.Bytes.Reinterpret(1) : dstNormal;
+                    var src = normal[i]; // 方向ベクトル
+                    var dst = Vector3.zero;
+                    if (w.x > 0) dst += m_matrices[j.Joint0].MultiplyVector(src) * w.x * factor;
+                    if (w.y > 0) dst += m_matrices[j.Joint1].MultiplyVector(src) * w.y * factor;
+                    if (w.z > 0) dst += m_matrices[j.Joint2].MultiplyVector(src) * w.z * factor;
+                    if (w.w > 0) dst += m_matrices[j.Joint3].MultiplyVector(src) * w.w * factor;
+                    dstNormal[i] = new Vector3(dst.x, dst.y, dst.z);
+                }
+            }
+        }
+
+        // だいたい Identity
+        static bool IsIdentity(Matrix4x4 m)
+        {
+            // 回転・スケール・しあー
+            if (
+                m.m00 == 1 && m.m10 == 0 && m.m20 == 0 && m.m30 == 0
+                && m.m01 == 0 && m.m11 == 1 && m.m21 == 0 && m.m31 == 0
+                && m.m02 == 0 && m.m12 == 0 && m.m22 == 1 && m.m32 == 0
+                && m.m33 == 1
+            )
+            {
+
+            }
+            else
+            {
+                return false;
+            }
+
+            // translate
+            if (Math.Abs(m.m03) > 1e-5f) return false;
+            if (Math.Abs(m.m13) > 1e-5f) return false;
+            if (Math.Abs(m.m23) > 1e-5f) return false;
+
+            return true;
+        }
+
+        public override string ToString()
+        {
+            if (InverseMatrices != null)
+            {
+                var sb = new StringBuilder();
+                var matrices = InverseMatrices.Bytes.Reinterpret(1);
+                var count = 0;
+                // var rootMatrix = Matrix4x4.identity;
+                // if (Root != null)
+                // {
+                //     rootMatrix = Root.InverseMatrix;
+                // }
+                for (int i = 0; i < matrices.Length; ++i)
+                {
+                    var m = matrices[i] * Joints[i].Matrix;
+                    if (!IsIdentity(m))
+                    {
+                        ++count;
+                    }
+                }
+                if (count > 0)
+                {
+                    sb.Append($"{count}/{Joints.Count} is not normalized");
+                }
+                else
+                {
+                    sb.Append($"{Joints.Count} joints normalized");
+                }
+                return sb.ToString();
+            }
+            else
+            {
+                return $"{Joints.Count} joints without InverseMatrices";
+            }
+        }
+
+        public void Replace(INativeArrayManager arrayManager, Node src, Node dst)
+        {
+            var removeIndex = Joints.IndexOf(src);
+            if (removeIndex >= 0)
+            {
+                Joints[removeIndex] = dst;
+
+                // エクスポート時に再計算させる
+                CalcInverseMatrices(arrayManager);
+            }
+        }
+
+        public void CalcInverseMatrices(INativeArrayManager arrayManager)
+        {
+            // var root = Root;
+            // if (root == null)
+            // {
+            //     root = Joints[0].Ancestors().Last();
+            // }
+            // root.CalcWorldMatrix(Matrix4x4.identity, true);
+
+            // calc inverse bind matrices
+            var matricesBytes = arrayManager.CreateNativeArray(Marshal.SizeOf(typeof(Matrix4x4)) * Joints.Count);
+            var matrices = matricesBytes.Reinterpret(1);
+            for (int i = 0; i < Joints.Count; ++i)
+            {
+                // var w = Joints[i].Matrix;
+                // Matrix4x4.Invert(w, out Matrix4x4 inv);
+                if (Joints[i] != null)
+                {
+                    matrices[i] = Joints[i].InverseMatrix;
+                }
+            }
+            InverseMatrices = new BufferAccessor(arrayManager, matricesBytes, AccessorValueType.FLOAT, AccessorVectorType.MAT4, Joints.Count);
+        }
+
+        static void Update(ref float weight, ref ushort index, int[] indexMap)
+        {
+            if (indexMap[index] == -1)
+            {
+                if (weight > 0)
+                {
+                    throw new Exception();
+                }
+                //削除された
+                weight = 0;
+                index = 0;
+            }
+            else
+            {
+                // 参照を更新(変わっているかもしれない)
+                index = (ushort)indexMap[index];
+            }
+        }
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/Skin.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/Skin.cs.meta
new file mode 100644
index 000000000..12db0b351
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/Skin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7435dea123c851c4a93dd046d5e40b70
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/VertexBuffer.cs b/Assets/External/VRM10/vrmlib/Runtime/VertexBuffer.cs
new file mode 100644
index 000000000..268ca7326
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/VertexBuffer.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UniGLTF;
+
+namespace VrmLib
+{
+    public class VertexBuffer : IEnumerable>
+    {
+        public Dictionary VertexBuffers = new Dictionary();
+
+        public bool ContainsKey(string key)
+        {
+            return VertexBuffers.ContainsKey(key);
+        }
+
+        public IEnumerator> GetEnumerator()
+        {
+            return VertexBuffers.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        public void Add(string key, BufferAccessor accessor)
+        {
+            // if exists, over write
+            VertexBuffers[key] = accessor;
+        }
+
+        public bool TryGetValue(string key, out BufferAccessor accessor)
+        {
+            return VertexBuffers.TryGetValue(key, out accessor);
+        }
+
+        public int Count
+        {
+            get
+            {
+                if (VertexBuffers.TryGetValue(PositionKey, out BufferAccessor buffer))
+                {
+                    return buffer.Count;
+                }
+                return 0;
+            }
+        }
+
+        public const string PositionKey = "POSITION";
+
+        public BufferAccessor Positions
+        {
+            get
+            {
+                if (VertexBuffers.TryGetValue(PositionKey, out BufferAccessor buffer))
+                {
+                    return buffer;
+                }
+                return null;
+            }
+        }
+
+        public const string NormalKey = "NORMAL";
+        public BufferAccessor Normals
+        {
+            get
+            {
+                if (VertexBuffers.TryGetValue(NormalKey, out BufferAccessor buffer))
+                {
+                    return buffer;
+                }
+                return null;
+            }
+        }
+
+        public const string TangentKey = "TANGENT";
+        public const string ColorKey = "COLOR_0";
+        public BufferAccessor Colors
+        {
+            get
+            {
+                if (VertexBuffers.TryGetValue(ColorKey, out BufferAccessor buffer))
+                {
+                    return buffer;
+                }
+                return null;
+            }
+        }
+
+        public const string TexCoordKey = "TEXCOORD_0";
+        public BufferAccessor TexCoords
+        {
+            get
+            {
+                if (VertexBuffers.TryGetValue(TexCoordKey, out BufferAccessor buffer))
+                {
+                    return buffer;
+                }
+                return null;
+            }
+        }
+
+        public const string TexCoordKey2 = "TEXCOORD_1";
+
+        public const string JointKey = "JOINTS_0";
+        public BufferAccessor Joints
+        {
+            get
+            {
+                if (VertexBuffers.TryGetValue(JointKey, out BufferAccessor buffer))
+                {
+                    return buffer;
+                }
+                return null;
+            }
+        }
+
+        public const string WeightKey = "WEIGHTS_0";
+        public BufferAccessor Weights
+        {
+            get
+            {
+                if (VertexBuffers.TryGetValue(WeightKey, out BufferAccessor buffer))
+                {
+                    return buffer;
+                }
+                return null;
+            }
+        }
+
+        public void RemoveTangent()
+        {
+            if (VertexBuffers.ContainsKey(TangentKey))
+            {
+                VertexBuffers.Remove(TangentKey);
+            }
+        }
+
+        public int ByteLength
+        {
+            get
+            {
+                return VertexBuffers.Sum(x => x.Value.ByteLength);
+            }
+        }
+
+        public void ValidateLength(string name = "")
+        {
+            foreach (var kv in VertexBuffers)
+            {
+                if (kv.Key == PositionKey) continue;
+
+                if (kv.Value.Count != Count)
+                {
+                    var msg = "vertex attribute not same length";
+                    if (!string.IsNullOrEmpty(name))
+                    {
+                        msg = $"{name}: {msg}";
+                    }
+                    throw new ArgumentException(msg);
+                }
+            }
+        }
+
+        public void ValidateNAN()
+        {
+            foreach (var kv in VertexBuffers)
+            {
+                if (kv.Value.ComponentType == AccessorValueType.FLOAT)
+                {
+                    var values = kv.Value.GetSpan(false);
+                    int i = 0;
+                    foreach (var f in values)
+                    {
+                        if (float.IsNaN(f)) throw new ArithmeticException("float error");
+                        ++i;
+                    }
+                }
+            }
+        }
+
+        public VertexBuffer()
+        {
+        }
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Runtime/VertexBuffer.cs.meta b/Assets/External/VRM10/vrmlib/Runtime/VertexBuffer.cs.meta
new file mode 100644
index 000000000..ba13bdd3f
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/VertexBuffer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fd0c2117beaa13845aa49d48c7bd8f48
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Runtime/VrmLib.asmdef b/Assets/External/VRM10/vrmlib/Runtime/VrmLib.asmdef
new file mode 100644
index 000000000..308107e1e
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/VrmLib.asmdef
@@ -0,0 +1,17 @@
+{
+    "name": "VrmLib",
+    "rootNamespace": "",
+    "references": [
+        "GUID:8d76e605759c3f64a957d63ef96ada7c",
+        "GUID:1cd941934d098654fa21a13f28346412"
+    ],
+    "includePlatforms": [],
+    "excludePlatforms": [],
+    "allowUnsafeCode": true,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": false,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/vrmlib/Runtime/VrmLib.asmdef.meta b/Assets/External/VRM10/vrmlib/Runtime/VrmLib.asmdef.meta
new file mode 100644
index 000000000..963943ae8
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Runtime/VrmLib.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 2ef84b520212e174a94668c7a0862d3b
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Tests.meta b/Assets/External/VRM10/vrmlib/Tests.meta
new file mode 100644
index 000000000..415161beb
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Tests.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3a50a5aa0ee336c4eaa4c0bae409974b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Tests/HumanoidTests.cs b/Assets/External/VRM10/vrmlib/Tests/HumanoidTests.cs
new file mode 100644
index 000000000..ce88850ab
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Tests/HumanoidTests.cs
@@ -0,0 +1,28 @@
+using System;
+using System.IO;
+using VrmLib;
+using NUnit.Framework;
+
+namespace VrmLibTests
+{
+    public class HumanoidTests
+    {
+        DirectoryInfo RootPath
+        {
+            get
+            {
+                return new FileInfo(GetType().Assembly.Location).Directory.Parent.Parent.Parent.Parent;
+            }
+        }
+
+        [Test]
+        [TestCase("Assets/UniVrm.bvh")]
+        public void HumanoidTest(string filename)
+        {
+            var humanoid = new Humanoid();
+            Assert.False(humanoid.HasRequiredBones);
+
+            Assert.Throws(() => humanoid.Add(HumanoidBones.unknown, null));
+        }
+    }
+}
diff --git a/Assets/External/VRM10/vrmlib/Tests/HumanoidTests.cs.meta b/Assets/External/VRM10/vrmlib/Tests/HumanoidTests.cs.meta
new file mode 100644
index 000000000..2aef96a30
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Tests/HumanoidTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d23637d237cf4f947a623b9af659d1c8
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Tests/ModelTests.cs b/Assets/External/VRM10/vrmlib/Tests/ModelTests.cs
new file mode 100644
index 000000000..3edaa77a9
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Tests/ModelTests.cs
@@ -0,0 +1,23 @@
+using VrmLib;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace VrmLibTests
+{
+    public class ModelTests
+    {
+        [Test]
+        public void NodeTest()
+        {
+            var root = new Node("root");
+            var child = new Node("child")
+            {
+                LocalTranslation = Vector3.right
+            };
+            root.Add(child);
+            root.LocalTranslation = Vector3.right;
+
+            Assert.AreEqual(new Vector3(2, 0, 0), child.Translation);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/vrmlib/Tests/ModelTests.cs.meta b/Assets/External/VRM10/vrmlib/Tests/ModelTests.cs.meta
new file mode 100644
index 000000000..0d69b8900
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Tests/ModelTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fbfe2caf92208854ba9da33cc7868ae8
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRM10/vrmlib/Tests/VrmLib.Tests.asmdef b/Assets/External/VRM10/vrmlib/Tests/VrmLib.Tests.asmdef
new file mode 100644
index 000000000..9ccd6fb1b
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Tests/VrmLib.Tests.asmdef
@@ -0,0 +1,23 @@
+{
+    "name": "VrmLibTests",
+    "references": [
+        "GUID:2ef84b520212e174a94668c7a0862d3b",
+        "GUID:27619889b8ba8c24980f49ee34dbb44a",
+        "GUID:0acc523941302664db1f4e527237feb3"
+    ],
+    "includePlatforms": [
+        "Editor"
+    ],
+    "excludePlatforms": [],
+    "allowUnsafeCode": false,
+    "overrideReferences": true,
+    "precompiledReferences": [
+        "nunit.framework.dll"
+    ],
+    "autoReferenced": false,
+    "defineConstraints": [
+        "UNITY_INCLUDE_TESTS"
+    ],
+    "versionDefines": [],
+    "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/External/VRM10/vrmlib/Tests/VrmLib.Tests.asmdef.meta b/Assets/External/VRM10/vrmlib/Tests/VrmLib.Tests.asmdef.meta
new file mode 100644
index 000000000..2e07b9619
--- /dev/null
+++ b/Assets/External/VRM10/vrmlib/Tests/VrmLib.Tests.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 399ad757077e97e4dbe45efbfa5c24c0
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Animation/Importer/AnimationClipFactory.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Animation/Importer/AnimationClipFactory.cs
index b6ff3fa92..d570b7df2 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Animation/Importer/AnimationClipFactory.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Animation/Importer/AnimationClipFactory.cs
@@ -37,7 +37,7 @@ namespace VRMShaders
         {
             foreach (var kv in _runtimeClips)
             {
-                UnityObjectDestoyer.DestroyRuntimeOrEditor(kv.Value);
+                UnityObjectDestroyer.DestroyRuntimeOrEditor(kv.Value);
             }
             _runtimeClips.Clear();
         }
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/IAwaitCaller.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/IAwaitCaller.cs
index c97e4d0ce..877ae8ae0 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/IAwaitCaller.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/IAwaitCaller.cs
@@ -31,5 +31,11 @@ namespace VRMShaders
         /// 
         /// 
         Task Run(Func action);
+
+        /// 
+        /// 指定した時間が経過している場合のみ、NextFrame() を使って1フレーム待つ
+        /// 
+        /// タイムアウト時はNextFrame()を呼び出す。そうではない場合、Task.CompletedTaskを返す
+        Task NextFrameIfTimedOut();
     }
 }
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/ImmediateCaller.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/ImmediateCaller.cs
index f3e6d56a0..db71fe818 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/ImmediateCaller.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/ImmediateCaller.cs
@@ -23,5 +23,7 @@ namespace VRMShaders
         {
             return Task.FromResult(action());
         }
+
+        public Task NextFrameIfTimedOut() => NextFrame();
     }
 }
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyAwaitCaller.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyAwaitCaller.cs
index 23cc7b592..b583465ff 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyAwaitCaller.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyAwaitCaller.cs
@@ -10,14 +10,23 @@ namespace VRMShaders
     public sealed class RuntimeOnlyAwaitCaller : IAwaitCaller
     {
         private readonly NextFrameTaskScheduler _scheduler;
+        private readonly float                  _timeOutInSeconds;
+        private          float                  _lastTimeoutBaseTime;
 
-        public RuntimeOnlyAwaitCaller()
+        /// 
+        /// タイムアウト指定可能なコンストラクタ
+        /// 
+        /// NextFrameIfTimedOutがタイムアウトと見なす時間(秒単位)
+        public RuntimeOnlyAwaitCaller(float timeOutInSeconds = 1f / 1000f)
         {
             _scheduler = new NextFrameTaskScheduler();
+            _timeOutInSeconds = timeOutInSeconds;
+            ResetLastTimeoutBaseTime();
         }
 
         public Task NextFrame()
         {
+            ResetLastTimeoutBaseTime();
             var tcs = new TaskCompletionSource();
             _scheduler.Enqueue(() => tcs.SetResult(default));
             return tcs.Task;
@@ -32,5 +41,21 @@ namespace VRMShaders
         {
             return Task.Run(action);
         }
+
+        public Task NextFrameIfTimedOut() => CheckTimeout() ? NextFrame() : Task.CompletedTask;
+
+        private void ResetLastTimeoutBaseTime() => _lastTimeoutBaseTime = 0f;
+
+        private bool LastTimeoutBaseTimeNeedsReset => _lastTimeoutBaseTime == 0f;
+
+        private bool CheckTimeout()
+        {
+            float t = UnityEngine.Time.realtimeSinceStartup;
+            if (LastTimeoutBaseTimeNeedsReset)
+            {
+                _lastTimeoutBaseTime = t;
+            }
+            return (t - _lastTimeoutBaseTime) >= _timeOutInSeconds;
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs
new file mode 100644
index 000000000..97e8597fd
--- /dev/null
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Threading.Tasks;
+
+namespace VRMShaders
+{
+    /// 
+    /// Runtime (Build 後と、Editor Playing) での非同期ロードを実現する AwaitCaller.
+    /// WebGL など Thread が無いもの向け
+    /// 
+    public sealed class RuntimeOnlyNoThreadAwaitCaller : IAwaitCaller
+    {
+        private readonly NextFrameTaskScheduler _scheduler;
+        private readonly float                  _timeoutInSeconds;
+        private          float                  _lastTimeoutBaseTime;
+
+        /// 
+        /// タイムアウト指定可能なコンストラクタ
+        /// 
+        /// NextFrameIfTimedOutがタイムアウトと見なす時間(秒単位)
+        public RuntimeOnlyNoThreadAwaitCaller(float timeoutInSeconds = 1f / 1000f)
+        {
+            _scheduler = new NextFrameTaskScheduler();
+            _timeoutInSeconds = timeoutInSeconds;
+            ResetLastTimeoutBaseTime();
+        }
+
+        public Task NextFrame()
+        {
+            ResetLastTimeoutBaseTime();
+            var tcs = new TaskCompletionSource();
+            _scheduler.Enqueue(() => tcs.SetResult(default));
+            return tcs.Task;
+        }
+
+        public Task Run(Action action)
+        {
+            try
+            {
+                action();
+                return Task.FromResult(null);
+            }
+            catch (Exception ex)
+            {
+                return Task.FromException(ex);
+            }
+        }
+
+        public Task Run(Func action)
+        {
+            try
+            {
+                return Task.FromResult(action());
+            }
+            catch (Exception ex)
+            {
+                return Task.FromException(ex);
+            }
+        }
+
+        public Task NextFrameIfTimedOut() => CheckTimeout() ? NextFrame() : Task.CompletedTask;
+
+        private void ResetLastTimeoutBaseTime() => _lastTimeoutBaseTime = 0f;
+
+        private bool LastTimeoutBaseTimeNeedsReset => _lastTimeoutBaseTime == 0f;
+
+        private bool CheckTimeout()
+        {
+            float t = UnityEngine.Time.realtimeSinceStartup;
+            if (LastTimeoutBaseTimeNeedsReset)
+            {
+                _lastTimeoutBaseTime = t;
+            }
+            return (t - _lastTimeoutBaseTime) >= _timeoutInSeconds;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs.meta b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs.meta
new file mode 100644
index 000000000..42bdc91ae
--- /dev/null
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6d3630f9fecf62f4a8137907b0f7beb2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Material/Importer/MaterialDescriptor.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Material/Importer/MaterialDescriptor.cs
index b46f09bcd..8d51b12ec 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Material/Importer/MaterialDescriptor.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Material/Importer/MaterialDescriptor.cs
@@ -4,10 +4,10 @@ using UnityEngine;
 
 namespace VRMShaders
 {
-    public readonly struct MaterialDescriptor : IEquatable
+    public sealed class MaterialDescriptor
     {
         public readonly string Name;
-        public readonly string ShaderName;
+        public readonly Shader Shader;
         public readonly int? RenderQueue;
         public readonly IReadOnlyDictionary TextureSlots;
         public readonly IReadOnlyDictionary FloatValues;
@@ -17,16 +17,9 @@ namespace VRMShaders
 
         public SubAssetKey SubAssetKey => new SubAssetKey(SubAssetKey.MaterialType, Name);
 
-        public static readonly MaterialDescriptor Default = new MaterialDescriptor("__default__", "Standard", default,
-            new Dictionary(),
-            new Dictionary(),
-            new Dictionary(),
-            new Dictionary(),
-            new List>());
-
         public MaterialDescriptor(
             string name,
-            string shaderName,
+            Shader shader,
             int? renderQueue,
             IReadOnlyDictionary textureSlots,
             IReadOnlyDictionary floatValues,
@@ -35,7 +28,7 @@ namespace VRMShaders
             IReadOnlyList> actions)
         {
             Name = name;
-            ShaderName = shaderName;
+            Shader = shader;
             RenderQueue = renderQueue;
             TextureSlots = textureSlots;
             FloatValues = floatValues;
@@ -43,31 +36,5 @@ namespace VRMShaders
             Vectors = vectors;
             Actions = actions;
         }
-
-        public bool Equals(MaterialDescriptor other)
-        {
-            return Name == other.Name && ShaderName == other.ShaderName && RenderQueue == other.RenderQueue && Equals(TextureSlots, other.TextureSlots) && Equals(FloatValues, other.FloatValues) && Equals(Colors, other.Colors) && Equals(Vectors, other.Vectors) && Equals(Actions, other.Actions);
-        }
-
-        public override bool Equals(object obj)
-        {
-            return obj is MaterialDescriptor other && Equals(other);
-        }
-
-        public override int GetHashCode()
-        {
-            unchecked
-            {
-                var hashCode = (Name != null ? Name.GetHashCode() : 0);
-                hashCode = (hashCode * 397) ^ (ShaderName != null ? ShaderName.GetHashCode() : 0);
-                hashCode = (hashCode * 397) ^ RenderQueue.GetHashCode();
-                hashCode = (hashCode * 397) ^ (TextureSlots != null ? TextureSlots.GetHashCode() : 0);
-                hashCode = (hashCode * 397) ^ (FloatValues != null ? FloatValues.GetHashCode() : 0);
-                hashCode = (hashCode * 397) ^ (Colors != null ? Colors.GetHashCode() : 0);
-                hashCode = (hashCode * 397) ^ (Vectors != null ? Vectors.GetHashCode() : 0);
-                hashCode = (hashCode * 397) ^ (Actions != null ? Actions.GetHashCode() : 0);
-                return hashCode;
-            }
-        }
     }
 }
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Material/Importer/MaterialFactory.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Material/Importer/MaterialFactory.cs
index f8f0011ac..882818fbb 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Material/Importer/MaterialFactory.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Material/Importer/MaterialFactory.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Threading.Tasks;
 using UnityEngine;
 
@@ -17,15 +18,6 @@ namespace VRMShaders
             m_externalMap = externalMaterialMap;
         }
 
-        // TODO: UniVRM 0.x の方に処理を移したい
-        static Dictionary s_fallbackShaders = new Dictionary
-        {
-            {"VRM/UnlitTexture", "Unlit/Texture"},
-            {"VRM/UnlitTransparent", "Unlit/Transparent"},
-            {"VRM/UnlitCutout", "Unlit/Transparent Cutout"},
-            {"UniGLTF/StandardVColor", UniGLTF.UniUnlit.UniUnlitUtil.ShaderName},
-        };
-
         public struct MaterialLoadInfo
         {
             public SubAssetKey Key;
@@ -61,10 +53,7 @@ namespace VRMShaders
                 if (!x.UseExternal)
                 {
                     // 外部の '.asset' からロードしていない
-#if VRM_DEVELOP
-                    // Debug.Log($"Destroy {x.Asset}");
-#endif
-                    UnityObjectDestoyer.DestroyRuntimeOrEditor(x.Asset);
+                    UnityObjectDestroyer.DestroyRuntimeOrEditor(x.Asset);
                 }
             }
         }
@@ -112,24 +101,12 @@ namespace VRMShaders
                 getTexture = (x, y) => Task.FromResult(null);
             }
 
-            var shaderName = matDesc.ShaderName;
-            if (String.IsNullOrEmpty(shaderName))
+            if (matDesc.Shader == null)
             {
-                throw new Exception("no shader name");
-            }
-            if (s_fallbackShaders.TryGetValue(shaderName, out string fallback))
-            {
-                Debug.LogWarning($"fallback: {shaderName} => {fallback}");
-                shaderName = fallback;
+                throw new ArgumentNullException(nameof(matDesc.Shader));
             }
 
-            var shader = Shader.Find(shaderName);
-            if (shader == null)
-            {
-                throw new Exception($"shader: {shaderName} not found");
-            }
-
-            material = new Material(shader);
+            material = new Material(matDesc.Shader);
             material.name = matDesc.SubAssetKey.Name;
 
             foreach (var kv in matDesc.TextureSlots)
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/PathObject.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/PathObject.cs
new file mode 100644
index 000000000..4ba004bfa
--- /dev/null
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/PathObject.cs
@@ -0,0 +1,204 @@
+using System;
+using System.IO;
+using UnityEngine;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+namespace VRMShaders
+{
+    /// 
+    /// UniGLTF.UnityPath (Assets の ひとつ上がルート) をすべてのパスが扱えるように拡張するのが趣旨。
+    /// readonly struct で Immutable であるという主張。
+    /// 
+    public readonly struct PathObject
+    {
+        /// 
+        /// * Delemeter は / を保証
+        /// * .. を解決済み
+        /// * フルパス
+        /// * 末尾に / を付けない
+        /// 
+        public string FullPath { get; }
+
+        public string Extension => Path.GetExtension(FullPath);
+
+        public string Stem => Path.GetFileNameWithoutExtension(FullPath);
+
+        public PathObject Parent => FromFullPath(Path.GetDirectoryName(FullPath));
+
+        public bool IsUnderAsset => IsDescendantOf(UnityAssets);
+
+        public bool Exists => System.IO.File.Exists(FullPath);
+
+        /// 
+        /// AssetDatabase の引き数になるパスを想定。
+        /// Assets のひとつ上を 基準とする相対パス。
+        /// Application.dataPath は Assets を得る。
+        /// 
+        /// 
+        public string UnityAssetPath
+        {
+            get
+            {
+                var root = UnityRoot;
+                if (!IsDescendantOf(UnityRoot))
+                {
+                    throw new ArgumentException($"{FullPath} is not under UnityAssetPath");
+                }
+                return FullPath.Substring(root.FullPath.Length + 1);
+            }
+        }
+
+        public static PathObject UnityRoot { get; } = FromFullPath(Path.GetDirectoryName(Application.dataPath));
+
+        // 記述順に解決?
+        public static PathObject UnityAssets { get; } = UnityRoot.Child("Assets/");
+
+        PathObject(string src)
+        {
+            if (string.IsNullOrEmpty(src))
+            {
+                throw new ArgumentNullException();
+            }
+            src = Path.GetFullPath(src).Replace('\\', '/');
+            if (src.Length > 1 && src[src.Length - 1] == '/')
+            {
+                // drop last /
+                src = src.Substring(0, src.Length - 1);
+            }
+            if (src[0] == '/')
+            {
+                FullPath = src;
+            }
+            else
+            {
+                if (src.Length >= 3 && src[1] == ':' && src[2] == '/')
+                {
+                    FullPath = src;
+                }
+                else
+                {
+                    throw new ArgumentException($"{src} is not fullpath");
+                }
+            }
+        }
+
+        public override string ToString()
+        {
+            try
+            {
+                var assetPath = UnityAssetPath;
+                return $"";
+            }
+            catch (ArgumentException)
+            {
+                return $"";
+            }
+        }
+
+        /// start with "X:/" on Windows else "/"
+        /// 
+        public static PathObject FromFullPath(string src)
+        {
+            return new PathObject(src);
+        }
+
+        /// AssetDatabase が使うパス
+        /// 
+        public static PathObject FromUnityAssetPath(string src)
+        {
+            return UnityRoot.Child(src);
+        }
+
+        public static bool TryGetFromEnvironmentVariable(string key, out PathObject dst)
+        {
+            var value = System.Environment.GetEnvironmentVariable(key);
+            if (string.IsNullOrEmpty(value))
+            {
+                dst = default;
+                return false;
+            }
+            dst = PathObject.FromFullPath(value);
+            return true;
+        }
+
+        public PathObject Child(string child)
+        {
+            return FromFullPath(Path.Combine(FullPath, child));
+        }
+
+        public bool IsDescendantOf(PathObject ascendant)
+        {
+            if (!FullPath.StartsWith(ascendant.FullPath))
+            {
+                return false;
+            }
+            if (FullPath.Length <= ascendant.FullPath.Length || FullPath[ascendant.FullPath.Length] != '/')
+            {
+                return false;
+            }
+            return true;
+        }
+
+        public byte[] ReadAllBytes()
+        {
+            return File.ReadAllBytes(FullPath);
+        }
+
+        public void WriteAllBytes(byte[] data)
+        {
+            File.WriteAllBytes(FullPath, data);
+        }
+
+#if UNITY_EDITOR
+        public static bool TryGetFromAsset(UnityEngine.Object src, out PathObject dst)
+        {
+            if (src == null)
+            {
+                dst = default;
+                return false;
+            }
+
+            var assetPath = AssetDatabase.GetAssetPath(src);
+            if (!string.IsNullOrEmpty(assetPath))
+            {
+                dst = FromUnityAssetPath(assetPath);
+                return true;
+            }
+
+            var prefab = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(src);
+            if (!string.IsNullOrEmpty(prefab))
+            {
+                dst = FromUnityAssetPath(prefab);
+                return true;
+            }
+
+            dst = default;
+            return false;
+
+        }
+
+        public void ImportAsset()
+        {
+            AssetDatabase.ImportAsset(UnityAssetPath);
+        }
+
+        public bool TrySaveDialog(string title, string name, out PathObject dst)
+        {
+            var path = EditorUtility.SaveFilePanel(
+                title,
+                FullPath,
+                name,
+                "vrm");
+            if (string.IsNullOrEmpty(path))
+            {
+                dst = default;
+                return false;
+            }
+            dst = PathObject.FromFullPath(path);
+            return true;
+        }
+#endif
+    }
+}
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/PathObject.cs.meta b/Assets/External/VRMShaders/GLTF/IO/Runtime/PathObject.cs.meta
new file mode 100644
index 000000000..0c5fa088f
--- /dev/null
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/PathObject.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d16607c9cf9d05e46b5beec82002d4ef
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs
index d9bd042b0..ffd1e18f7 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs
@@ -55,9 +55,14 @@ namespace VRMShaders
 
         public SubAssetKey(Type type, string name)
         {
-            if (type == null || string.IsNullOrEmpty(name))
+            if (type == null)
             {
-                throw new System.ArgumentNullException();
+                throw new System.ArgumentNullException("type");
+            }
+
+            if (string.IsNullOrEmpty(name))
+            {
+                throw new System.ArgumentNullException("name");
             }
 
             if (!type.IsSubclassOf(typeof(UnityEngine.Object)))
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/ITextureExporter.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/ITextureExporter.cs
index e6bb6f0a0..bb132fcae 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/ITextureExporter.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/ITextureExporter.cs
@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System;
 using UnityEngine;
 
 namespace VRMShaders
@@ -8,7 +8,7 @@ namespace VRMShaders
     ///
     /// glTF 拡張で Texture の用途を増やす必要がある場合は、この interface を継承して実装すればよい。
     /// 
-    public interface ITextureExporter
+    public interface ITextureExporter: IDisposable
     {
         /// 
         /// 指定の Texture を、 sRGB 色空間の値を持つ Texture に出力するように指示する。
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/TextureExportParam.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/TextureExportParam.cs
index 447514a8e..45aeac9a4 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/TextureExportParam.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/TextureExportParam.cs
@@ -12,9 +12,11 @@ namespace VRMShaders
         public float OptionFactor { get; }
 
         public bool NeedsAlpha { get; set; }
-        public Func Creator { get; set; }
+        public Func<(Texture2D, bool IsDisposable)> Creator { get; set; }
 
-        public TextureExportParam(TextureExportTypes exportType, ColorSpace exportColorSpace, Texture primaryTexture, Texture secondaryTexture, float optionFactor, bool needsAlpha, Func creator)
+        public TextureExportParam(TextureExportTypes exportType, ColorSpace exportColorSpace, 
+            Texture primaryTexture, Texture secondaryTexture, float optionFactor, bool needsAlpha, 
+            Func<(Texture2D, bool IsDisposable)> creator)
         {
             ExportType = exportType;
             ExportColorSpace = exportColorSpace;
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/TextureExporter.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/TextureExporter.cs
index 3b4229dc6..151f30242 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/TextureExporter.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Exporter/TextureExporter.cs
@@ -8,10 +8,11 @@ namespace VRMShaders
     /// glTF にエクスポートする変換方式を蓄えて index を確定させる。
     /// Exporter の最後で Export() でまとめて変換する。
     /// 
-    public sealed class TextureExporter : IDisposable, ITextureExporter
+    public sealed class TextureExporter : ITextureExporter
     {
         private readonly ITextureSerializer _textureSerializer;
         private readonly List _exportingList = new List();
+        private readonly List _disposables = new List();
 
         public TextureExporter(ITextureSerializer textureSerializer)
         {
@@ -20,6 +21,22 @@ namespace VRMShaders
 
         public void Dispose()
         {
+            foreach (var o in _disposables)
+            {
+                if (Application.isEditor)
+                {
+                    GameObject.DestroyImmediate(o);
+                }
+                else
+                {
+                    GameObject.Destroy(o);
+                }
+            }
+        }
+
+        private void PushDisposable(UnityEngine.Texture2D disposable)
+        {
+            _disposables.Add(disposable);
         }
 
         /// 
@@ -31,7 +48,11 @@ namespace VRMShaders
             for (var idx = 0; idx < _exportingList.Count; ++idx)
             {
                 var exporting = _exportingList[idx];
-                var texture = exporting.Creator();
+                var (texture, isDisposable) = exporting.Creator();
+                if (isDisposable)
+                {
+                    PushDisposable(texture);
+                }
                 exportedTextures.Add((texture, exporting.ExportColorSpace));
             }
             return exportedTextures;
@@ -98,8 +119,8 @@ namespace VRMShaders
                 {
                     _textureSerializer.ModifyTextureAssetBeforeExporting(metallicSmoothTexture);
                     _textureSerializer.ModifyTextureAssetBeforeExporting(occlusionTexture);
-                    return OcclusionMetallicRoughnessConverter.Export(metallicSmoothTexture, smoothness,
-                        occlusionTexture);
+                    return (OcclusionMetallicRoughnessConverter.Export(metallicSmoothTexture, smoothness,
+                        occlusionTexture), true);
                 });
             if (TryGetExistsParam(param, out var existsIdx))
             {
@@ -125,7 +146,7 @@ namespace VRMShaders
                 false, () =>
                 {
                     _textureSerializer.ModifyTextureAssetBeforeExporting(src);
-                    return NormalConverter.Export(src);
+                    return (NormalConverter.Export(src), true);
                 });
             if (TryGetExistsParam(param, out var existsIdx))
             {
@@ -142,10 +163,11 @@ namespace VRMShaders
             }
         }
 
-        private Texture2D ConvertTextureSimple(Texture src, bool needsAlpha, ColorSpace exportColorSpace)
+        private (Texture2D, bool IsDisposable) ConvertTextureSimple(Texture src, bool needsAlpha, ColorSpace exportColorSpace)
         {
             // get Texture2D
             var texture2D = src as Texture2D;
+            var isDisposable = false;
             if (_textureSerializer.CanExportAsEditorAssetFile(texture2D, exportColorSpace))
             {
                 // NOTE: 生のファイルとして出力可能な場合、何もせずそのまま Texture2D を渡す。
@@ -156,8 +178,9 @@ namespace VRMShaders
             {
                 _textureSerializer.ModifyTextureAssetBeforeExporting(src);
                 texture2D = TextureConverter.CopyTexture(src, exportColorSpace, needsAlpha, null);
+                isDisposable = true;
             }
-            return texture2D;
+            return (texture2D, isDisposable);
         }
 
         private bool TryGetExistsParam(TextureExportParam param, out int existsIdx)
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/DeserializingTextureInfo.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/DeserializingTextureInfo.cs
index 9d9106acc..a7e6676d2 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/DeserializingTextureInfo.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/DeserializingTextureInfo.cs
@@ -42,6 +42,8 @@ namespace VRMShaders
         /// 
         public TextureWrapMode WrapModeV { get; }
 
+        public TextureImportTypes ImportTypes { get; }
+
         public DeserializingTextureInfo(byte[] imageData, string dataMimeType, ColorSpace colorSpace, bool useMipmap, FilterMode filterMode, TextureWrapMode wrapModeU, TextureWrapMode wrapModeV)
         {
             ImageData = imageData;
@@ -53,7 +55,7 @@ namespace VRMShaders
             WrapModeV = wrapModeV;
         }
 
-        public DeserializingTextureInfo(byte[] imageData, string dataMimeType, ColorSpace colorSpace, SamplerParam samplerParam)
+        public DeserializingTextureInfo(byte[] imageData, string dataMimeType, ColorSpace colorSpace, SamplerParam samplerParam, TextureImportTypes importTypes)
         {
             ImageData = imageData;
             DataMimeType = dataMimeType;
@@ -62,6 +64,7 @@ namespace VRMShaders
             FilterMode = samplerParam.FilterMode;
             WrapModeU = samplerParam.WrapModesU;
             WrapModeV = samplerParam.WrapModesV;
+            ImportTypes = importTypes;
         }
     }
 }
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureDescriptor.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureDescriptor.cs
index 37b4ea2c7..ac9b01850 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureDescriptor.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureDescriptor.cs
@@ -52,6 +52,10 @@ namespace VRMShaders
             GetTextureBytesAsync i4,
             GetTextureBytesAsync i5)
         {
+            if (string.IsNullOrEmpty(name))
+            {
+                throw new ArgumentNullException(nameof(name));
+            }
             UnityObjectName = name;
             Offset = offset;
             Scale = scale;
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureFactory.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureFactory.cs
index 68a80c458..e4590d546 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureFactory.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureFactory.cs
@@ -36,6 +36,10 @@ namespace VRMShaders
 
         public void Dispose()
         {
+            foreach (var (k, v) in _textureCache)
+            {
+                UnityObjectDestroyer.DestroyRuntimeOrEditor(v);
+            }
             _textureCache.Clear();
         }
 
@@ -80,7 +84,7 @@ namespace VRMShaders
                         // https://docs.unity3d.com/2018.4/Documentation/Manual/StandardShaderMaterialParameterNormalMap.html
                         var data0 = await texDesc.Index0();
                         var rawTexture = await TextureDeserializer.LoadTextureAsync(
-                            new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler),
+                            new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
                             awaitCaller);
                         rawTexture.name = subAssetKey.Name;
                         _textureCache.Add(subAssetKey, rawTexture);
@@ -96,14 +100,14 @@ namespace VRMShaders
                         {
                             var data0 = await texDesc.Index0();
                             metallicRoughnessTexture = await TextureDeserializer.LoadTextureAsync(
-                                new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler),
+                                new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
                                 awaitCaller);
                         }
                         if (texDesc.Index1 != null)
                         {
                             var data1 = await texDesc.Index1();
                             occlusionTexture = await TextureDeserializer.LoadTextureAsync(
-                                new DeserializingTextureInfo(data1?.binary, data1?.mimeType, ColorSpace.Linear, texDesc.Sampler),
+                                new DeserializingTextureInfo(data1?.binary, data1?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
                                 awaitCaller);
                         }
 
@@ -114,8 +118,8 @@ namespace VRMShaders
                         //       したがって合成後の Texture に Sampler Param を設定する必要があるが、エッジケースで不整合な結果になる可能性がある.
                         combinedTexture.SetSampler(texDesc.Sampler);
                         _textureCache.Add(subAssetKey, combinedTexture);
-                        UnityObjectDestoyer.DestroyRuntimeOrEditor(metallicRoughnessTexture);
-                        UnityObjectDestoyer.DestroyRuntimeOrEditor(occlusionTexture);
+                        UnityObjectDestroyer.DestroyRuntimeOrEditor(metallicRoughnessTexture);
+                        UnityObjectDestroyer.DestroyRuntimeOrEditor(occlusionTexture);
                         return combinedTexture;
                     }
 
@@ -123,7 +127,7 @@ namespace VRMShaders
                     {
                         var data0 = await texDesc.Index0();
                         var rawTexture = await TextureDeserializer.LoadTextureAsync(
-                            new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.sRGB, texDesc.Sampler),
+                            new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.sRGB, texDesc.Sampler, texDesc.TextureType),
                             awaitCaller);
                         rawTexture.name = subAssetKey.Name;
                         _textureCache.Add(subAssetKey, rawTexture);
@@ -133,7 +137,7 @@ namespace VRMShaders
                     {
                         var data0 = await texDesc.Index0();
                         var rawTexture = await TextureDeserializer.LoadTextureAsync(
-                            new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler),
+                            new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
                             awaitCaller);
                         rawTexture.name = subAssetKey.Name;
                         _textureCache.Add(subAssetKey, rawTexture);
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/UnityTextureDeserializer.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/UnityTextureDeserializer.cs
index 2d5a1b174..14ce16d55 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/UnityTextureDeserializer.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Texture/Importer/UnityTextureDeserializer.cs
@@ -18,7 +18,14 @@ namespace VRMShaders
                 case "image/jpeg":
                     break;
                 default:
-                    Debug.LogWarning($"Texture image MIME type `{textureInfo.DataMimeType}` is not supported.");
+                    if (string.IsNullOrEmpty(textureInfo.DataMimeType))
+                    {
+                        Debug.Log($"Texture image MIME type is empty.");
+                    }
+                    else
+                    {
+                        Debug.Log($"Texture image MIME type `{textureInfo.DataMimeType}` is not supported.");
+                    }
                     break;
             }
 
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/KeyValuePariExtensions.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/KeyValuePariExtensions.cs
deleted file mode 100644
index 91a41891f..000000000
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/KeyValuePariExtensions.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Collections.Generic;
-
-namespace VRMShaders
-{
-    public static class KeyValuePariExtensions
-    {
-        public static void Deconstruct(this KeyValuePair pair, out T key, out U value)
-        {
-            key = pair.Key;
-            value = pair.Value;
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/KeyValuePariExtensions.cs.meta b/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/KeyValuePariExtensions.cs.meta
deleted file mode 100644
index ec64d27cb..000000000
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/KeyValuePariExtensions.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 7dd6ef3302d21eb4b83c4f8f2c1e47cf
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/Symbols.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/Symbols.cs
index 3766e019c..2308ce5f2 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/Symbols.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/Symbols.cs
@@ -15,6 +15,18 @@ namespace VRMShaders
                 return true;
 #else
                 return false;
+#endif
+            }
+        }
+
+        public static bool VRM_NORMALIZE_BLENDSHAPE_TANGENT
+        {
+            get
+            {
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+                return true;
+#else
+                return false;
 #endif
             }
         }
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/UnityObjectDestroyer.cs b/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/UnityObjectDestroyer.cs
index d35cffc54..bf5df6e9f 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/UnityObjectDestroyer.cs
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/Util/UnityObjectDestroyer.cs
@@ -2,7 +2,7 @@ using UnityEngine;
 
 namespace VRMShaders
 {
-    public static class UnityObjectDestoyer
+    public static class UnityObjectDestroyer
     {
         public static void DestroyRuntimeOrEditor(UnityEngine.Object o)
         {
diff --git a/Assets/External/VRMShaders/GLTF/IO/Runtime/VRMShaders.GLTF.IO.Runtime.asmdef b/Assets/External/VRMShaders/GLTF/IO/Runtime/VRMShaders.GLTF.IO.Runtime.asmdef
index 3b9bbeeb0..54472abde 100644
--- a/Assets/External/VRMShaders/GLTF/IO/Runtime/VRMShaders.GLTF.IO.Runtime.asmdef
+++ b/Assets/External/VRMShaders/GLTF/IO/Runtime/VRMShaders.GLTF.IO.Runtime.asmdef
@@ -1,8 +1,6 @@
 {
     "name": "VRMShaders.GLTF.IO.Runtime",
-    "references": [
-        "GUID:60c8346e00a8ddd4cafc5a02eceeec57"
-    ],
+    "references": [],
     "includePlatforms": [],
     "excludePlatforms": [],
     "allowUnsafeCode": false,
diff --git a/Assets/External/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs b/Assets/External/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs
new file mode 100644
index 000000000..1a14bda0d
--- /dev/null
+++ b/Assets/External/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs
@@ -0,0 +1,28 @@
+using System.Linq;
+using NUnit.Framework;
+using UnityEditor;
+using UnityEngine;
+
+namespace VRMShaders
+{
+    public sealed class PathObjectTests
+    {
+        [Test]
+        public void Test()
+        {
+            var dataPath = PathObject.FromFullPath(Application.dataPath);
+
+            Assert.AreEqual("Assets", dataPath.Stem);
+
+            // UnityRoot
+            Assert.True(dataPath.IsDescendantOf(PathObject.UnityRoot));
+            // UnityRoot/Assets
+            Assert.False(dataPath.IsDescendantOf(PathObject.UnityAssets));
+            Assert.AreEqual(dataPath, PathObject.UnityAssets);
+
+            Assert.AreEqual(PathObject.UnityRoot.Child("Assets"), PathObject.UnityAssets);
+            Assert.AreEqual(PathObject.UnityAssets.Parent, PathObject.UnityRoot);
+            Assert.AreEqual("Assets", PathObject.UnityAssets.UnityAssetPath);
+        }
+    }
+}
diff --git a/Assets/External/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs.meta b/Assets/External/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs.meta
new file mode 100644
index 000000000..23b001bcf
--- /dev/null
+++ b/Assets/External/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 45383f6fca5a57246b70f3919b582b7d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Editor/ShaderPropMenu.cs b/Assets/External/VRMShaders/VRM/IO/Editor/ShaderPropMenu.cs
deleted file mode 100644
index 059c7fb87..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Editor/ShaderPropMenu.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using System.Reflection;
-using System.Linq;
-using UnityEditor;
-using UnityEngine;
-using System.IO;
-using UniGLTF.ShaderPropExporter;
-using System.Collections.Generic;
-
-namespace UniGLTF
-{
-    public static class ShaderPropMenu
-    {
-        public static void PreExport()
-        {
-            foreach (var fi in typeof(PreExportShaders).GetFields(
-                BindingFlags.Static
-                | BindingFlags.Public
-                | BindingFlags.NonPublic))
-            {
-                var attr = fi.GetCustomAttributes(true).FirstOrDefault(y => y is PreExportShadersAttribute);
-                if (attr != null)
-                {
-                    var supportedShaders = fi.GetValue(null) as SupportedShader[];
-                    foreach (var supported in supportedShaders)
-                    {
-                        PreExport(supported);
-                    }
-                }
-            }
-        }
-
-        static string EscapeShaderName(string name)
-        {
-            return name.Replace("/", "_").Replace(" ", "_");
-        }
-
-        static string ExportDir
-        {
-            get
-            {
-                return Application.dataPath + "/VRM/ShaderProperty/Runtime";
-            }
-        }
-
-        static void PreExport(SupportedShader supportedShader)
-        {
-            var shader = Shader.Find(supportedShader.ShaderName);
-            var props = ShaderProps.FromShader(shader);
-
-            var path = Path.Combine(ExportDir, supportedShader.TargetFolder);
-            path = Path.Combine(path, EscapeShaderName(supportedShader.ShaderName) + ".cs").Replace("\\", "/");
-            Debug.LogFormat("PreExport: {0}", path);
-            File.WriteAllText(path, ToString(props, shader.name));
-        }
-
-        static string ToString(ShaderProps props, string shaderName)
-        {
-            var list = new List();
-            foreach (var prop in props.Properties)
-            {
-                list.Add(string.Format("new ShaderProperty(\"{0}\", ShaderPropertyType.{1})\r\n", prop.Key, prop.ShaderPropertyType));
-            }
-
-            return string.Format(@"using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{{
-    public static partial class PreShaderPropExporter
-    {{
-        [PreExportShader]
-        static KeyValuePair {0} 
-        {{
-            get 
-            {{
-                return new KeyValuePair(
-                    ""{1}"",
-                    new ShaderProps
-                    {{
-                        Properties = new ShaderProperty[]{{
-{2}
-                        }}
-                    }}
-                );
-            }}
-        }}
-    }}
-}}
-"
-, EscapeShaderName(shaderName)
-, shaderName
-, string.Join(",", list.ToArray()));
-        }
-
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Editor/ShaderPropMenu.cs.meta b/Assets/External/VRMShaders/VRM/IO/Editor/ShaderPropMenu.cs.meta
deleted file mode 100644
index 0626004d1..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Editor/ShaderPropMenu.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 5eb12c186c6337e4db278b5f01d47cae
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/PreExportShaders_GLTF.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/PreExportShaders_GLTF.cs
deleted file mode 100644
index f6fcb7675..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/PreExportShaders_GLTF.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreExportShaders
-    {
-        const string GLTF_FOLDER = "GLTF";
-
-#pragma warning disable 414
-        [PreExportShaders]
-        static SupportedShader[] SupportedShaders = new SupportedShader[]
-        {
-            new SupportedShader(GLTF_FOLDER, "Standard"),
-            new SupportedShader(GLTF_FOLDER, "Unlit/Color"),
-            new SupportedShader(GLTF_FOLDER, "Unlit/Texture"),
-            new SupportedShader(GLTF_FOLDER, "Unlit/Transparent"),
-            new SupportedShader(GLTF_FOLDER, "Unlit/Transparent Cutout"),
-            new SupportedShader(GLTF_FOLDER, "UniGLTF/UniUnlit"),
-        };
-#pragma warning restore 414
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/PreExportShaders_GLTF.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/PreExportShaders_GLTF.cs.meta
deleted file mode 100644
index fa17b5099..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/PreExportShaders_GLTF.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 90dcef1978c51e74386b76d77689dc82
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Standard.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Standard.cs
deleted file mode 100644
index aa5b342d2..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Standard.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair Standard 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "Standard",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_Color", ShaderPropertyType.Color)
-,new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_Cutoff", ShaderPropertyType.Range)
-,new ShaderProperty("_Glossiness", ShaderPropertyType.Range)
-,new ShaderProperty("_GlossMapScale", ShaderPropertyType.Range)
-,new ShaderProperty("_SmoothnessTextureChannel", ShaderPropertyType.Float)
-,new ShaderProperty("_Metallic", ShaderPropertyType.Range)
-,new ShaderProperty("_MetallicGlossMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_SpecularHighlights", ShaderPropertyType.Float)
-,new ShaderProperty("_GlossyReflections", ShaderPropertyType.Float)
-,new ShaderProperty("_BumpScale", ShaderPropertyType.Float)
-,new ShaderProperty("_BumpMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_Parallax", ShaderPropertyType.Range)
-,new ShaderProperty("_ParallaxMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_OcclusionStrength", ShaderPropertyType.Range)
-,new ShaderProperty("_OcclusionMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_EmissionColor", ShaderPropertyType.Color)
-,new ShaderProperty("_EmissionMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_DetailMask", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_DetailAlbedoMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_DetailNormalMapScale", ShaderPropertyType.Float)
-,new ShaderProperty("_DetailNormalMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_UVSec", ShaderPropertyType.Float)
-,new ShaderProperty("_Mode", ShaderPropertyType.Float)
-,new ShaderProperty("_SrcBlend", ShaderPropertyType.Float)
-,new ShaderProperty("_DstBlend", ShaderPropertyType.Float)
-,new ShaderProperty("_ZWrite", ShaderPropertyType.Float)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/UniGLTF_UniUnlit.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/UniGLTF_UniUnlit.cs
deleted file mode 100644
index ce4503a7b..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/UniGLTF_UniUnlit.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair UniGLTF_UniUnlit 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "UniGLTF/UniUnlit",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_Color", ShaderPropertyType.Color)
-,new ShaderProperty("_Cutoff", ShaderPropertyType.Range)
-,new ShaderProperty("_BlendMode", ShaderPropertyType.Float)
-,new ShaderProperty("_CullMode", ShaderPropertyType.Float)
-,new ShaderProperty("_VColBlendMode", ShaderPropertyType.Float)
-,new ShaderProperty("_SrcBlend", ShaderPropertyType.Float)
-,new ShaderProperty("_DstBlend", ShaderPropertyType.Float)
-,new ShaderProperty("_ZWrite", ShaderPropertyType.Float)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/UniGLTF_UniUnlit.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/UniGLTF_UniUnlit.cs.meta
deleted file mode 100644
index c1315f41d..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/UniGLTF_UniUnlit.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: ad4b6b115b83ecd48a513f697afc95f0
-timeCreated: 1537860074
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Color.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Color.cs
deleted file mode 100644
index 1ef6c3a02..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Color.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair Unlit_Color 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "Unlit/Color",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_Color", ShaderPropertyType.Color)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Color.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Color.cs.meta
deleted file mode 100644
index 4f97a3c69..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Color.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 4f91421c5846d5d48933d2ee4ffeeceb
-timeCreated: 1535186213
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Texture.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Texture.cs
deleted file mode 100644
index ed6f487a3..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Texture.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair Unlit_Texture 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "Unlit/Texture",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Texture.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Texture.cs.meta
deleted file mode 100644
index 83320688d..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Texture.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 8273e1e61ad8e914baae94d06836f2ad
-timeCreated: 1535186213
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent.cs
deleted file mode 100644
index cad3b4b94..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair Unlit_Transparent 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "Unlit/Transparent",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent.cs.meta
deleted file mode 100644
index f64c65586..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: b98a8ee8ca13abb43809305cc4e5571a
-timeCreated: 1535186213
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent_Cutout.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent_Cutout.cs
deleted file mode 100644
index ebe366b5b..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent_Cutout.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair Unlit_Transparent_Cutout 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "Unlit/Transparent Cutout",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_Cutoff", ShaderPropertyType.Range)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent_Cutout.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent_Cutout.cs.meta
deleted file mode 100644
index 5ffeb3f48..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/GLTF/Unlit_Transparent_Cutout.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 844490f13976543478d82efe28251941
-timeCreated: 1535186301
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/PreShaderPropExporter.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/PreShaderPropExporter.cs
index 8bc5988cb..50c6e6cf4 100644
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/PreShaderPropExporter.cs
+++ b/Assets/External/VRMShaders/VRM/IO/Runtime/PreShaderPropExporter.cs
@@ -1,69 +1,63 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using UnityEngine;
-#if UNITY_EDITOR
-using UnityEditor;
-#endif
-
-
-namespace UniGLTF.ShaderPropExporter
+namespace UniGLTF.ShaderPropExporter
 {
-    public class PreExportShadersAttribute : Attribute { }
-    public class PreExportShaderAttribute : Attribute { }
-
-    public struct SupportedShader
+    /// 
+    /// TODO: MToon にひきとってもらう
+    /// 
+    public static class PreShaderPropExporter
     {
-        public string TargetFolder;
-        public string ShaderName;
-
-        public SupportedShader(string targetFolder, string shaderName)
+        const string ShaderName = "VRM/MToon";
+        public static ShaderProps GetPropsForMToon()
         {
-            TargetFolder = targetFolder;
-            ShaderName = shaderName;
+            return VRM_MToon;
         }
-    }
 
-    public static partial class PreShaderPropExporter
-    {
-        public static readonly string[] VRMExtensionShaders = new string[]
-        {
-            "VRM/UnlitTransparentZWrite",
-            "VRM/MToon"
-        };
-
-        static Dictionary m_shaderPropMap;
-
-        public static ShaderProps GetPropsForSupportedShader(string shaderName)
-        {
-            if (m_shaderPropMap == null)
-            {
-                m_shaderPropMap = new Dictionary();
-                foreach (var prop in typeof(PreShaderPropExporter).GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
-                {
-                    if (prop.GetCustomAttributes(typeof(PreExportShaderAttribute), true).Any())
+        static ShaderProps VRM_MToon =
+                    new ShaderProps
                     {
-                        var kv = (KeyValuePair)prop.GetValue(null, null);
-                        m_shaderPropMap.Add(kv.Key, kv.Value);
-                    }
-                }
-            }
-
-            ShaderProps props;
-            if (m_shaderPropMap.TryGetValue(shaderName, out props))
-            {
-                return props;
-            }
-
-#if UNITY_EDITOR
-            // fallback
-            Debug.LogWarningFormat("{0} is not predefined shader. Use ShaderUtil", shaderName);
-            var shader = Shader.Find(shaderName);
-            return ShaderProps.FromShader(shader);
-#else
-            return null;
-#endif
-        }
+                        Properties = new ShaderProperty[]{
+new ShaderProperty("_Cutoff", ShaderPropertyType.Range)
+,new ShaderProperty("_Color", ShaderPropertyType.Color)
+,new ShaderProperty("_ShadeColor", ShaderPropertyType.Color)
+,new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_ShadeTexture", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_BumpScale", ShaderPropertyType.Float)
+,new ShaderProperty("_BumpMap", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_ReceiveShadowRate", ShaderPropertyType.Range)
+,new ShaderProperty("_ReceiveShadowTexture", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_ShadingGradeRate", ShaderPropertyType.Range)
+,new ShaderProperty("_ShadingGradeTexture", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_ShadeShift", ShaderPropertyType.Range)
+,new ShaderProperty("_ShadeToony", ShaderPropertyType.Range)
+,new ShaderProperty("_LightColorAttenuation", ShaderPropertyType.Range)
+,new ShaderProperty("_IndirectLightIntensity", ShaderPropertyType.Range)
+,new ShaderProperty("_RimColor", ShaderPropertyType.Color)
+,new ShaderProperty("_RimTexture", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_RimLightingMix", ShaderPropertyType.Range)
+,new ShaderProperty("_RimFresnelPower", ShaderPropertyType.Range)
+,new ShaderProperty("_RimLift", ShaderPropertyType.Range)
+,new ShaderProperty("_SphereAdd", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_EmissionColor", ShaderPropertyType.Color)
+,new ShaderProperty("_EmissionMap", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_OutlineWidthTexture", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_OutlineWidth", ShaderPropertyType.Range)
+,new ShaderProperty("_OutlineScaledMaxDistance", ShaderPropertyType.Range)
+,new ShaderProperty("_OutlineColor", ShaderPropertyType.Color)
+,new ShaderProperty("_OutlineLightingMix", ShaderPropertyType.Range)
+,new ShaderProperty("_UvAnimMaskTexture", ShaderPropertyType.TexEnv)
+,new ShaderProperty("_UvAnimScrollX", ShaderPropertyType.Float)
+,new ShaderProperty("_UvAnimScrollY", ShaderPropertyType.Float)
+,new ShaderProperty("_UvAnimRotation", ShaderPropertyType.Float)
+,new ShaderProperty("_MToonVersion", ShaderPropertyType.Float)
+,new ShaderProperty("_DebugMode", ShaderPropertyType.Float)
+,new ShaderProperty("_BlendMode", ShaderPropertyType.Float)
+,new ShaderProperty("_OutlineWidthMode", ShaderPropertyType.Float)
+,new ShaderProperty("_OutlineColorMode", ShaderPropertyType.Float)
+,new ShaderProperty("_CullMode", ShaderPropertyType.Float)
+,new ShaderProperty("_OutlineCullMode", ShaderPropertyType.Float)
+,new ShaderProperty("_SrcBlend", ShaderPropertyType.Float)
+,new ShaderProperty("_DstBlend", ShaderPropertyType.Float)
+,new ShaderProperty("_ZWrite", ShaderPropertyType.Float)
+                        }
+                    };
     }
 }
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM.meta
deleted file mode 100644
index 6d0ee19da..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM.meta
+++ /dev/null
@@ -1,8 +0,0 @@
-fileFormatVersion: 2
-guid: eb31f565eeca6164694b06ccfe3bc251
-folderAsset: yes
-DefaultImporter:
-  externalObjects: {}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/PreExportShaders_VRM.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/PreExportShaders_VRM.cs
deleted file mode 100644
index f246304c9..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/PreExportShaders_VRM.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreExportShaders
-    {
-        const string VRM_TARGET_FOLDER = "VRM";
-        [PreExportShaders]
-        public static SupportedShader[] VRMSupportedShaders = new SupportedShader[]
-        {
-            new SupportedShader(VRM_TARGET_FOLDER, "VRM/MToon"),
-            new SupportedShader(VRM_TARGET_FOLDER, "VRM/UnlitTexture"),
-            new SupportedShader(VRM_TARGET_FOLDER, "VRM/UnlitCutout"),
-            new SupportedShader(VRM_TARGET_FOLDER, "VRM/UnlitTransparent"),
-            new SupportedShader(VRM_TARGET_FOLDER, "VRM/UnlitTransparentZWrite"),
-        };
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/PreExportShaders_VRM.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/PreExportShaders_VRM.cs.meta
deleted file mode 100644
index d0fd45cad..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/PreExportShaders_VRM.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 625b5ee8b5811dc4a915a2fbb2cb319d
-timeCreated: 1533035131
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_MToon.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_MToon.cs
deleted file mode 100644
index f5fc6f15a..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_MToon.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair VRM_MToon 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "VRM/MToon",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_Cutoff", ShaderPropertyType.Range)
-,new ShaderProperty("_Color", ShaderPropertyType.Color)
-,new ShaderProperty("_ShadeColor", ShaderPropertyType.Color)
-,new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_ShadeTexture", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_BumpScale", ShaderPropertyType.Float)
-,new ShaderProperty("_BumpMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_ReceiveShadowRate", ShaderPropertyType.Range)
-,new ShaderProperty("_ReceiveShadowTexture", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_ShadingGradeRate", ShaderPropertyType.Range)
-,new ShaderProperty("_ShadingGradeTexture", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_ShadeShift", ShaderPropertyType.Range)
-,new ShaderProperty("_ShadeToony", ShaderPropertyType.Range)
-,new ShaderProperty("_LightColorAttenuation", ShaderPropertyType.Range)
-,new ShaderProperty("_IndirectLightIntensity", ShaderPropertyType.Range)
-,new ShaderProperty("_RimColor", ShaderPropertyType.Color)
-,new ShaderProperty("_RimTexture", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_RimLightingMix", ShaderPropertyType.Range)
-,new ShaderProperty("_RimFresnelPower", ShaderPropertyType.Range)
-,new ShaderProperty("_RimLift", ShaderPropertyType.Range)
-,new ShaderProperty("_SphereAdd", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_EmissionColor", ShaderPropertyType.Color)
-,new ShaderProperty("_EmissionMap", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_OutlineWidthTexture", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_OutlineWidth", ShaderPropertyType.Range)
-,new ShaderProperty("_OutlineScaledMaxDistance", ShaderPropertyType.Range)
-,new ShaderProperty("_OutlineColor", ShaderPropertyType.Color)
-,new ShaderProperty("_OutlineLightingMix", ShaderPropertyType.Range)
-,new ShaderProperty("_UvAnimMaskTexture", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_UvAnimScrollX", ShaderPropertyType.Float)
-,new ShaderProperty("_UvAnimScrollY", ShaderPropertyType.Float)
-,new ShaderProperty("_UvAnimRotation", ShaderPropertyType.Float)
-,new ShaderProperty("_MToonVersion", ShaderPropertyType.Float)
-,new ShaderProperty("_DebugMode", ShaderPropertyType.Float)
-,new ShaderProperty("_BlendMode", ShaderPropertyType.Float)
-,new ShaderProperty("_OutlineWidthMode", ShaderPropertyType.Float)
-,new ShaderProperty("_OutlineColorMode", ShaderPropertyType.Float)
-,new ShaderProperty("_CullMode", ShaderPropertyType.Float)
-,new ShaderProperty("_OutlineCullMode", ShaderPropertyType.Float)
-,new ShaderProperty("_SrcBlend", ShaderPropertyType.Float)
-,new ShaderProperty("_DstBlend", ShaderPropertyType.Float)
-,new ShaderProperty("_ZWrite", ShaderPropertyType.Float)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_MToon.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_MToon.cs.meta
deleted file mode 100644
index 26afcbf63..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_MToon.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 4629d794c8969c141a4724e182af082e
-timeCreated: 1533542890
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitCutout.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitCutout.cs
deleted file mode 100644
index 8695f72f3..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitCutout.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair VRM_UnlitCutout 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "VRM/UnlitCutout",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-,new ShaderProperty("_Cutoff", ShaderPropertyType.Range)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitCutout.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitCutout.cs.meta
deleted file mode 100644
index 3f6607d2a..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitCutout.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 611b546ea471ad34cb7d94740c63b558
-timeCreated: 1533542890
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTexture.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTexture.cs
deleted file mode 100644
index 6a0ab5b39..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTexture.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair VRM_UnlitTexture 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "VRM/UnlitTexture",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTexture.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTexture.cs.meta
deleted file mode 100644
index 181adad30..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTexture.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 22a8083880389b3498f421e6a5c340d5
-timeCreated: 1533542890
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparent.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparent.cs
deleted file mode 100644
index 2c750386e..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparent.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair VRM_UnlitTransparent 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "VRM/UnlitTransparent",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparent.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparent.cs.meta
deleted file mode 100644
index eeaf3b8d6..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparent.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 140d6538826e0eb448929d3e4bb2f1cd
-timeCreated: 1533542890
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparentZWrite.cs b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparentZWrite.cs
deleted file mode 100644
index 8d03c4ec7..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparentZWrite.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-
-
-namespace UniGLTF.ShaderPropExporter
-{
-    public static partial class PreShaderPropExporter
-    {
-        [PreExportShader]
-        static KeyValuePair VRM_UnlitTransparentZWrite 
-        {
-            get 
-            {
-                return new KeyValuePair(
-                    "VRM/UnlitTransparentZWrite",
-                    new ShaderProps
-                    {
-                        Properties = new ShaderProperty[]{
-new ShaderProperty("_MainTex", ShaderPropertyType.TexEnv)
-
-                        }
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparentZWrite.cs.meta b/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparentZWrite.cs.meta
deleted file mode 100644
index 6efeb43e5..000000000
--- a/Assets/External/VRMShaders/VRM/IO/Runtime/VRM/VRM_UnlitTransparentZWrite.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 165ec79b7aac1564a850fb3d3d19396e
-timeCreated: 1533542890
-licenseType: Free
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/MToon/MToon/Resources/Shaders/MToon.shader b/Assets/External/VRMShaders/VRM/MToon/MToon/Resources/Shaders/MToon.shader
index 773302908..df0f7fe89 100644
--- a/Assets/External/VRMShaders/VRM/MToon/MToon/Resources/Shaders/MToon.shader
+++ b/Assets/External/VRMShaders/VRM/MToon/MToon/Resources/Shaders/MToon.shader
@@ -35,7 +35,7 @@ Shader "VRM/MToon"
         _UvAnimScrollY ("UV Animation Scroll Y", Float) = 0
         _UvAnimRotation ("UV Animation Rotation", Float) = 0
 
-        [HideInInspector] _MToonVersion ("_MToonVersion", Float) = 38
+        [HideInInspector] _MToonVersion ("_MToonVersion", Float) = 39
         [HideInInspector] _DebugMode ("_DebugMode", Float) = 0.0
         [HideInInspector] _BlendMode ("_BlendMode", Float) = 0.0
         [HideInInspector] _OutlineWidthMode ("_OutlineWidthMode", Float) = 0.0
diff --git a/Assets/External/VRMShaders/VRM/MToon/MToon/Resources/Shaders/MToonCore.cginc b/Assets/External/VRMShaders/VRM/MToon/MToon/Resources/Shaders/MToonCore.cginc
index 7e3ca7946..38c5d9c1c 100644
--- a/Assets/External/VRMShaders/VRM/MToon/MToon/Resources/Shaders/MToonCore.cginc
+++ b/Assets/External/VRMShaders/VRM/MToon/MToon/Resources/Shaders/MToonCore.cginc
@@ -230,7 +230,7 @@ float4 frag_forward(v2f i) : SV_TARGET
     half3 mixedRimLighting = lighting + indirectLighting;
 #endif
     half3 rimLighting = lerp(staticRimLighting, mixedRimLighting, _RimLightingMix);
-    half3 rim = pow(saturate(1.0 - dot(worldNormal, worldView) + _RimLift), _RimFresnelPower) * _RimColor.rgb * tex2D(_RimTexture, mainUv).rgb;
+    half3 rim = pow(saturate(1.0 - dot(worldNormal, worldView) + _RimLift), max(_RimFresnelPower, EPS_COL)) * _RimColor.rgb * tex2D(_RimTexture, mainUv).rgb;
     col += lerp(rim * rimLighting, half3(0, 0, 0), i.isOutline);
 
     // additive matcap
diff --git a/Assets/External/VRMShaders/VRM/MToon/MToon/Scripts/UtilsVersion.cs b/Assets/External/VRMShaders/VRM/MToon/MToon/Scripts/UtilsVersion.cs
index 72585b30e..91436bc17 100644
--- a/Assets/External/VRMShaders/VRM/MToon/MToon/Scripts/UtilsVersion.cs
+++ b/Assets/External/VRMShaders/VRM/MToon/MToon/Scripts/UtilsVersion.cs
@@ -3,6 +3,6 @@ namespace MToon
     public static partial class Utils
     {
         public const string Implementation = "Santarh/MToon";
-        public const int VersionNumber = 38;
+        public const int VersionNumber = 39;
     }
 }
diff --git a/Assets/External/VRMShaders/VRM/MToon/README.md b/Assets/External/VRMShaders/VRM/MToon/README.md
index ac59db373..a1e26c6d8 100644
--- a/Assets/External/VRMShaders/VRM/MToon/README.md
+++ b/Assets/External/VRMShaders/VRM/MToon/README.md
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:99370ebbb927fbd694dceab31510c69acccb75be68dfe32a8a18a10d7e5cd9b3
+oid sha256:9910dddb2b6f00b9f6b0a31f3063f4b76335d768cb1d32e203f6fa430c610735
 size 189
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Editor/MToonInspector.cs b/Assets/External/VRMShaders/VRM10/MToon10/Editor/MToonInspector.cs
index af3348f40..da625d88a 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Editor/MToonInspector.cs
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Editor/MToonInspector.cs
@@ -147,37 +147,44 @@ namespace VRMShaders.VRM10.MToon10.Editor
 
             using (new LabelScope("Rim Lighting"))
             {
-                materialEditor.TexturePropertySingleLine(
-                    new GUIContent("Rim Color", "Rim Color (RGB)"),
-                    props[MToon10Prop.RimMultiplyTexture]
-                );
                 if (isAdvancedEditMode)
                 {
+                    materialEditor.TexturePropertySingleLine(
+                        new GUIContent("Mask", "Rim Lighting Mask (RGB)"),
+                        props[MToon10Prop.RimMultiplyTexture]
+                    );
                     materialEditor.ShaderProperty(
                         props[MToon10Prop.RimLightingMixFactor],
-                        new GUIContent("Rim LightingMix")
+                        new GUIContent("LightingMix")
                     );
                     EditorGUILayout.Space();
+                }
 
+                using (new LabelScope("Matcap"))
+                {
                     materialEditor.TexturePropertySingleLine(
-                        new GUIContent("Matcap Rim", "Matcap Rim (RGB)"),
-                        props[MToon10Prop.MatcapTexture]
+                        new GUIContent("Matcap", "Matcap (RGB)"),
+                        props[MToon10Prop.MatcapTexture],
+                        props[MToon10Prop.MatcapColorFactor]
+                    );
+                    EditorGUILayout.Space();
+                }
+
+                using (new LabelScope("Parametric Rim"))
+                {
+                    materialEditor.ShaderProperty(
+                        props[MToon10Prop.ParametricRimColorFactor],
+                        new GUIContent("Color")
+                    );
+                    materialEditor.ShaderProperty(
+                        props[MToon10Prop.ParametricRimFresnelPowerFactor],
+                        new GUIContent("Fresnel Power")
+                    );
+                    materialEditor.ShaderProperty(
+                        props[MToon10Prop.ParametricRimLiftFactor],
+                        new GUIContent("Lift")
                     );
                 }
-                EditorGUILayout.Space();
-
-                materialEditor.ShaderProperty(
-                    props[MToon10Prop.ParametricRimColorFactor],
-                    new GUIContent("Parametric Rim Color")
-                );
-                materialEditor.ShaderProperty(
-                    props[MToon10Prop.ParametricRimFresnelPowerFactor],
-                    new GUIContent("Parametric Rim Fresnel Power")
-                );
-                materialEditor.ShaderProperty(
-                    props[MToon10Prop.ParametricRimLiftFactor],
-                    new GUIContent("Parametric Rim Lift")
-                );
             }
 
             using (new LabelScope("Outline"))
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon.shader b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon.shader
index 81d8d77f5..76e3d25a9 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon.shader
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon.shader
@@ -29,6 +29,7 @@ Shader "VRM10/MToon10"
         _EmissionMap ("emissiveTexture", 2D) = "white" {} // Unity specified name
 
         // Rim Lighting
+        _MatcapColor ("mtoon.matcapFactor", Color) = (0, 0, 0, 1)
         _MatcapTex ("mtoon.matcapTexture", 2D) = "black" {}
         _RimColor ("mtoon.parametricRimColorFactor", Color) = (0, 0, 0, 1)
         _RimFresnelPower ("mtoon.parametricRimFresnelPowerFactor", Range(0, 100)) = 5.0
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_attribute.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_attribute.hlsl
index 6f4d5e82e..9cb022b47 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_attribute.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_attribute.hlsl
@@ -1,8 +1,7 @@
 #ifndef VRMC_MATERIALS_MTOON_ATTRIBUTE_INCLUDED
 #define VRMC_MATERIALS_MTOON_ATTRIBUTE_INCLUDED
 
-#include 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 
 struct Attributes
 {
@@ -25,8 +24,9 @@ struct Varyings
     half4 tangentWS : TEXCOORD3;
 #endif
     float3 viewDirWS : TEXCOORD4;
-    UNITY_FOG_COORDS(5)
-    UNITY_LIGHTING_COORDS(6,7)
+
+    MTOON_FOG_AND_LIGHTING_COORDS(5, 6, 7)
+    
     float4 pos : SV_POSITION; // UnityCG macro specified name. Accurately "positionCS"
     UNITY_VERTEX_INPUT_INSTANCE_ID
     UNITY_VERTEX_OUTPUT_STEREO
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_define.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_define.hlsl
index 13792639b..f0d4ed761 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_define.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_define.hlsl
@@ -12,7 +12,11 @@
 #endif
 #ifndef MTOON_FRONT_FACE_TYPE
     // from https://docs.unity3d.com/Manual/SL-ShaderSemantics.html
-    #define MTOON_FRONT_FACE_TYPE fixed
+    #ifdef MTOON_URP
+        #define MTOON_FRONT_FACE_TYPE float
+    #else
+        #define MTOON_FRONT_FACE_TYPE fixed
+    #endif
 #endif
 #ifndef MTOON_IS_FRONT_VFACE
     #define MTOON_IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL > 0.0) ? (FRONT) : (BACK))
@@ -28,7 +32,9 @@ inline bool MToon_IsPbrCorrectOn()
 // Compile-time constant
 inline bool MToon_IsForwardBasePass()
 {
-#if defined(UNITY_PASS_FORWARDBASE)
+#if defined(MTOON_URP)
+    return true;
+#elif defined(UNITY_PASS_FORWARDBASE)
     return true;
 #elif defined(UNITY_PASS_FORWARDADD)
     return false;
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_fragment.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_fragment.hlsl
new file mode 100644
index 000000000..278bfca0f
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_fragment.hlsl
@@ -0,0 +1,38 @@
+#ifndef VRMC_MATERIALS_MTOON_DEPTHNORMALS_FRAGMENT_INCLUDED
+#define VRMC_MATERIALS_MTOON_DEPTHNORMALS_FRAGMENT_INCLUDED
+
+#ifdef MTOON_URP
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
+
+#include "./vrmc_materials_mtoon_define.hlsl"
+#include "./vrmc_materials_mtoon_utility.hlsl"
+#include "./vrmc_materials_mtoon_input.hlsl"
+#include "./vrmc_materials_mtoon_attribute.hlsl"
+#include "./vrmc_materials_mtoon_geometry_uv.hlsl"
+#include "./vrmc_materials_mtoon_geometry_alpha.hlsl"
+#include "./vrmc_materials_mtoon_geometry_normal.hlsl"
+#include "./vrmc_materials_mtoon_lighting_unity.hlsl"
+#include "./vrmc_materials_mtoon_lighting_mtoon.hlsl"
+
+half4 MToonDepthNormalsFragment(const FragmentInput fragmentInput) : SV_Target
+{
+    const Varyings input = fragmentInput.varyings;
+    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
+
+    // Get MToon UV (with UVAnimation)
+    const float2 uv = GetMToonGeometry_Uv(input.uv);
+
+    // Get LitColor with Alpha
+    const half4 litColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv) * _Color;
+    GetMToonGeometry_Alpha(litColor);
+
+    // Get Normal
+    float3 normalWS = GetMToonGeometry_Normal(input, fragmentInput.facing, uv);
+    normalWS = NormalizeNormalPerPixel(normalWS);
+
+    return half4(normalWS, 0.0);
+}
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/uv_color.shader.meta b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_fragment.hlsl.meta
similarity index 80%
rename from Assets/External/UniGLTF/Samples/ScreenSpace/uv_color.shader.meta
rename to Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_fragment.hlsl.meta
index 18b7effaf..6087a7c7f 100644
--- a/Assets/External/UniGLTF/Samples/ScreenSpace/uv_color.shader.meta
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_fragment.hlsl.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 1480dc3335b60e24fac1c62736559733
+guid: 93f88dc204e783a4aaabfc17a087bce8
 ShaderImporter:
   externalObjects: {}
   defaultTextures: []
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_vertex.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_vertex.hlsl
new file mode 100644
index 000000000..9349252e0
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_vertex.hlsl
@@ -0,0 +1,43 @@
+#ifndef VRMC_MATERIALS_MTOON_DEPTHNORMALS_VERTEX_INCLUDED
+#define VRMC_MATERIALS_MTOON_DEPTHNORMALS_VERTEX_INCLUDED
+
+#ifdef MTOON_URP
+
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
+
+#include "./vrmc_materials_mtoon_define.hlsl"
+#include "./vrmc_materials_mtoon_utility.hlsl"
+#include "./vrmc_materials_mtoon_input.hlsl"
+#include "./vrmc_materials_mtoon_attribute.hlsl"
+#include "./vrmc_materials_mtoon_geometry_vertex.hlsl"
+
+Varyings MToonDepthNormalsVertex(const Attributes v)
+{
+    Varyings output = (Varyings)0;
+
+    UNITY_SETUP_INSTANCE_ID(v);
+    UNITY_TRANSFER_INSTANCE_ID(v, output);
+    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
+
+#if defined(_NORMALMAP)
+    VertexNormalInputs normalInput = GetVertexNormalInputs(v.normalOS, v.tangentOS);
+    float3 normalWS = normalInput.normalWS;
+    float sign = v.tangentOS.w * float(GetOddNegativeScale());
+    half4 tangentWS = half4(normalInput.tangentWS.xyz, sign);
+#else
+    float3 normalWS = TransformObjectToWorldNormal(v.normalOS);
+#endif
+
+    output.pos = TransformObjectToHClip(v.vertex.xyz);
+    output.normalWS = normalWS;
+#if defined(_NORMALMAP)
+    output.tangentWS = tangentWS;
+#endif
+    output.uv = v.texcoord0;
+
+    return output;
+}
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_vertex.hlsl.meta b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_vertex.hlsl.meta
new file mode 100644
index 000000000..8b3aaab6a
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthnormals_vertex.hlsl.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: b69080781a3778e499a6ae99adb82053
+ShaderImporter:
+  externalObjects: {}
+  defaultTextures: []
+  nonModifiableTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_fragment.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_fragment.hlsl
new file mode 100644
index 000000000..fa306c3d8
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_fragment.hlsl
@@ -0,0 +1,34 @@
+#ifndef VRMC_MATERIALS_MTOON_DEPTHONLY_FRAGMENT_INCLUDED
+#define VRMC_MATERIALS_MTOON_DEPTHONLY_FRAGMENT_INCLUDED
+
+#ifdef MTOON_URP
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
+
+#include "./vrmc_materials_mtoon_define.hlsl"
+#include "./vrmc_materials_mtoon_utility.hlsl"
+#include "./vrmc_materials_mtoon_input.hlsl"
+#include "./vrmc_materials_mtoon_attribute.hlsl"
+#include "./vrmc_materials_mtoon_geometry_uv.hlsl"
+#include "./vrmc_materials_mtoon_geometry_alpha.hlsl"
+#include "./vrmc_materials_mtoon_geometry_normal.hlsl"
+#include "./vrmc_materials_mtoon_lighting_unity.hlsl"
+#include "./vrmc_materials_mtoon_lighting_mtoon.hlsl"
+
+half4 MToonDepthOnlyFragment(const FragmentInput fragmentInput) : SV_Target
+{
+    const Varyings input = fragmentInput.varyings;
+    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
+
+    // Get MToon UV (with UVAnimation)
+    const float2 uv = GetMToonGeometry_Uv(input.uv);
+
+    // Get LitColor with Alpha
+    const half4 litColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv) * _Color;
+    GetMToonGeometry_Alpha(litColor);
+
+    return 0;
+}
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_fragment.hlsl.meta b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_fragment.hlsl.meta
new file mode 100644
index 000000000..eab81c4cc
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_fragment.hlsl.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 68d7d7ebb0ec69440b052da859a20d74
+ShaderImporter:
+  externalObjects: {}
+  defaultTextures: []
+  nonModifiableTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_vertex.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_vertex.hlsl
new file mode 100644
index 000000000..54f3a47a1
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_vertex.hlsl
@@ -0,0 +1,30 @@
+#ifndef VRMC_MATERIALS_MTOON_DEPTHONLY_VERTEX_INCLUDED
+#define VRMC_MATERIALS_MTOON_DEPTHONLY_VERTEX_INCLUDED
+
+#ifdef MTOON_URP
+
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
+
+#include "./vrmc_materials_mtoon_define.hlsl"
+#include "./vrmc_materials_mtoon_utility.hlsl"
+#include "./vrmc_materials_mtoon_input.hlsl"
+#include "./vrmc_materials_mtoon_attribute.hlsl"
+#include "./vrmc_materials_mtoon_geometry_vertex.hlsl"
+
+Varyings MToonDepthOnlyVertex(const Attributes v)
+{
+    Varyings output = (Varyings)0;
+
+    UNITY_SETUP_INSTANCE_ID(v);
+    UNITY_TRANSFER_INSTANCE_ID(v, output);
+    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
+
+    output.pos = TransformObjectToHClip(v.vertex.xyz);
+    output.uv = v.texcoord0;
+
+    return output;
+}
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_vertex.hlsl.meta b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_vertex.hlsl.meta
new file mode 100644
index 000000000..38c82ffe9
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_depthonly_vertex.hlsl.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 6957b39e3ab2cbc43aa0de76d9b4a411
+ShaderImporter:
+  externalObjects: {}
+  defaultTextures: []
+  nonModifiableTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_forward_fragment.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_forward_fragment.hlsl
index 544e3560a..1e16957eb 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_forward_fragment.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_forward_fragment.hlsl
@@ -1,7 +1,7 @@
 #ifndef VRMC_MATERIALS_MTOON_FORWARD_FRAGMENT_INCLUDED
 #define VRMC_MATERIALS_MTOON_FORWARD_FRAGMENT_INCLUDED
 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 #include "./vrmc_materials_mtoon_define.hlsl"
 #include "./vrmc_materials_mtoon_utility.hlsl"
 #include "./vrmc_materials_mtoon_input.hlsl"
@@ -20,12 +20,13 @@ half4 MToonFragment(const FragmentInput fragmentInput) : SV_Target
     }
 
     const Varyings input = fragmentInput.varyings;
+    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
 
     // Get MToon UV (with UVAnimation)
     const float2 uv = GetMToonGeometry_Uv(input.uv);
 
     // Get LitColor with Alpha
-    const half4 litColor = UNITY_SAMPLE_TEX2D(_MainTex, uv) * _Color;
+    const half4 litColor = MTOON_SAMPLE_TEXTURE2D(_MainTex, uv) * _Color;
 
     // Alpha Test
     const half alpha = GetMToonGeometry_Alpha(litColor);
@@ -45,8 +46,22 @@ half4 MToonFragment(const FragmentInput fragmentInput) : SV_Target
     mtoonInput.alpha = alpha;
     half4 col = GetMToonLighting(unityLighting, mtoonInput);
 
+    #if defined(MTOON_URP) && defined(_ADDITIONAL_LIGHTS) && !defined(MTOON_PASS_OUTLINE)
+    uint pixelLightCount = GetAdditionalLightsCount();
+    for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
+    {
+        UnityLighting additionalUnityLighting = GetAdditionalUnityLighting(input, normalWS, lightIndex);
+        col.rgb += GetMToonURPAdditionalLighting(additionalUnityLighting, mtoonInput).rgb;
+    }
+    #endif
+
     // Apply Fog
+    #ifdef MTOON_URP
+    float fogCoord = input.fogFactorAndVertexLight.x;
+    col.rgb = MixFog(col.rgb, fogCoord);
+    #else
     UNITY_APPLY_FOG(fragmentInput.varyings.fogCoord, col);
+    #endif
 
     return col;
 }
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_forward_vertex.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_forward_vertex.hlsl
index e536543f3..4a9a3927b 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_forward_vertex.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_forward_vertex.hlsl
@@ -1,8 +1,7 @@
 #ifndef VRMC_MATERIALS_MTOON_FORWARD_VERTEX_INCLUDED
 #define VRMC_MATERIALS_MTOON_FORWARD_VERTEX_INCLUDED
 
-#include 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 #include "./vrmc_materials_mtoon_define.hlsl"
 #include "./vrmc_materials_mtoon_utility.hlsl"
 #include "./vrmc_materials_mtoon_input.hlsl"
@@ -23,26 +22,27 @@ Varyings MToonVertex(const Attributes v) // v is UnityCG macro specified name.
     {
         const VertexPositionInfo position = MToon_GetOutlineVertex(v.vertex.xyz, normalize(v.normalOS), output.uv);
         output.pos = position.positionCS;
-        output.positionWS = position.positionWS;
-        output.normalWS = UnityObjectToWorldNormal(-v.normalOS);
+        output.positionWS = position.positionWS.xyz;
+
+        output.normalWS = MToon_TransformObjectToWorldNormal(-v.normalOS);
     }
     else
     {
         const VertexPositionInfo position = MToon_GetVertex(v.vertex.xyz);
         output.pos = position.positionCS;
-        output.positionWS = position.positionWS;
-        output.normalWS = UnityObjectToWorldNormal(v.normalOS);
+        output.positionWS = position.positionWS.xyz;
+
+        output.normalWS = MToon_TransformObjectToWorldNormal(v.normalOS);
     }
 
     output.viewDirWS = MToon_GetWorldSpaceNormalizedViewDir(output.positionWS);
 
 #if defined(_NORMALMAP)
     const half tangentSign = v.tangentOS.w * unity_WorldTransformParams.w;
-    output.tangentWS = half4(UnityObjectToWorldDir(v.tangentOS), tangentSign);
+    output.tangentWS = half4(MToon_TransformObjectToWorldDir(v.tangentOS), tangentSign);
 #endif
 
-    UNITY_TRANSFER_FOG(output, output.pos);
-    UNITY_TRANSFER_LIGHTING(output, v.texcoord1.xy);
+    MTOON_TRANSFER_FOG_AND_LIGHTING(output, output.pos, v.texcoord1.xy, v.vertex.xyz);
 
     return output;
 }
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_normal.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_normal.hlsl
index b43066138..4ad066c4c 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_normal.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_normal.hlsl
@@ -1,7 +1,7 @@
 #ifndef VRMC_MATERIALS_MTOON_GEOMETRY_NORMAL_INCLUDED
 #define VRMC_MATERIALS_MTOON_GEOMETRY_NORMAL_INCLUDED
 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 #include "./vrmc_materials_mtoon_define.hlsl"
 #include "./vrmc_materials_mtoon_utility.hlsl"
 #include "./vrmc_materials_mtoon_input.hlsl"
@@ -15,13 +15,17 @@ inline float3 GetMToonGeometry_Normal(const Varyings input, const MTOON_FRONT_FA
 {
     const half3 normalWS = MTOON_IS_FRONT_VFACE(facing, input.normalWS, -input.normalWS);
 
-#if defined(_NORMALMAP)
+    #if defined(_NORMALMAP)
+
     // Get Normal in WorldSpace from Normalmap if available
-    const half3 normalTS = normalize(UnpackNormalWithScale(UNITY_SAMPLE_TEX2D(_BumpMap, mtoonUv), _BumpScale));
+    const half3 normalTS = normalize(MToon_UnpackNormalScale(MTOON_SAMPLE_TEXTURE2D(_BumpMap, mtoonUv), _BumpScale));
     return normalize(mul(normalTS, MToon_GetTangentToWorld(normalWS, input.tangentWS)));
-#else
+    
+    #else
+
     return GetMToonGeometry_NormalWithoutNormalMap(normalWS);
-#endif
+
+    #endif
 }
 
 #endif
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_uv.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_uv.hlsl
index 2dd7f939a..f37565eda 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_uv.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_uv.hlsl
@@ -1,7 +1,7 @@
 #ifndef VRMC_MATERIALS_MTOON_GEOMETRY_UV_INCLUDED
 #define VRMC_MATERIALS_MTOON_GEOMETRY_UV_INCLUDED
 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 #include "./vrmc_materials_mtoon_define.hlsl"
 #include "./vrmc_materials_mtoon_utility.hlsl"
 #include "./vrmc_materials_mtoon_input.hlsl"
@@ -10,12 +10,9 @@ inline float GetMToonGeometry_Uv_Time(const float2 uvRaw)
 {
     if (MToon_IsParameterMapOn())
     {
-        return UNITY_SAMPLE_TEX2D(_UvAnimMaskTex, uvRaw).b * _Time.y;
-    }
-    else
-    {
-        return _Time.y;
+        return MTOON_SAMPLE_TEXTURE2D(_UvAnimMaskTex, uvRaw).b * _Time.y;
     }
+    return _Time.y;
 }
 
 inline float2 GetMToonGeometry_Uv(const float2 geometryUv)
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_vertex.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_vertex.hlsl
index 75548d4c5..655b22dbe 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_vertex.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_geometry_vertex.hlsl
@@ -1,7 +1,7 @@
 #ifndef VRMC_MATERIALS_MTOON_GEOMETRY_VERTEX_INCLUDED
 #define VRMC_MATERIALS_MTOON_GEOMETRY_VERTEX_INCLUDED
 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 #include "./vrmc_materials_mtoon_define.hlsl"
 #include "./vrmc_materials_mtoon_utility.hlsl"
 #include "./vrmc_materials_mtoon_input.hlsl"
@@ -16,7 +16,7 @@ inline half MToon_GetOutlineVertex_OutlineWidth(const float2 uv)
 {
     if (MToon_IsParameterMapOn())
     {
-        return _OutlineWidth * UNITY_SAMPLE_TEX2D_LOD(_OutlineWidthTex, uv, 0);
+        return _OutlineWidth * UNITY_SAMPLE_TEX2D_LOD(_OutlineWidthTex, uv, 0).x;
     }
     else
     {
@@ -49,12 +49,13 @@ inline VertexPositionInfo MToon_GetOutlineVertex(const float3 positionOS, const
     if (MToon_IsOutlineModeWorldCoordinates())
     {
         const float3 positionWS = mul(unity_ObjectToWorld, float4(positionOS, 1)).xyz;
-        const half3 normalWS = UnityObjectToWorldNormal(normalOS);
+        const half3 normalWS =  MToon_TransformObjectToWorldNormal(normalOS);
         const half outlineWidth = MToon_GetOutlineVertex_OutlineWidth(uv);
 
         VertexPositionInfo output;
         output.positionWS = float4(positionWS + normalWS * outlineWidth, 1);
-        output.positionCS = UnityWorldToClipPos(output.positionWS);
+        output.positionCS = MToon_TransformWorldToHClip(output.positionWS.xyz);
+
         return output;
     }
     else if (MToon_IsOutlineModeScreenCoordinates())
@@ -64,10 +65,9 @@ inline VertexPositionInfo MToon_GetOutlineVertex(const float3 positionOS, const
 
         const float4 nearUpperRight = mul(unity_CameraInvProjection, float4(1, 1, UNITY_NEAR_CLIP_VALUE, _ProjectionParams.y));
         const half aspect = abs(nearUpperRight.y / nearUpperRight.x);
-
-        const float4 positionCS = UnityObjectToClipPos(positionOS);
+        const float4 positionCS = MToon_TransformObjectToHClip(positionOS);
         const half3 normalVS = MToon_GetObjectToViewNormal(normalOS);
-        const half3 normalCS = TransformViewToProjection(normalVS.xyz);
+        const half3 normalCS = MToon_TransformViewToHClip(normalVS.xyz);
 
         half2 normalProjectedCS = normalize(normalCS.xy);
         const float clipSpaceHeight = 2.0f;
@@ -85,7 +85,8 @@ inline VertexPositionInfo MToon_GetOutlineVertex(const float3 positionOS, const
     {
         VertexPositionInfo output;
         output.positionWS = mul(unity_ObjectToWorld, float4(positionOS * 0.001, 1));
-        output.positionCS = UnityWorldToClipPos(output.positionWS);
+        output.positionCS = MToon_TransformWorldToHClip(output.positionWS.xyz);
+
         return output;
     }
 }
@@ -94,7 +95,8 @@ inline VertexPositionInfo MToon_GetVertex(const float3 positionOS)
 {
     VertexPositionInfo output;
     output.positionWS = mul(unity_ObjectToWorld, float4(positionOS, 1));
-    output.positionCS = UnityWorldToClipPos(output.positionWS);
+    output.positionCS = MToon_TransformWorldToHClip(output.positionWS.xyz);
+
     return output;
 }
 
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_input.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_input.hlsl
index 6f5d361e9..dedbd3d14 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_input.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_input.hlsl
@@ -1,19 +1,19 @@
 #ifndef VRMC_MATERIALS_MTOON_INPUT_INCLUDED
 #define VRMC_MATERIALS_MTOON_INPUT_INCLUDED
 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 
 // Textures
-UNITY_DECLARE_TEX2D(_MainTex);
-UNITY_DECLARE_TEX2D(_ShadeTex);
-UNITY_DECLARE_TEX2D(_BumpMap);
-UNITY_DECLARE_TEX2D(_ShadingShiftTex);
-UNITY_DECLARE_TEX2D(_EmissionMap);
-UNITY_DECLARE_TEX2D(_MatcapTex);
-UNITY_DECLARE_TEX2D(_RimTex);
-UNITY_DECLARE_TEX2D(_OutlineWidthTex);
+MTOON_DECLARE_TEX2D(_MainTex);
+MTOON_DECLARE_TEX2D(_ShadeTex);
+MTOON_DECLARE_TEX2D(_BumpMap);
+MTOON_DECLARE_TEX2D(_ShadingShiftTex);
+MTOON_DECLARE_TEX2D(_EmissionMap);
+MTOON_DECLARE_TEX2D(_MatcapTex);
+MTOON_DECLARE_TEX2D(_RimTex);
+MTOON_DECLARE_TEX2D(_OutlineWidthTex);
 // NOTE: "tex2d() * _Time.y" returns mediump value if sampler is half precision in Android VR platform
-UNITY_DECLARE_TEX2D_FLOAT(_UvAnimMaskTex);
+MTOON_DECLARE_TEX2D_FLOAT(_UvAnimMaskTex);
 
 CBUFFER_START(UnityPerMaterial)
 // Vector
@@ -22,6 +22,7 @@ float4 _MainTex_ST;
 half4 _Color;
 half4 _ShadeColor;
 half4 _EmissionColor;
+half4 _MatcapColor;
 half4 _RimColor;
 half4 _OutlineColor;
 // Floats
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_lighting_mtoon.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_lighting_mtoon.hlsl
index 63560eab8..23e0ef5c8 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_lighting_mtoon.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_lighting_mtoon.hlsl
@@ -1,7 +1,7 @@
 #ifndef VRMC_MATERIALS_MTOON_LIGHTING_MTOON_INCLUDED
 #define VRMC_MATERIALS_MTOON_LIGHTING_MTOON_INCLUDED
 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 #include "./vrmc_materials_mtoon_define.hlsl"
 #include "./vrmc_materials_mtoon_utility.hlsl"
 #include "./vrmc_materials_mtoon_input.hlsl"
@@ -20,12 +20,9 @@ inline half GetMToonLighting_Reflectance_ShadingShift(const MToonInput input)
 {
     if (MToon_IsParameterMapOn())
     {
-        return UNITY_SAMPLE_TEX2D(_ShadingShiftTex, input.uv).r * _ShadingShiftTexScale + _ShadingShiftFactor;
-    }
-    else
-    {
-        return _ShadingShiftFactor;
+        return MTOON_SAMPLE_TEXTURE2D(_ShadingShiftTex, input.uv).r * _ShadingShiftTexScale + _ShadingShiftFactor;
     }
+    return _ShadingShiftFactor;
 }
 
 inline half GetMToonLighting_DotNL(const UnityLighting lighting, const MToonInput input)
@@ -47,7 +44,7 @@ inline half GetMToonLighting_Shade(const UnityLighting lighting, const MToonInpu
     if (MToon_IsForwardBasePass())
     {
         const half shadeInput = lerp(-1, 1, mtoon_linearstep(-1, 1, dotNL));
-        return mtoon_linearstep(-1.0 + shadeToony, +1.0 - shadeToony, shadeInput + shadeShift) * lighting.directLightAttenuation;
+        return mtoon_linearstep(-1.0 + shadeToony, +1.0 - shadeToony, shadeInput + shadeShift) * lighting.directLightAttenuation.x;
     }
     else
     {
@@ -60,7 +57,7 @@ inline half GetMToonLighting_Shadow(const UnityLighting lighting, const half dot
 {
     if (MToon_IsPbrCorrectOn())
     {
-        return lighting.directLightAttenuation * step(0, dotNL);
+        return lighting.directLightAttenuation.x * step(0, dotNL);
     }
 
     if (MToon_IsForwardBasePass())
@@ -72,13 +69,13 @@ inline half GetMToonLighting_Shadow(const UnityLighting lighting, const half dot
         // heuristic term for weak lights.
         //     0.5: heuristic.
         //     min(0, dotNL) + 1: darken if (dotNL < 0) by using half lambert.
-        return lighting.directLightAttenuation * 0.5 * (min(0, dotNL) + 1);
+        return lighting.directLightAttenuation.x * 0.5 * (min(0, dotNL) + 1);
     }
 }
 
 inline half3 GetMToonLighting_DirectLighting(const UnityLighting unityLight, const MToonInput input, const half shade, const half shadow)
 {
-    const half3 shadeColor = UNITY_SAMPLE_TEX2D(_ShadeTex, input.uv).rgb * _ShadeColor.rgb;
+    const half3 shadeColor = MTOON_SAMPLE_TEXTURE2D(_ShadeTex, input.uv).rgb * _ShadeColor.rgb;
     const half3 albedo = lerp(shadeColor, input.litColor, shade);
 
     return albedo * unityLight.directLightColor * shadow;
@@ -102,17 +99,11 @@ inline half3 GetMToonLighting_Emissive(const MToonInput input)
     {
         if (MToon_IsEmissiveMapOn())
         {
-            return UNITY_SAMPLE_TEX2D(_EmissionMap, input.uv).rgb * _EmissionColor.rgb;
-        }
-        else
-        {
-            return _EmissionColor.rgb;
+            return MTOON_SAMPLE_TEXTURE2D(_EmissionMap, input.uv).rgb * _EmissionColor.rgb;
         }
+        return _EmissionColor.rgb;
     }
-    else
-    {
-        return 0;
-    }
+    return 0;
 }
 
 inline half3 GetMToonLighting_Rim_Matcap(const MToonInput input)
@@ -124,17 +115,15 @@ inline half3 GetMToonLighting_Rim_Matcap(const MToonInput input)
         const half3 matcapRightAxisWS = normalize(cross(input.viewDirWS, worldUpWS));
         const half3 matcapUpAxisWS = normalize(cross(matcapRightAxisWS, input.viewDirWS));
         const half2 matcapUv = float2(dot(matcapRightAxisWS, input.normalWS), dot(matcapUpAxisWS, input.normalWS)) * 0.5 + 0.5;
-        return UNITY_SAMPLE_TEX2D(_MatcapTex, matcapUv).rgb;
-    }
-    else
-    {
-        return 0;
+        
+        return _MatcapColor.rgb * MTOON_SAMPLE_TEXTURE2D(_MatcapTex, matcapUv).rgb;
     }
+    return _MatcapColor.rgb;
 }
 
 inline half3 GetMToonLighting_Rim(const UnityLighting unityLight, const MToonInput input, const half shadow)
 {
-    const half3 parametricRimFactor = pow(saturate(1.0 - dot(input.normalWS, input.viewDirWS) + _RimLift), _RimFresnelPower) * _RimColor.rgb;
+    const half3 parametricRimFactor = pow(saturate(1.0 - dot(input.normalWS, input.viewDirWS) + _RimLift), max(_RimFresnelPower, EPS_COL)) * _RimColor.rgb;
     const half3 matcapFactor = GetMToonLighting_Rim_Matcap(input);
     const half3 directLightingFactor = unityLight.directLightColor * shadow;
 
@@ -152,12 +141,9 @@ inline half3 GetMToonLighting_Rim(const UnityLighting unityLight, const MToonInp
 
     if (MToon_IsRimMapOn())
     {
-        return (matcapFactor + parametricRimFactor) * rimLightingFactor * UNITY_SAMPLE_TEX2D(_RimTex, input.uv).rgb;
-    }
-    else
-    {
-        return (matcapFactor + parametricRimFactor) * rimLightingFactor;
+        return (matcapFactor + parametricRimFactor) * rimLightingFactor * MTOON_SAMPLE_TEXTURE2D(_RimTex, input.uv).rgb;
     }
+    return (matcapFactor + parametricRimFactor) * rimLightingFactor;
 }
 
 half4 GetMToonLighting(const UnityLighting unityLight, const MToonInput input)
@@ -179,10 +165,51 @@ half4 GetMToonLighting(const UnityLighting unityLight, const MToonInput input)
         const half3 outlineCol = _OutlineColor.rgb * lerp(half3(1, 1, 1), baseCol, _OutlineLightingMix);
         return half4(outlineCol, input.alpha);
     }
-    else
+    return half4(baseCol, input.alpha);
+}
+
+#ifdef MTOON_URP
+
+inline half GetMToonURPAdditionalLighting_Shadow(const UnityLighting lighting, const half dotNL)
+{
+    if (MToon_IsPbrCorrectOn())
     {
-        return half4(baseCol, input.alpha);
+        return lighting.directLightAttenuation.x * step(0, dotNL);
     }
+
+    return lighting.directLightAttenuation.x * 0.5 * (min(0, dotNL) + 1);
+}
+
+inline half GetMToonURPAdditionalLighting_Shade(const UnityLighting lighting, const MToonInput input, const half dotNL)
+{
+    const half shadeShift = GetMToonLighting_Reflectance_ShadingShift(input);
+    const half shadeToony = _ShadingToonyFactor;
+
+    if (MToon_IsPbrCorrectOn())
+    {
+        const half shadeInput = dotNL;
+        return mtoon_linearstep(-1.0 + shadeToony, +1.0 - shadeToony, shadeInput + shadeShift);
+    }
+
+    const half shadeInput = dotNL;
+    return mtoon_linearstep(-1.0 + shadeToony, +1.0 - shadeToony, shadeInput + shadeShift);
+}
+
+half4 GetMToonURPAdditionalLighting(const UnityLighting unityLight, const MToonInput input)
+{
+    const half dotNL = GetMToonLighting_DotNL(unityLight, input);
+    const half shade = GetMToonURPAdditionalLighting_Shade(unityLight, input, dotNL);
+    const half shadow = GetMToonURPAdditionalLighting_Shadow(unityLight, dotNL);
+
+    const half3 direct = GetMToonLighting_DirectLighting(unityLight, input, shade, shadow);
+    const half3 lighting = direct;
+    
+    const half3 baseCol = lighting;
+
+    return half4(baseCol, input.alpha);
 }
 
 #endif
+
+
+#endif
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_lighting_unity.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_lighting_unity.hlsl
index d8908b4ff..b2ff73747 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_lighting_unity.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_lighting_unity.hlsl
@@ -1,9 +1,7 @@
 #ifndef VRMC_MATERIALS_MTOON_LIGHTING_UNITY_INCLUDED
 #define VRMC_MATERIALS_MTOON_LIGHTING_UNITY_INCLUDED
 
-#include 
-#include 
-#include 
+#include "./vrmc_materials_mtoon_render_pipeline.hlsl"
 #include "./vrmc_materials_mtoon_define.hlsl"
 #include "./vrmc_materials_mtoon_input.hlsl"
 #include "./vrmc_materials_mtoon_attribute.hlsl"
@@ -19,31 +17,50 @@ struct UnityLighting
 
 UnityLighting GetUnityLighting(const Varyings input, const half3 normalWS)
 {
-    UNITY_LIGHT_ATTENUATION(atten, input, input.positionWS);
-
-    const half3 lightDir = normalize(UnityWorldSpaceLightDir(input.positionWS));
-    const half3 lightColor = _LightColor0.rgb;
+    MTOON_LIGHT_DESCRIPTION(input, atten, lightDir, lightColor);
 
     if (MToon_IsForwardBasePass())
     {
         UnityLighting output;
-        output.indirectLight = ShadeSH9(half4(normalWS, 1));
-        output.indirectLightEqualized = (ShadeSH9(half4(0, 1, 0, 1)) + ShadeSH9(half4(0, -1, 0, 1))) * 0.5;
-        output.directLightColor = lightColor;
-        output.directLightDirection = lightDir;
-        output.directLightAttenuation = atten;
-        return output;
-    }
-    else
-    {
-        UnityLighting output;
-        output.indirectLight = 0;
-        output.indirectLightEqualized = 0;
+        output.indirectLight = MToon_SampleSH(half3(normalWS));
+        output.indirectLightEqualized = (MToon_SampleSH(half3(0, 1, 0)) + MToon_SampleSH(half3(0, -1, 0))) * 0.5;
         output.directLightColor = lightColor;
         output.directLightDirection = lightDir;
         output.directLightAttenuation = atten;
         return output;
     }
+    UnityLighting output;
+    output.indirectLight = 0;
+    output.indirectLightEqualized = 0;
+    output.directLightColor = lightColor;
+    output.directLightDirection = lightDir;
+    output.directLightAttenuation = atten;
+    return output;
 }
 
+#ifdef MTOON_URP
+UnityLighting GetAdditionalUnityLighting(const Varyings input, const half3 normalWS, int lightIndex)
+{
+    // TODO: Duplicate in GetUnityLighting
+    #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
+    float4 shadowCoord = input.shadowCoord;
+    #elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
+    float4 shadowCoord = TransformWorldToShadowCoord(input.positionWS);
+    #else
+    float4 shadowCoord = float4(0, 0, 0, 0);
+    #endif
+        
+    half4 shadowMask = SAMPLE_SHADOWMASK(input.lightmapUV);
+    Light light = GetAdditionalLight(lightIndex, input.positionWS, shadowMask);
+
+    UnityLighting output;
+    output.indirectLight = 0;
+    output.indirectLightEqualized = 0;
+    output.directLightColor = light.color;
+    output.directLightDirection = light.direction;
+    output.directLightAttenuation = light.shadowAttenuation * light.distanceAttenuation;
+    return output;
+}
+#endif
+
 #endif
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_render_pipeline.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_render_pipeline.hlsl
new file mode 100644
index 000000000..bcc46dc8b
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_render_pipeline.hlsl
@@ -0,0 +1,171 @@
+#ifndef VRMC_MATERIALS_MTOON_RENDER_PIPELINE_INCLUDED
+#define VRMC_MATERIALS_MTOON_RENDER_PIPELINE_INCLUDED
+
+// Include
+#ifdef MTOON_URP
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
+#else
+#include 
+#include 
+#include 
+#include 
+#endif
+
+// Texture
+#ifdef MTOON_URP
+#define MTOON_DECLARE_TEX2D(tex) TEXTURE2D_FLOAT(tex); SAMPLER(sampler##tex);
+#define MTOON_DECLARE_TEX2D_FLOAT(tex) TEXTURE2D(tex); SAMPLER(sampler##tex);
+#define MTOON_SAMPLE_TEXTURE2D(tex, uv) SAMPLE_TEXTURE2D(tex, sampler##tex, uv)
+#else
+#define MTOON_DECLARE_TEX2D(tex) UNITY_DECLARE_TEX2D(tex)
+#define MTOON_DECLARE_TEX2D_FLOAT(tex) UNITY_DECLARE_TEX2D_FLOAT(tex);
+#define MTOON_SAMPLE_TEXTURE2D(tex, uv) UNITY_SAMPLE_TEX2D(tex, uv)
+#endif
+
+// Fog and lighting
+#ifdef MTOON_URP
+
+#ifdef REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR
+
+#define MTOON_FOG_AND_LIGHTING_COORDS(idx1, idx2, idx3) \
+    half4 fogFactorAndVertexLight : TEXCOORD##idx1; \
+    float4 shadowCoord              : TEXCOORD##idx2; \
+    DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, idx3);
+
+#else
+
+#define MTOON_FOG_AND_LIGHTING_COORDS(idx1, idx2, idx3) \
+    half4 fogFactorAndVertexLight : TEXCOORD##idx1; \
+    DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, idx);
+
+#endif
+
+#else
+#define MTOON_FOG_AND_LIGHTING_COORDS(idx1, idx2, idx3) \
+    UNITY_FOG_COORDS(5) \
+    UNITY_LIGHTING_COORDS(6,7)
+#endif
+
+// Light
+#ifdef MTOON_URP
+
+#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
+#define MTOON_SHADOW_COORD input.shadowCoord
+#elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
+#define MTOON_SHADOW_COORD TransformWorldToShadowCoord(input.positionWS)
+#else
+#define MTOON_SHADOW_COORD float4(0, 0, 0, 0)
+#endif
+
+#if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
+#define MTOON_SAMPLE_SHADOWMASK(uv) SAMPLE_TEXTURE2D_LIGHTMAP(SHADOWMASK_NAME, SHADOWMASK_SAMPLER_NAME, uv SHADOWMASK_SAMPLE_EXTRA_ARGS)
+#elif !defined (LIGHTMAP_ON)
+#define MTOON_SAMPLE_SHADOWMASK(uv) unity_ProbesOcclusion
+#else
+#define MTOON_SAMPLE_SHADOWMASK(uv) half4(1, 1, 1, 1)
+#endif
+
+#define MTOON_LIGHT_DESCRIPTION(input, atten, lightDir, lightColor) \
+    const half3 lightDir = _MainLightPosition.xyz; \
+    const half3 lightColor = _MainLightColor.rgb; \
+    const float atten = MainLightShadow(MTOON_SHADOW_COORD, input.positionWS, MTOON_SAMPLE_SHADOWMASK(input.lightmapUV), _MainLightOcclusionProbes);
+
+#else
+
+#define MTOON_LIGHT_DESCRIPTION(input, atten, lightDir, lightColor) \
+    UNITY_LIGHT_ATTENUATION(atten, input, input.positionWS); \
+    const half3 lightDir = normalize(UnityWorldSpaceLightDir(input.positionWS)); \
+    const half3 lightColor = _LightColor0.rgb;
+
+#endif
+
+// Transfer fog and lighting
+#ifdef MTOON_URP
+
+#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
+#define MTOON_TRANSFER_FOG_AND_LIGHTING(o, outpos, coord, vertex) \
+    OUTPUT_LIGHTMAP_UV(coord.xy, unity_LightmapST, output.lightmapUV); \
+    OUTPUT_SH(output.normalWS.xyz, output.vertexSH); \
+    output.fogFactorAndVertexLight = half4(ComputeFogFactor(outpos.z), VertexLighting(output.positionWS, output.normalWS)); \
+    output.shadowCoord = GetShadowCoord(GetVertexPositionInputs(vertex.xyz)); 
+#else
+#define MTOON_TRANSFER_FOG_AND_LIGHTING(o, outpos, coord, vertex) \
+    OUTPUT_LIGHTMAP_UV(coord.xy, unity_LightmapST, output.lightmapUV); \
+    OUTPUT_SH(output.normalWS.xyz, output.vertexSH); \
+    output.fogFactorAndVertexLight = half4(ComputeFogFactor(outpos.z), VertexLighting(output.positionWS, output.normalWS));
+#endif
+
+#else
+#define MTOON_TRANSFER_FOG_AND_LIGHTING(o, outpos, coord, vertex) \
+    UNITY_TRANSFER_FOG(o, outpos); \
+    UNITY_TRANSFER_LIGHTING(o, coord.xy);
+#endif
+
+// SampleSH
+inline half3 MToon_SampleSH(half3 normalWS)
+{
+    #ifdef MTOON_URP
+    return SampleSH(normalWS);
+    #else
+    return ShadeSH9(half4(normalWS, 1));
+    #endif
+}
+
+// Transform
+inline float3 MToon_TransformObjectToWorldNormal(float3 normalOS)
+{
+    #ifdef MTOON_URP
+    return TransformObjectToWorldNormal(normalOS);
+    #else
+    return UnityObjectToWorldNormal(normalOS);
+    #endif
+}
+
+inline float4 MToon_TransformWorldToHClip(float3 positionWS)
+{
+    #ifdef MTOON_URP
+    return TransformWorldToHClip(positionWS);
+    #else
+    return UnityWorldToClipPos(positionWS);
+    #endif
+}
+
+inline float4 MToon_TransformObjectToHClip(float3 positionOS)
+{
+    #ifdef MTOON_URP
+    return TransformObjectToHClip(positionOS);
+    #else
+    return UnityObjectToClipPos(positionOS);
+    #endif
+}
+
+inline float3 MToon_TransformViewToHClip(float3 positionVS)
+{
+    #ifdef MTOON_URP
+    return mul((float3x3)GetViewToHClipMatrix(), positionVS);
+    #else
+    return TransformViewToProjection(positionVS);
+    #endif
+}
+
+inline float3 MToon_UnpackNormalScale(float4 packedNormal, float bumpScale)
+{
+    #ifdef MTOON_URP
+    return UnpackNormalScale(packedNormal, bumpScale);
+    #else
+    return UnpackNormalWithScale(packedNormal, bumpScale);
+    #endif
+}
+
+inline float3 MToon_TransformObjectToWorldDir(float3 dirOS)
+{
+    #ifdef MTOON_URP
+    return TransformObjectToWorldDir(dirOS);
+    #else
+    return UnityObjectToWorldDir(dirOS);
+    #endif
+}
+
+#endif
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_render_pipeline.hlsl.meta b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_render_pipeline.hlsl.meta
new file mode 100644
index 000000000..c5b8dfe07
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_render_pipeline.hlsl.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 4c9e0c12587dbb5488a3e07dfc9430d3
+timeCreated: 1622632833
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_fragment.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_fragment.hlsl
new file mode 100644
index 000000000..e020417a3
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_fragment.hlsl
@@ -0,0 +1,34 @@
+#ifndef VRMC_MATERIALS_MTOON_SHADOWCASTER_FRAGMENT_INCLUDED
+#define VRMC_MATERIALS_MTOON_SHADOWCASTER_FRAGMENT_INCLUDED
+
+#ifdef MTOON_URP
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
+
+#include "./vrmc_materials_mtoon_define.hlsl"
+#include "./vrmc_materials_mtoon_utility.hlsl"
+#include "./vrmc_materials_mtoon_input.hlsl"
+#include "./vrmc_materials_mtoon_attribute.hlsl"
+#include "./vrmc_materials_mtoon_geometry_uv.hlsl"
+#include "./vrmc_materials_mtoon_geometry_alpha.hlsl"
+#include "./vrmc_materials_mtoon_geometry_normal.hlsl"
+#include "./vrmc_materials_mtoon_lighting_unity.hlsl"
+#include "./vrmc_materials_mtoon_lighting_mtoon.hlsl"
+
+half4 MToonShadowCasterFragment(const FragmentInput fragmentInput) : SV_Target
+{
+    const Varyings input = fragmentInput.varyings;
+    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
+
+    // Get MToon UV (with UVAnimation)
+    const float2 uv = GetMToonGeometry_Uv(input.uv);
+
+    // Get LitColor with Alpha
+    const half4 litColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv) * _Color;
+    GetMToonGeometry_Alpha(litColor);
+
+    return 0;
+}
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_fragment.hlsl.meta b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_fragment.hlsl.meta
new file mode 100644
index 000000000..9b6e1469d
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_fragment.hlsl.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: de3bc67bd63189846842d2a03b2b13a9
+ShaderImporter:
+  externalObjects: {}
+  defaultTextures: []
+  nonModifiableTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_vertex.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_vertex.hlsl
new file mode 100644
index 000000000..28311104a
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_vertex.hlsl
@@ -0,0 +1,53 @@
+#ifndef VRMC_MATERIALS_MTOON_SHADOWCASTER_VERTEX_INCLUDED
+#define VRMC_MATERIALS_MTOON_SHADOWCASTER_VERTEX_INCLUDED
+
+#ifdef MTOON_URP
+
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
+
+#include "./vrmc_materials_mtoon_define.hlsl"
+#include "./vrmc_materials_mtoon_utility.hlsl"
+#include "./vrmc_materials_mtoon_input.hlsl"
+#include "./vrmc_materials_mtoon_attribute.hlsl"
+#include "./vrmc_materials_mtoon_geometry_vertex.hlsl"
+
+float3 _LightDirection;
+
+VertexPositionInfo MToon_GetShadowCasterVertex(const float3 positionOS, const float3 normalWS)
+{
+    VertexPositionInfo output;
+    output.positionWS = mul(unity_ObjectToWorld, float4(positionOS, 1));
+    float4 positionCS = TransformWorldToHClip(ApplyShadowBias(output.positionWS.xyz, normalWS, _LightDirection));
+
+    #if UNITY_REVERSED_Z
+    positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
+    #else
+    positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
+    #endif
+    
+    output.positionCS = positionCS;
+
+    return output;
+}
+
+Varyings MToonShadowCasterVertex(const Attributes v)
+{
+    Varyings output = (Varyings)0;
+
+    UNITY_SETUP_INSTANCE_ID(v);
+    UNITY_TRANSFER_INSTANCE_ID(v, output);
+    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
+
+    float3 normalWS = TransformObjectToWorldNormal(v.normalOS);
+    const VertexPositionInfo position = MToon_GetShadowCasterVertex(v.vertex.xyz, normalWS);
+
+    output.pos = position.positionCS;
+    output.uv = v.texcoord0;
+
+    return output;
+}
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_vertex.hlsl.meta b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_vertex.hlsl.meta
new file mode 100644
index 000000000..fd4fe6a34
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_shadowcaster_vertex.hlsl.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 06e9bdc3bc909534399f25d6769c8396
+ShaderImporter:
+  externalObjects: {}
+  defaultTextures: []
+  nonModifiableTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_urp.shader b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_urp.shader
new file mode 100644
index 000000000..593becb3a
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_urp.shader
@@ -0,0 +1,251 @@
+Shader "VRM10/Universal Render Pipeline/MToon10"
+{
+    Properties
+    {
+        // Rendering
+        _AlphaMode ("alphaMode", Int) = 0
+        _TransparentWithZWrite ("mtoon.transparentWithZWrite", Int) = 0
+        _Cutoff ("alphaCutoff", Range(0, 1)) = 0.5 // Unity specified name
+        _RenderQueueOffset ("mtoon.renderQueueOffsetNumber", Int) = 0
+        _DoubleSided ("doubleSided", Int) = 0
+
+        // Lighting
+        _Color ("pbrMetallicRoughness.baseColorFactor", Color) = (1, 1, 1, 1) // Unity specified name
+        _MainTex ("pbrMetallicRoughness.baseColorTexture", 2D) = "white" {} // Unity specified name
+        _ShadeColor ("mtoon.shadeColorFactor", Color) = (1, 1, 1, 1)
+        _ShadeTex ("mtoon.shadeMultiplyTexture", 2D) = "white" {}
+        [Normal] _BumpMap ("normalTexture", 2D) = "bump" {} // Unity specified name
+        _BumpScale ("normalTexture.scale", Float) = 1.0 // Unity specified name
+        _ShadingShiftFactor ("mtoon.shadingShiftFactor", Range(-1, 1)) = -0.05
+        _ShadingShiftTex ("mtoon.shadingShiftTexture", 2D) = "black" {} // channel R
+        _ShadingShiftTexScale ("mtoon.shadingShiftTexture.scale", Float) = 1
+        _ShadingToonyFactor ("mtoon.shadingToonyFactor", Range(0, 1)) = 0.95
+
+        // GI
+        _GiEqualization ("mtoon.giEqualizationFactor", Range(0, 1)) = 0.9
+
+        // Emission
+        [HDR] _EmissionColor ("emissiveFactor", Color) = (0, 0, 0, 1) // Unity specified name
+        _EmissionMap ("emissiveTexture", 2D) = "white" {} // Unity specified name
+
+        // Rim Lighting
+        _MatcapColor ("mtoon.matcapFactor", Color) = (0, 0, 0, 1)
+        _MatcapTex ("mtoon.matcapTexture", 2D) = "black" {}
+        _RimColor ("mtoon.parametricRimColorFactor", Color) = (0, 0, 0, 1)
+        _RimFresnelPower ("mtoon.parametricRimFresnelPowerFactor", Range(0, 100)) = 5.0
+        _RimLift ("mtoon.parametricRimLiftFactor", Range(0, 1)) = 0
+        _RimTex ("mtoon.rimMultiplyTexture", 2D) = "white" {}
+        _RimLightingMix ("mtoon.rimLightingMixFactor", Range(0, 1)) = 1
+
+        // Outline
+        _OutlineWidthMode ("mtoon.outlineWidthMode", Int) = 0
+        [PowerSlider(2.2)] _OutlineWidth ("mtoon.outlineWidthFactor", Range(0, 0.05)) = 0
+        _OutlineWidthTex ("mtoon.outlineWidthMultiplyTexture", 2D) = "white" {} // channel G
+        _OutlineColor ("mtoon.outlineColorFactor", Color) = (0, 0, 0, 1)
+        _OutlineLightingMix ("mtoon.outlineLightingMixFactor", Range(0, 1)) = 1
+
+        // UV Animation
+        _UvAnimMaskTex ("mtoon.uvAnimationMaskTexture", 2D) = "white" {} // channel B
+        _UvAnimScrollXSpeed ("mtoon.uvAnimationScrollXSpeedFactor", Float) = 0
+        _UvAnimScrollYSpeed ("mtoon.uvAnimationScrollYSpeedFactor", Float) = 0
+        _UvAnimRotationSpeed ("mtoon.uvAnimationRotationSpeedFactor", Float) = 0
+
+        // Unity ShaderPass Mode
+        _M_CullMode ("_CullMode", Float) = 2.0
+        _M_SrcBlend ("_SrcBlend", Float) = 1.0
+        _M_DstBlend ("_DstBlend", Float) = 0.0
+        _M_ZWrite ("_ZWrite", Float) = 1.0
+        _M_AlphaToMask ("_AlphaToMask", Float) = 0.0
+
+        // etc
+        _M_DebugMode ("_DebugMode", Float) = 0.0
+
+        // for Editor
+        _M_EditMode ("_EditMode", Float) = 0.0
+    }
+
+    // Shader Model 3.0
+    SubShader
+    {
+        Tags
+        {
+            "RenderType" = "Opaque"
+            "RenderPipeline" = "UniversalPipeline"
+            "UniversalMaterialType" = "Lit"
+            "IgnoreProjector" = "True"
+        }
+
+        // Universal Forward Pass
+        Pass
+        {
+            Name "UniversalForward"
+            Tags { "LightMode" = "UniversalForward" }
+
+            Cull [_M_CullMode]
+            Blend [_M_SrcBlend] [_M_DstBlend]
+            ZWrite [_M_ZWrite]
+            ZTest LEqual
+            BlendOp Add, Max
+            AlphaToMask [_M_AlphaToMask]
+
+            HLSLPROGRAM
+            #pragma target 3.0
+
+            // Unity defined keywords
+            #pragma multi_compile_fog
+            #pragma multi_compile_instancing
+
+            #pragma multi_compile __ _ALPHATEST_ON _ALPHABLEND_ON
+            #pragma multi_compile __ _NORMALMAP
+            #pragma multi_compile __ _MTOON_EMISSIVEMAP
+            #pragma multi_compile __ _MTOON_RIMMAP
+            #pragma multi_compile __ _MTOON_PARAMETERMAP
+
+            // -------------------------------------
+            // Universal Pipeline keywords
+            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
+            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
+            #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
+            #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
+            #pragma multi_compile_fragment _ _SHADOWS_SOFT
+            #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
+            #pragma multi_compile _ SHADOWS_SHADOWMASK
+            #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
+            
+            #pragma vertex MToonVertex
+            #pragma fragment MToonFragment
+
+            #define MTOON_URP
+
+            #include "./vrmc_materials_mtoon_forward_vertex.hlsl"
+            #include "./vrmc_materials_mtoon_forward_fragment.hlsl"
+            ENDHLSL
+        }
+
+        // MToon Outline Pass
+        Pass
+        {
+            Name "MToonOutline"
+            Tags { "LightMode" = "MToonOutline" }
+
+            Cull Front
+            Blend [_M_SrcBlend] [_M_DstBlend]
+            ZWrite [_M_ZWrite]
+            ZTest LEqual
+            Offset 1, 1
+            BlendOp Add, Max
+            AlphaToMask [_M_AlphaToMask]
+
+            HLSLPROGRAM
+            #pragma target 3.0
+
+            // Unity defined keywords
+            #pragma multi_compile_fog
+            #pragma multi_compile_instancing
+
+            #pragma multi_compile __ _ALPHATEST_ON _ALPHABLEND_ON
+            #pragma multi_compile __ _NORMALMAP
+            #pragma multi_compile __ _MTOON_EMISSIVEMAP
+            #pragma multi_compile __ _MTOON_RIMMAP
+            #pragma multi_compile __ _MTOON_PARAMETERMAP
+            #pragma multi_compile __ _MTOON_OUTLINE_WORLD _MTOON_OUTLINE_SCREEN
+
+            #pragma vertex MToonVertex
+            #pragma fragment MToonFragment
+
+            #define MTOON_URP
+            #define MTOON_PASS_OUTLINE
+
+            #include "./vrmc_materials_mtoon_forward_vertex.hlsl"
+            #include "./vrmc_materials_mtoon_forward_fragment.hlsl"
+            ENDHLSL
+        }
+
+        //  Depth Only Pass
+        Pass
+        {
+            Name "DepthOnly"
+            Tags { "LightMode" = "DepthOnly" }
+
+            Cull [_M_CullMode]
+            ZWrite On
+            ColorMask 0
+
+            HLSLPROGRAM
+            #pragma target 3.0
+
+            // Unity defined keywords
+            #pragma multi_compile_instancing
+
+            #pragma multi_compile __ _ALPHATEST_ON _ALPHABLEND_ON
+
+            #pragma vertex MToonDepthOnlyVertex
+            #pragma fragment MToonDepthOnlyFragment
+
+            #define MTOON_URP
+            
+            #include "./vrmc_materials_mtoon_depthonly_vertex.hlsl"
+            #include "./vrmc_materials_mtoon_depthonly_fragment.hlsl"
+            ENDHLSL
+        }
+
+        //  Depth Normals Pass
+        Pass
+        {
+            Name "DepthNormals"
+            Tags { "LightMode" = "DepthNormals" }
+
+            Cull [_M_CullMode]
+            ZWrite On
+
+            HLSLPROGRAM
+            #pragma target 3.0
+
+            // Unity defined keywords
+            #pragma multi_compile_instancing
+
+            #pragma multi_compile __ _ALPHATEST_ON _ALPHABLEND_ON
+            #pragma multi_compile __ _NORMALMAP
+
+            #pragma vertex MToonDepthNormalsVertex
+            #pragma fragment MToonDepthNormalsFragment
+
+            #define MTOON_URP
+            
+            #include "./vrmc_materials_mtoon_depthnormals_vertex.hlsl"
+            #include "./vrmc_materials_mtoon_depthnormals_fragment.hlsl"
+            ENDHLSL
+        }
+
+        //  Shadow Caster Pass
+        Pass
+        {
+            Name "ShadowCaster"
+            Tags { "LightMode" = "ShadowCaster" }
+
+            Cull [_M_CullMode]
+            ZWrite On
+            ZTest LEqual
+
+            HLSLPROGRAM
+            #pragma target 3.0
+
+            // Unity defined keywords
+            #pragma multi_compile_instancing
+
+            #pragma multi_compile __ _ALPHATEST_ON _ALPHABLEND_ON
+
+            #pragma vertex MToonShadowCasterVertex
+            #pragma fragment MToonShadowCasterFragment
+
+            #define MTOON_URP
+            
+            #include "./vrmc_materials_mtoon_shadowcaster_vertex.hlsl"
+            #include "./vrmc_materials_mtoon_shadowcaster_fragment.hlsl"
+            ENDHLSL
+        }
+    }
+
+    FallBack "Hidden/Universal Render Pipeline/FallbackError"
+    CustomEditor "VRMShaders.VRM10.MToon10.Editor.MToonInspector"
+}
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_urp.shader.meta b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_urp.shader.meta
new file mode 100644
index 000000000..9d51e8d1a
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_urp.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 0781c64b7f2a1604ea6aa7e252080372
+timeCreated: 1514111466
+licenseType: Free
+ShaderImporter:
+  defaultTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_utility.hlsl b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_utility.hlsl
index b9703bdab..b9b517940 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_utility.hlsl
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Resources/VRM10/vrmc_materials_mtoon_utility.hlsl
@@ -1,7 +1,11 @@
 #ifndef VRMC_MATERIALS_MTOON_UTILITY_INCLUDED
 #define VRMC_MATERIALS_MTOON_UTILITY_INCLUDED
 
+#ifdef MTOON_URP
+#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
+#else
 #include 
+#endif
 
 // define
 static const float PI_2 = 6.28318530718;
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToon10Context.cs b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToon10Context.cs
index 67b59ad44..e06f82746 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToon10Context.cs
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToon10Context.cs
@@ -111,6 +111,10 @@ namespace VRMShaders.VRM10.MToon10.Runtime
             get => _material.GetTexture(MToon10Prop.EmissiveTexture);
         }
         // Rim Lighting
+        public Color MatcapColorFactorSrgb
+        {
+            get => _material.GetColor(MToon10Prop.MatcapColorFactor);
+        }
         public Texture MatcapTexture
         {
             get => _material.GetTexture(MToon10Prop.MatcapTexture);
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderFeature.cs b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderFeature.cs
new file mode 100644
index 000000000..28b610f8d
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderFeature.cs
@@ -0,0 +1,25 @@
+#if MTOON_URP
+using UnityEngine.Rendering;
+using UnityEngine.Rendering.Universal;
+
+namespace VRMShaders.VRM10.MToon10.Runtime
+{
+    public sealed class MToonOutlineRenderFeature : ScriptableRendererFeature
+    {
+        private MToonOutlineRenderPass _opaquePass;
+        private MToonOutlineRenderPass _transparentPass;
+
+        public override void Create()
+        {
+            _opaquePass = new MToonOutlineRenderPass(RenderPassEvent.AfterRenderingOpaques, RenderQueueRange.opaque);
+            _transparentPass = new MToonOutlineRenderPass(RenderPassEvent.BeforeRenderingTransparents, RenderQueueRange.transparent);
+        }
+
+        public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
+        {
+            renderer.EnqueuePass(_opaquePass);
+            renderer.EnqueuePass(_transparentPass);
+        }
+    }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderFeature.cs.meta b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderFeature.cs.meta
new file mode 100644
index 000000000..e0a69838c
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderFeature.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5b6d00cd3f0249a2b4ee7dc86f9a8d63
+timeCreated: 1682661280
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderPass.cs b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderPass.cs
new file mode 100644
index 000000000..9aa172f23
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderPass.cs
@@ -0,0 +1,50 @@
+#if MTOON_URP
+using UnityEngine.Rendering;
+using UnityEngine.Rendering.Universal;
+
+namespace VRMShaders.VRM10.MToon10.Runtime
+{
+    public sealed class MToonOutlineRenderPass : ScriptableRenderPass
+    {
+        private const string ProfilerTag = nameof(MToonOutlineRenderPass);
+        private readonly ProfilingSampler _profilingSampler = new ProfilingSampler(ProfilerTag);
+
+        private readonly RenderQueueRange _renderQueueRange;
+        
+        public MToonOutlineRenderPass(RenderPassEvent renderPassEvent, RenderQueueRange renderQueueRange)
+        {
+            _renderQueueRange = renderQueueRange;
+            this.renderPassEvent = renderPassEvent;
+        }
+
+        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
+        {
+            var cmd = CommandBufferPool.Get();
+            using (new ProfilingScope(cmd, _profilingSampler))
+            {
+                context.ExecuteCommandBuffer(cmd);
+                cmd.Clear();
+
+                var camera = renderingData.cameraData.camera;
+                var shaderTagId = new ShaderTagId("MToonOutline");
+                var sortingSettings = new SortingSettings(camera);
+                var drawingSettings = new DrawingSettings(shaderTagId, sortingSettings)
+                {
+                    perObjectData = PerObjectData.ReflectionProbes | PerObjectData.Lightmaps |
+                                    PerObjectData.LightProbe | PerObjectData.LightData | PerObjectData.OcclusionProbe |
+                                    PerObjectData.ShadowMask
+                };
+                var filteringSettings = FilteringSettings.defaultValue;
+                filteringSettings.renderQueueRange = _renderQueueRange;
+                var renderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
+                context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filteringSettings,
+                    ref renderStateBlock);
+            }
+
+            context.ExecuteCommandBuffer(cmd);
+            cmd.Clear();
+            CommandBufferPool.Release(cmd);
+        }
+    }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderPass.cs.meta b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderPass.cs.meta
new file mode 100644
index 000000000..e26639ad2
--- /dev/null
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/MToonOutlineRenderPass.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: df162971c1034acdbe28ff1ec94d8601
+timeCreated: 1682665616
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Meta.cs b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Meta.cs
index 8141abb90..33e485a96 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Meta.cs
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Meta.cs
@@ -3,5 +3,6 @@
     public static class MToon10Meta
     {
         public static readonly string UnityShaderName = "VRM10/MToon10";
+        public static readonly string URPUnityShaderName = "VRM10/Universal Render Pipeline/MToon10";
     }
 }
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Prop.cs b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Prop.cs
index 6a0b6e386..f21a4c8c3 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Prop.cs
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Prop.cs
@@ -29,6 +29,7 @@
         EmissiveTexture,
 
         // Rim Lighting
+        MatcapColorFactor,
         MatcapTexture,
         ParametricRimColorFactor,
         ParametricRimFresnelPowerFactor,
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Properties.cs b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Properties.cs
index fb209cfcc..d7d684284 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Properties.cs
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/UnityShaderLab/Properties/MToon10Properties.cs
@@ -28,6 +28,7 @@ namespace VRMShaders.VRM10.MToon10.Runtime
             [MToon10Prop.EmissiveFactor] = "_EmissionColor",
             [MToon10Prop.EmissiveTexture] = "_EmissionMap",
 
+            [MToon10Prop.MatcapColorFactor] = "_MatcapColor",
             [MToon10Prop.MatcapTexture] = "_MatcapTex",
             [MToon10Prop.ParametricRimColorFactor] = "_RimColor",
             [MToon10Prop.ParametricRimFresnelPowerFactor] = "_RimFresnelPower",
diff --git a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/VRMShaders.VRM10.MToon10.Runtime.asmdef b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/VRMShaders.VRM10.MToon10.Runtime.asmdef
index 25f494397..df7c69f39 100644
--- a/Assets/External/VRMShaders/VRM10/MToon10/Runtime/VRMShaders.VRM10.MToon10.Runtime.asmdef
+++ b/Assets/External/VRMShaders/VRM10/MToon10/Runtime/VRMShaders.VRM10.MToon10.Runtime.asmdef
@@ -1,6 +1,10 @@
 {
     "name": "VRMShaders.VRM10.MToon10.Runtime",
-    "references": [],
+    "rootNamespace": "",
+    "references": [
+        "GUID:15fc0a57446b3144c949da3e2b9737a9",
+        "GUID:df380645f10b7bc4b97d4f5eb6303d95"
+    ],
     "includePlatforms": [],
     "excludePlatforms": [],
     "allowUnsafeCode": false,
@@ -8,6 +12,12 @@
     "precompiledReferences": [],
     "autoReferenced": false,
     "defineConstraints": [],
-    "versionDefines": [],
+    "versionDefines": [
+        {
+            "name": "com.unity.render-pipelines.universal",
+            "expression": "",
+            "define": "MTOON_URP"
+        }
+    ],
     "noEngineReferences": false
 }
\ No newline at end of file
diff --git a/Assets/External/VRMShaders/VRM10/VRM10Shaders.shadervariants b/Assets/External/VRMShaders/VRM10/VRM10Shaders.shadervariants
index 8255b2c68..862245327 100644
--- a/Assets/External/VRMShaders/VRM10/VRM10Shaders.shadervariants
+++ b/Assets/External/VRMShaders/VRM10/VRM10Shaders.shadervariants
@@ -11,7 +11,7 @@ ShaderVariantCollection:
   - first: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
     second:
       variants: []
-  - first: {fileID: 4800000, guid: 1a97144e4ad27a04aafd70f7b915cedb, type: 3}
+  - first: {fileID: 4800000, guid: e0edbf68d81d1f340ae8b110086b7063, type: 3}
     second:
       variants: []
   - first: {fileID: 4800000, guid: 8c17b56f4bf084c47872edcb95237e4a, type: 3}
diff --git a/Assets/External/VRMShaders/package.json b/Assets/External/VRMShaders/package.json
index 327dfcd81..53b059cc9 100644
--- a/Assets/External/VRMShaders/package.json
+++ b/Assets/External/VRMShaders/package.json
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:b9a7a99ec1802a892db82301bedb4258601d80ca553ab46d6f2401d45a97db5a
-size 237
+oid sha256:c6a699e2e234e34a4ce9402ec9f3a6eea49bda66136245177e12a886332088dc
+size 312
diff --git a/Assets/External/uOSC.meta b/Assets/External/uOSC.meta
new file mode 100644
index 000000000..f7ca73097
--- /dev/null
+++ b/Assets/External/uOSC.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: f8cc2f15087e84e158a8308baf60dd6e
+folderAsset: yes
+timeCreated: 1502625976
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Editor.meta b/Assets/External/uOSC/Editor.meta
new file mode 100644
index 000000000..e55060a2a
--- /dev/null
+++ b/Assets/External/uOSC/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 32eff7c82f0c8f84c9cd2a8fff2d6356
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Editor/EditorUtil.cs b/Assets/External/uOSC/Editor/EditorUtil.cs
new file mode 100644
index 000000000..a2f2502d3
--- /dev/null
+++ b/Assets/External/uOSC/Editor/EditorUtil.cs
@@ -0,0 +1,86 @@
+using UnityEngine;
+using UnityEditor;
+
+namespace uOSC
+{
+
+public static class EditorUtil
+{
+    public static string GetKey(string title, string category)
+    {
+        return $"uOSC-{title}-{category}";
+    }
+
+    private static string GetFoldOutKey(string title)
+    {
+        return GetKey(title, "FoldOut");
+    }
+
+    public static bool EditorOnlyToggle(string title, string category, bool initialState)
+    {
+        var keyTitle = title.Replace(" ", "_");
+        var key = GetKey(keyTitle, category);
+        var value = EditorPrefs.GetBool(key, initialState);
+        var newValue = EditorGUILayout.Toggle(title, value);
+        if (newValue != value)
+        {
+            EditorPrefs.SetBool(key, newValue);
+        }
+        return newValue;
+    }
+
+    public static bool IsFoldOutOpened(string title)
+    {
+        return EditorPrefs.GetBool(GetFoldOutKey(title));
+    }
+
+    public static bool Foldout(string title, bool initialState)
+    {
+        var style = new GUIStyle("ShurikenModuleTitle");
+        style.font = new GUIStyle(EditorStyles.label).font;
+        style.border = new RectOffset(15, 7, 4, 4);
+        style.fixedHeight = 22;
+        style.contentOffset = new Vector2(20f, -2f);
+        style.margin = new RectOffset((EditorGUI.indentLevel + 1) * 16, 0, 0, 0);
+
+        var key = GetFoldOutKey(title);
+        bool display = EditorPrefs.GetBool(key, initialState);
+
+        var rect = GUILayoutUtility.GetRect(16f, 22f, style);
+        GUI.Box(rect, title, style);
+
+        var e = Event.current;
+
+        var toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f);
+        if (e.type == EventType.Repaint) 
+        {
+            EditorStyles.foldout.Draw(toggleRect, false, false, display, false);
+        }
+
+        if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) 
+        {
+            EditorPrefs.SetBool(key, !display);
+            e.Use();
+        }
+
+        return display;
+    }
+
+    public static bool SimpleFoldout(string title, bool initialState, string additionalKey = "")
+    {
+        var key = GetFoldOutKey(title + additionalKey);
+        bool display = EditorPrefs.GetBool(key, initialState);
+        bool newDisplay = EditorGUILayout.Foldout(display, title, EditorStyles.foldoutHeader);
+        if (newDisplay != display) EditorPrefs.SetBool(key, newDisplay);
+        return newDisplay;
+    }
+
+    public static void DrawProperty(SerializedObject obj, string propName)
+    {
+        var prop = obj.FindProperty(propName);
+        if (prop == null) return;
+        EditorGUILayout.PropertyField(prop);
+    }
+}
+
+}
diff --git a/Assets/External/uOSC/Editor/EditorUtil.cs.meta b/Assets/External/uOSC/Editor/EditorUtil.cs.meta
new file mode 100644
index 000000000..a9ba5718c
--- /dev/null
+++ b/Assets/External/uOSC/Editor/EditorUtil.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 318f692a71b639e49ba0b18c84fb4623
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/VRMShaders/VRM/IO/Editor/VRMShaders.VRM.IO.Editor.asmdef b/Assets/External/uOSC/Editor/uOSC.Editor.asmdef
similarity index 69%
rename from Assets/External/VRMShaders/VRM/IO/Editor/VRMShaders.VRM.IO.Editor.asmdef
rename to Assets/External/uOSC/Editor/uOSC.Editor.asmdef
index 683e958e1..96c831849 100644
--- a/Assets/External/VRMShaders/VRM/IO/Editor/VRMShaders.VRM.IO.Editor.asmdef
+++ b/Assets/External/uOSC/Editor/uOSC.Editor.asmdef
@@ -1,7 +1,8 @@
 {
-    "name": "VRMShaders.VRM.IO.Editor",
+    "name": "uOSC.Editor",
+    "rootNamespace": "",
     "references": [
-        "GUID:301b251fd9834274c9228e0532f444f7"
+        "GUID:e8063cf3a345f9c46b7c7c4f14d54285"
     ],
     "includePlatforms": [
         "Editor"
@@ -10,7 +11,7 @@
     "allowUnsafeCode": false,
     "overrideReferences": false,
     "precompiledReferences": [],
-    "autoReferenced": false,
+    "autoReferenced": true,
     "defineConstraints": [],
     "versionDefines": [],
     "noEngineReferences": false
diff --git a/Assets/External/uOSC/Editor/uOSC.Editor.asmdef.meta b/Assets/External/uOSC/Editor/uOSC.Editor.asmdef.meta
new file mode 100644
index 000000000..57e90edf9
--- /dev/null
+++ b/Assets/External/uOSC/Editor/uOSC.Editor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 0cf9b36876ffd3d4289f50a966b77d21
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Editor/uOscClientEditor.cs b/Assets/External/uOSC/Editor/uOscClientEditor.cs
new file mode 100644
index 000000000..b409d8511
--- /dev/null
+++ b/Assets/External/uOSC/Editor/uOscClientEditor.cs
@@ -0,0 +1,90 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+
+namespace uOSC
+{
+
+[CustomEditor(typeof(uOscClient))]
+public class uOscClientEditor : Editor
+{
+    uOscClient client { get { return target as uOscClient; } }
+
+    public override void OnInspectorGUI()
+    {
+        serializedObject.Update();
+
+        if (EditorUtil.Foldout("Client", true))
+        {
+            ++EditorGUI.indentLevel;
+            DrawClient();
+            EditorGUILayout.Separator();
+            --EditorGUI.indentLevel;
+        }
+
+        if (EditorUtil.Foldout("Events", false))
+        {
+            ++EditorGUI.indentLevel;
+            DrawEvents();
+            EditorGUILayout.Separator();
+            --EditorGUI.indentLevel;
+        }
+
+        if (EditorUtil.Foldout("Advanced", false))
+        {
+            ++EditorGUI.indentLevel;
+            DrawAdvanced();
+            EditorGUILayout.Separator();
+            --EditorGUI.indentLevel;
+        }
+
+        if (EditorUtil.Foldout("Status", false))
+        {
+            ++EditorGUI.indentLevel;
+            DrawStatus();
+            EditorGUILayout.Separator();
+            --EditorGUI.indentLevel;
+        }
+
+        serializedObject.ApplyModifiedProperties();
+    }
+
+    void DrawClient()
+    {
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscClient.address));
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscClient.port));
+    }
+
+    void DrawAdvanced()
+    {
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscClient.maxQueueSize));
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscClient.dataTransimissionInterval));
+    }
+
+    void DrawEvents()
+    {
+        EditorGUILayout.Separator();
+
+        EditorGUILayout.BeginHorizontal();
+        EditorGUILayout.Space(10f, false);
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscClient.onClientStarted));
+        EditorGUILayout.EndHorizontal();
+
+        EditorGUILayout.BeginHorizontal();
+        EditorGUILayout.Space(10f, false);
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscClient.onClientStopped));
+        EditorGUILayout.EndHorizontal();
+    }
+
+    void DrawStatus()
+    {
+        var skin = GUI.skin.label;
+        skin.richText = true;
+        var status = client.isRunning ?
+            "Running" :
+            "Stop";
+        EditorGUILayout.LabelField("Status", status, skin);
+    }
+}
+
+}
diff --git a/Assets/External/uOSC/Editor/uOscClientEditor.cs.meta b/Assets/External/uOSC/Editor/uOscClientEditor.cs.meta
new file mode 100644
index 000000000..834acf19d
--- /dev/null
+++ b/Assets/External/uOSC/Editor/uOscClientEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 997a71092f149ee4aafa0f41e0ddf8ec
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Editor/uOscServerEditor.cs b/Assets/External/uOSC/Editor/uOscServerEditor.cs
new file mode 100644
index 000000000..fd79fb81b
--- /dev/null
+++ b/Assets/External/uOSC/Editor/uOscServerEditor.cs
@@ -0,0 +1,133 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace uOSC
+{
+
+[CustomEditor(typeof(uOscServer))]
+public class uOscServerEditor : Editor
+{
+    uOscServer server { get { return target as uOscServer; } }
+    Queue messages = new Queue();
+    Vector2 messageScrollPos = Vector2.zero;
+    StringBuilder messageStringBuilder = new StringBuilder();
+
+    void OnEnable()
+    {
+        server._onDataReceivedEditor.AddListener(OnMessage);
+    }
+
+    void OnDisable()
+    {
+        server._onDataReceivedEditor.RemoveListener(OnMessage);
+    }
+
+    public override void OnInspectorGUI()
+    {
+        serializedObject.Update();
+
+        if (EditorUtil.Foldout("Server", true))
+        {
+            ++EditorGUI.indentLevel;
+            DrawServer();
+            EditorGUILayout.Separator();
+            --EditorGUI.indentLevel;
+        }
+
+        if (EditorUtil.Foldout("Events", false))
+        {
+            ++EditorGUI.indentLevel;
+            DrawEvents();
+            EditorGUILayout.Separator();
+            --EditorGUI.indentLevel;
+        }
+
+        if (EditorUtil.Foldout("Status", false))
+        {
+            ++EditorGUI.indentLevel;
+            DrawStatus();
+            EditorGUILayout.Separator();
+            --EditorGUI.indentLevel;
+        }
+
+        serializedObject.ApplyModifiedProperties();
+    }
+
+    void OnMessage(Message msg)
+    {
+        messages.Enqueue(msg);
+
+        while (messages.Count > 100)
+        {
+            messages.Dequeue();
+        }
+    }
+
+    void DrawServer()
+    {
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscServer.port));
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscServer.autoStart));
+    }
+
+    void DrawEvents()
+    {
+        EditorGUILayout.Separator();
+
+        EditorGUILayout.BeginHorizontal();
+        EditorGUILayout.Space(10f, false);
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscServer.onDataReceived));
+        EditorGUILayout.EndHorizontal();
+
+        EditorGUILayout.BeginHorizontal();
+        EditorGUILayout.Space(10f, false);
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscServer.onServerStarted));
+        EditorGUILayout.EndHorizontal();
+
+        EditorGUILayout.BeginHorizontal();
+        EditorGUILayout.Space(10f, false);
+        EditorUtil.DrawProperty(serializedObject, nameof(uOscServer.onServerStopped));
+        EditorGUILayout.EndHorizontal();
+    }
+
+    void DrawStatus()
+    {
+        var skin = GUI.skin.label;
+        skin.richText = true;
+        var status = server.isRunning ?
+            "Running" :
+            "Stop";
+        EditorGUILayout.LabelField("Status", status, skin);
+
+        if (EditorUtil.SimpleFoldout("Messages", false))
+        {
+            EditorGUILayout.BeginVertical(GUILayout.MinHeight(200f));
+
+            messageStringBuilder.Clear();
+            messageScrollPos = EditorGUILayout.BeginScrollView(messageScrollPos, GUI.skin.box);
+            foreach (var msg in messages.Reverse())
+            {
+                messageStringBuilder.AppendLine(msg.ToString());
+            }
+            var messageText = messageStringBuilder.ToString();
+            GUILayout.Label(messageText);
+            EditorGUILayout.EndScrollView();
+
+            EditorGUILayout.BeginHorizontal();
+            GUILayout.FlexibleSpace();
+            if (GUILayout.Button("Copy", GUILayout.MinWidth(100f)))
+            {
+                EditorGUIUtility.systemCopyBuffer = messageText;
+            }
+            EditorGUILayout.EndHorizontal();
+
+            EditorGUILayout.EndVertical();
+
+            Repaint();
+        }
+    }
+}
+
+}
diff --git a/Assets/External/uOSC/Editor/uOscServerEditor.cs.meta b/Assets/External/uOSC/Editor/uOscServerEditor.cs.meta
new file mode 100644
index 000000000..4bb726985
--- /dev/null
+++ b/Assets/External/uOSC/Editor/uOscServerEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1726a761e316b2241acb5a6af89f9a22
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime.meta b/Assets/External/uOSC/Runtime.meta
new file mode 100644
index 000000000..05453d326
--- /dev/null
+++ b/Assets/External/uOSC/Runtime.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5c5b5c707b969bc4a84ba219af4da39b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core.meta b/Assets/External/uOSC/Runtime/Core.meta
new file mode 100644
index 000000000..8ae3d8df6
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 93b559ac6a1c14559886b18f0b9624f5
+folderAsset: yes
+timeCreated: 1503034009
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Bundle.cs b/Assets/External/uOSC/Runtime/Core/Bundle.cs
new file mode 100644
index 000000000..e2f65e3a4
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Bundle.cs
@@ -0,0 +1,70 @@
+using System.IO;
+using System.Collections.Generic;
+
+namespace uOSC
+{
+
+public class Bundle
+{
+    private Timestamp timestamp;
+    private List elements_ = new List();
+
+    public Bundle()
+    {
+        this.timestamp = Timestamp.Immediate;
+    }
+
+    public Bundle(Timestamp timestamp)
+    {
+        this.timestamp = timestamp;
+    }
+
+    public void Add(Message message)
+    {
+        elements_.Add(message);
+    }
+
+    public void Add(Bundle bundle)
+    {
+        elements_.Add(bundle);
+    }
+
+    public void Write(MemoryStream stream)
+    {
+        Writer.Write(stream, Identifier.Bundle);
+        Writer.Write(stream, timestamp);
+
+        for (int i = 0; i < elements_.Count; ++i)
+        {
+            var elem = elements_[i];
+            if (elem is Message)
+            {
+                Write(stream, (Message)elem);
+            }
+            else if (elem is Bundle)
+            {
+                Write(stream, (Bundle)elem);
+            }
+        }
+    }
+
+    void Write(MemoryStream stream, Message message)
+    {
+        using (var tmpStream = new MemoryStream())
+        {
+            message.Write(tmpStream);
+            Writer.Write(stream, tmpStream);
+        }
+    }
+
+    void Write(MemoryStream stream, Bundle bundle)
+    {
+        using (var tmpStream = new MemoryStream())
+        {
+            bundle.Write(tmpStream);
+            Writer.Write(stream, tmpStream);
+        }
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs.meta b/Assets/External/uOSC/Runtime/Core/Bundle.cs.meta
similarity index 75%
rename from Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs.meta
rename to Assets/External/uOSC/Runtime/Core/Bundle.cs.meta
index 4359c836d..a1df0929b 100644
--- a/Assets/External/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs.meta
+++ b/Assets/External/uOSC/Runtime/Core/Bundle.cs.meta
@@ -1,6 +1,6 @@
 fileFormatVersion: 2
-guid: 20e02dc7c390454448d4a3ce7aca4d17
-timeCreated: 1545735556
+guid: dcff748175cad4d64a37f2b328988557
+timeCreated: 1503121142
 licenseType: Pro
 MonoImporter:
   serializedVersion: 2
diff --git a/Assets/External/uOSC/Runtime/Core/DotNet.meta b/Assets/External/uOSC/Runtime/Core/DotNet.meta
new file mode 100644
index 000000000..5f690805c
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/DotNet.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: ebb1db81bb3f2a54ebaa3c5c8a0a332b
+folderAsset: yes
+timeCreated: 1503140960
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/DotNet/Thread.cs b/Assets/External/uOSC/Runtime/Core/DotNet/Thread.cs
new file mode 100644
index 000000000..83e05cb06
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/DotNet/Thread.cs
@@ -0,0 +1,62 @@
+#if !NETFX_CORE
+
+using UnityEngine;
+using System;
+
+namespace uOSC.DotNet
+{
+
+public class Thread : uOSC.Thread
+{
+    System.Threading.Thread thread_;
+    bool isRunning_ = false;
+    Action loopFunc_ = null;
+
+    public override void Start(Action loopFunc)
+    {
+        if (isRunning_ || loopFunc == null) return;
+
+        isRunning_ = true;
+        loopFunc_ = loopFunc;
+
+        thread_ = new System.Threading.Thread(ThreadLoop);
+        thread_.Start();
+    }
+
+    void ThreadLoop()
+    {
+        while (isRunning_)
+        {
+            try
+            {
+                loopFunc_();
+                System.Threading.Thread.Sleep(IntervalMillisec);
+            }
+            catch (Exception e)
+            {
+                Debug.LogError(e.Message);
+                Debug.LogError(e.StackTrace);
+            }
+        }
+    }
+
+    public override void Stop(int timeoutMilliseconds = 3000)
+    {
+        if (!isRunning_) return;
+
+        isRunning_ = false;
+
+        if (thread_.IsAlive)
+        {
+            thread_.Join(timeoutMilliseconds);
+            if (thread_.IsAlive)
+            {
+                thread_.Abort();
+            }
+        }
+    }
+}
+
+}
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/DotNet/Thread.cs.meta b/Assets/External/uOSC/Runtime/Core/DotNet/Thread.cs.meta
new file mode 100644
index 000000000..ef92a3ae8
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/DotNet/Thread.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 1823f765450dd3b498b33858df0c57f1
+timeCreated: 1502677461
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/DotNet/Udp.cs b/Assets/External/uOSC/Runtime/Core/DotNet/Udp.cs
new file mode 100644
index 000000000..b98447b5d
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/DotNet/Udp.cs
@@ -0,0 +1,114 @@
+#if !NETFX_CORE
+
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+
+namespace uOSC.DotNet
+{
+
+public class Udp : uOSC.Udp
+{
+    enum State
+    {
+        Stop,
+        Server,
+        Client,
+    }
+    State state_ = State.Stop;
+
+    Queue messageQueue_ = new Queue();
+    object lockObject_ = new object();
+
+    UdpClient udpClient_;
+    IPEndPoint endPoint_;
+    Thread thread_ = new Thread();
+
+    public override int messageCount
+    {
+        get { return messageQueue_.Count; }
+    }
+
+    public override bool isRunning
+    {
+        get { return state_ != State.Stop; }
+    }
+
+    public override void StartServer(int port)
+    {
+        Stop();
+        state_ = State.Server;
+
+        try
+        {
+            endPoint_ = new IPEndPoint(IPAddress.IPv6Any, port);
+            udpClient_ = new UdpClient(AddressFamily.InterNetworkV6);
+            udpClient_.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
+            udpClient_.Client.Bind(endPoint_);
+        }
+        catch (System.Exception e)
+        {
+
+            UnityEngine.Debug.LogError(e.ToString());
+            state_ = State.Stop;
+            return;
+        }
+
+        thread_.Start(() => 
+        {
+            while (udpClient_.Available > 0) 
+            {
+                var buffer = udpClient_.Receive(ref endPoint_);
+                lock (lockObject_)
+                {
+                    messageQueue_.Enqueue(buffer);
+                }
+            }
+        });
+    }
+
+    public override void StartClient(string address, int port)
+    {
+        Stop();
+        state_ = State.Client;
+
+        var ip = IPAddress.Parse(address);
+        endPoint_ = new IPEndPoint(ip, port);
+        udpClient_ = new UdpClient(endPoint_.AddressFamily);
+    }
+
+    public override void Stop()
+    {
+        if (state_ == State.Stop) return;
+
+        thread_.Stop();
+        udpClient_.Close();
+        state_ = State.Stop;
+    }
+
+    public override void Send(byte[] data, int size)
+    {
+        try
+        {
+            udpClient_.Send(data, size, endPoint_);
+        }
+        catch (System.Exception e)
+        {
+            UnityEngine.Debug.LogError(e.ToString());
+        }
+    }
+
+    public override byte[] Receive()
+    {
+        byte[] buffer;
+        lock (lockObject_)
+        {
+            buffer = messageQueue_.Dequeue();
+        }
+        return buffer;
+    }
+}
+
+}
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/DotNet/Udp.cs.meta b/Assets/External/uOSC/Runtime/Core/DotNet/Udp.cs.meta
new file mode 100644
index 000000000..9486618a9
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/DotNet/Udp.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2ce9f0faf3aee436da29b8449f149bb1
+timeCreated: 1502963364
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Event.cs b/Assets/External/uOSC/Runtime/Core/Event.cs
new file mode 100644
index 000000000..fae47760c
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Event.cs
@@ -0,0 +1,21 @@
+using UnityEngine.Events;
+
+namespace uOSC
+{
+
+[System.Serializable]
+public class ServerStartEvent : UnityEvent {};
+
+[System.Serializable]
+public class ServerStopEvent : UnityEvent {};
+
+[System.Serializable]
+public class ClientStartEvent : UnityEvent {};
+
+[System.Serializable]
+public class ClientStopEvent : UnityEvent {};
+
+[System.Serializable]
+public class DataReceiveEvent : UnityEvent {};
+
+}
diff --git a/Assets/External/uOSC/Runtime/Core/Event.cs.meta b/Assets/External/uOSC/Runtime/Core/Event.cs.meta
new file mode 100644
index 000000000..0c03e1ad2
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Event.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: da2c0f1b4245a544781c6b6fe9cba546
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Message.cs b/Assets/External/uOSC/Runtime/Core/Message.cs
new file mode 100644
index 000000000..ea67abcc6
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Message.cs
@@ -0,0 +1,83 @@
+using System.IO;
+using System.Text;
+
+namespace uOSC
+{
+
+public struct Message
+{
+    public string address;
+    public Timestamp timestamp;
+    public object[] values;
+
+    public static Message none
+    {
+        get { return new Message(""); } 
+    }
+
+    public Message(string address, params object[] packet)
+    {
+        this.address = address;
+        this.timestamp = new Timestamp();
+        this.values = packet;
+    }
+
+    public void Write(MemoryStream stream)
+    {
+        WriteAddress(stream);
+        WriteTypes(stream);
+        WriteValues(stream);
+    }
+
+    void WriteAddress(MemoryStream stream)
+    {
+        Writer.Write(stream, address);
+    }
+
+    void WriteTypes(MemoryStream stream)
+    {
+        string types = ",";
+        for (int i = 0; i < values.Length; ++i)
+        {
+            var value = values[i];
+            if      (value is int)    types += Identifier.Int;
+            else if (value is float)  types += Identifier.Float;
+            else if (value is string) types += Identifier.String;
+            else if (value is byte[]) types += Identifier.Blob;
+            else if (value is bool)   types += (bool)value ? Identifier.True : Identifier.False;
+        }
+        Writer.Write(stream, types);
+    }
+
+    void WriteValues(MemoryStream stream)
+    {
+        for (int i = 0; i < values.Length; ++i)
+        {
+            var value = values[i];
+            if      (value is int)    Writer.Write(stream, (int)value);
+            else if (value is float)  Writer.Write(stream, (float)value);
+            else if (value is string) Writer.Write(stream, (string)value);
+            else if (value is byte[]) Writer.Write(stream, (byte[])value);
+        }
+    }
+
+    public override string ToString()
+    {
+        var str = new StringBuilder();
+
+        str.Append(address);
+        str.Append("\t");
+
+        foreach (var value in values)
+        {
+            str.Append(value.GetString());
+            str.Append(" ");
+        }
+
+        str.Append($"({timestamp.ToLocalTime()})");
+
+        return str.ToString();
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Message.cs.meta b/Assets/External/uOSC/Runtime/Core/Message.cs.meta
new file mode 100644
index 000000000..0c394901a
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Message.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 325587fe434e14dfe94533b7fb2dae7a
+timeCreated: 1502607996
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Parser.cs b/Assets/External/uOSC/Runtime/Core/Parser.cs
new file mode 100644
index 000000000..711046860
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Parser.cs
@@ -0,0 +1,124 @@
+using UnityEngine;
+using System.Collections.Generic;
+
+namespace uOSC
+{
+
+public static class Identifier
+{
+    public const string Bundle = "#bundle";
+
+    public const char Int    = 'i';
+    public const char Float  = 'f';
+    public const char String = 's';
+    public const char Blob   = 'b';
+    public const char True   = 'T';
+    public const char False  = 'F';
+}
+
+public class Parser
+{
+    public static readonly object[] EmptyObjectArray = new object[0];
+
+    object lockObject_ = new object();
+    Queue messages_ = new Queue();
+
+    public int messageCount
+    {
+        get { return messages_.Count; }
+    }
+
+    public void Parse(byte[] buf, ref int pos, int endPos, ulong timestamp = 0x1u)
+    {
+        var first = Reader.ParseString(buf, ref pos);
+
+        if (first == Identifier.Bundle)
+        {
+            ParseBundle(buf, ref pos, endPos);
+        }
+        else
+        {
+            var values = ParseData(buf, ref pos);
+            lock (lockObject_)
+            {
+                messages_.Enqueue(new Message() 
+                {
+                    address = first,
+                    timestamp = new Timestamp(timestamp),
+                    values = values
+                });
+            }
+        }
+
+        if (pos != endPos)
+        {
+            Debug.LogErrorFormat(
+                "The parsed data size is inconsitent with the given size: {0} / {1}", 
+                pos,
+                endPos);
+        }
+    }
+
+    public Message Dequeue()
+    {
+        if (messageCount == 0)
+        {
+            return Message.none;
+        }
+
+        lock (lockObject_)
+        {
+            return messages_.Dequeue();
+        }
+    }
+
+    void ParseBundle(byte[] buf, ref int pos, int endPos)
+    {
+        var time = Reader.ParseTimetag(buf, ref pos);
+
+        while (pos < endPos)
+        {
+            var contentSize = Reader.ParseInt(buf, ref pos);
+            if (Util.IsMultipleOfFour(contentSize))
+            {
+                Parse(buf, ref pos, pos + contentSize, time);
+            }
+            else
+            {
+                Debug.LogErrorFormat("Given data is invalid (bundle size ({0}) is not a multiple of 4).", contentSize);
+                pos += contentSize;
+            }
+        }
+    }
+
+    object[] ParseData(byte[] buf, ref int pos)
+    {
+        // remove ','
+        var types = Reader.ParseString(buf, ref pos).Substring(1);
+
+        var n = types.Length;
+        if (n == 0) return EmptyObjectArray;
+
+        var data = new object[n];
+
+        for (int i = 0; i < n; ++i)
+        {
+            switch (types[i])
+            {
+                case Identifier.Int    : data[i] = Reader.ParseInt(buf, ref pos); break;
+                case Identifier.Float  : data[i] = Reader.ParseFloat(buf, ref pos); break;
+                case Identifier.String : data[i] = Reader.ParseString(buf, ref pos); break;
+                case Identifier.Blob   : data[i] = Reader.ParseBlob(buf, ref pos); break;
+                case Identifier.True   : data[i] = true; break;
+                case Identifier.False  : data[i] = false; break;
+                default:
+                    // Add more types here if you want to handle them.
+                    break;
+            }
+        }
+
+        return data;
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Parser.cs.meta b/Assets/External/uOSC/Runtime/Core/Parser.cs.meta
new file mode 100644
index 000000000..8846889b2
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Parser.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5690b343ba09447f2b1bdd2a7f5dabc5
+timeCreated: 1502598770
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Reader.cs b/Assets/External/uOSC/Runtime/Core/Reader.cs
new file mode 100644
index 000000000..fc6403a03
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Reader.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Text;
+
+namespace uOSC
+{
+
+public static class Reader
+{
+    public static string ParseString(byte[] buf, ref int pos)
+    {
+        int size = 0;
+        int bufSize = buf.Length;
+        for (; buf[pos + size] != 0; ++size);
+        var value = Encoding.UTF8.GetString(buf, pos, size);
+        pos += Util.GetStringAlignedSize(size);
+        return value;
+    }
+
+    public static int ParseInt(byte[] buf, ref int pos)
+    {
+        Array.Reverse(buf, pos, 4);
+        var value = BitConverter.ToInt32(buf, pos);
+        pos += 4;
+        return value;
+    }
+
+    public static float ParseFloat(byte[] buf, ref int pos)
+    {
+        Array.Reverse(buf, pos, 4);
+        var value = BitConverter.ToSingle(buf, pos);
+        pos += 4;
+        return value;
+    }
+
+    public static byte[] ParseBlob(byte[] buf, ref int pos)
+    {
+        var size = ParseInt(buf, ref pos);
+        var value = new byte[size];
+        Buffer.BlockCopy(buf, pos, value, 0, size);
+        pos += Util.GetBufferAlignedSize(size);
+        return value;
+    }
+
+    public static ulong ParseTimetag(byte[] buf, ref int pos)
+    {
+        Array.Reverse(buf, pos, 8);
+        var value = BitConverter.ToUInt64(buf, pos);
+        pos += 8;
+        return value;
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Reader.cs.meta b/Assets/External/uOSC/Runtime/Core/Reader.cs.meta
new file mode 100644
index 000000000..5b61cf74e
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Reader.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 01d59f7294f9b4af7bd24436711ecad2
+timeCreated: 1503214726
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Thread.cs b/Assets/External/uOSC/Runtime/Core/Thread.cs
new file mode 100644
index 000000000..e78646da0
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Thread.cs
@@ -0,0 +1,12 @@
+namespace uOSC
+{
+
+public abstract class Thread
+{
+    protected const int IntervalMillisec = 1;
+
+    public abstract void Start(System.Action loopFunc);
+    public abstract void Stop(int timeoutMilliseconds = 3000);
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Thread.cs.meta b/Assets/External/uOSC/Runtime/Core/Thread.cs.meta
new file mode 100644
index 000000000..6ba04f868
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Thread.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 202680ea4799e456ab1b931109e1e017
+timeCreated: 1502677461
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Timestamp.cs b/Assets/External/uOSC/Runtime/Core/Timestamp.cs
new file mode 100644
index 000000000..99cbf074f
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Timestamp.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace uOSC
+{
+
+public struct Timestamp
+{
+    public UInt64 value;
+
+    public Timestamp(UInt64 value)
+    {
+        this.value = value;
+    }
+
+    public static readonly Timestamp Immediate = new Timestamp(0x1u);
+
+    public static Timestamp Now
+    {
+        get { return Timestamp.CreateFromDateTime(DateTime.UtcNow); }
+    }
+
+    public static Timestamp CreateFromDateTime(DateTime time)
+    {
+        var span = time - new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+        var msec = (UInt64)span.TotalMilliseconds;
+        var integerPart = msec / 1000;
+        var decimalPart = ((msec % 1000) * 0x100000000L) / 1000;
+        var timestamp = ((UInt64)integerPart << 32) | (UInt64)decimalPart;
+        return new Timestamp(timestamp);
+    }
+
+    public DateTime ToUtcTime()
+    {
+        var integerPart = (UInt64)((value >> 32) & 0xFFFFFFFF); 
+        var decimalPart = (UInt64)(value & 0xFFFFFFFF);
+        var msec = (integerPart * 1000) + ((decimalPart * 1000) / 0x100000000L);
+        var baseDate = new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
+        return baseDate.AddMilliseconds(msec);
+    }
+
+    public DateTime ToLocalTime()
+    {
+        return TimeZoneInfo.ConvertTime(ToUtcTime(), TimeZoneInfo.Local);
+    }
+}
+
+}
diff --git a/Assets/External/uOSC/Runtime/Core/Timestamp.cs.meta b/Assets/External/uOSC/Runtime/Core/Timestamp.cs.meta
new file mode 100644
index 000000000..c60512402
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Timestamp.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 70c34d21d18b54802bb1f5cf669d55d4
+timeCreated: 1503121366
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Udp.cs b/Assets/External/uOSC/Runtime/Core/Udp.cs
new file mode 100644
index 000000000..88b029921
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Udp.cs
@@ -0,0 +1,15 @@
+namespace uOSC
+{
+
+public abstract class Udp
+{
+    public abstract int messageCount { get; }
+    public abstract bool isRunning { get; }
+    public abstract void StartServer(int port);
+    public abstract void StartClient(string address, int port);
+    public abstract void Stop();
+    public abstract void Send(byte[] data, int size);
+    public abstract byte[] Receive();
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Udp.cs.meta b/Assets/External/uOSC/Runtime/Core/Udp.cs.meta
new file mode 100644
index 000000000..264ad751c
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Udp.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 984d0e61f1ff54ac4b08d93ee7e8f8da
+timeCreated: 1502961086
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Util.cs b/Assets/External/uOSC/Runtime/Core/Util.cs
new file mode 100644
index 000000000..2876b8132
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Util.cs
@@ -0,0 +1,52 @@
+using UnityEngine;
+using System;
+using System.IO;
+
+namespace uOSC
+{
+
+public static class Util
+{
+    public static bool IsMultipleOfFour(int num)
+    {
+        return num == (num & ~0x3);
+    }
+
+    public static int GetStringAlignedSize(int size)
+    {
+        return (size + 4) & ~0x3;
+    }
+
+    public static int GetBufferAlignedSize(int size)
+    {
+        var offset = size & ~0x3;
+        return (offset == size) ? size : (offset + 4);
+    }
+
+    public static string GetString(this object value)
+    {
+        if (value is int)    return ((int)value).ToString();
+        if (value is float)  return ((float)value).ToString();
+        if (value is string) return (string)value;
+        if (value is byte[]) return "Byte[" + ((byte[])value).Length + "]";
+
+        return value.ToString();
+    }
+
+    public static byte[] GetBuffer(MemoryStream stream)
+    {
+#if NETFX_CORE
+        ArraySegment buffer;
+        if (!stream.TryGetBuffer(out buffer))
+        {
+            Debug.LogError("Failed to perform MemoryStream.TryGetBuffer()");
+            return null;
+        }
+        return buffer.Array;
+#else
+        return stream.GetBuffer();
+#endif
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Util.cs.meta b/Assets/External/uOSC/Runtime/Core/Util.cs.meta
new file mode 100644
index 000000000..3d9d5194d
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Util.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 13a559a345bb6453b9394c519398056b
+timeCreated: 1502608916
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Uwp.meta b/Assets/External/uOSC/Runtime/Core/Uwp.meta
new file mode 100644
index 000000000..4c3d4a076
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Uwp.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 4abd0b1a0d146c84b898a4a827f52d24
+folderAsset: yes
+timeCreated: 1503140965
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Uwp/Thread.cs b/Assets/External/uOSC/Runtime/Core/Uwp/Thread.cs
new file mode 100644
index 000000000..e099db5ea
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Uwp/Thread.cs
@@ -0,0 +1,59 @@
+#if NETFX_CORE
+
+using UnityEngine;
+using System;
+using System.Threading.Tasks;
+
+namespace uOSC.Uwp
+{
+
+public class Thread : uOSC.Thread
+{
+    Task task_;
+    bool isRunning_ = false;
+    Action loopFunc_ = null;
+
+    public override void Start(Action loopFunc)
+    {
+        if (isRunning_ || loopFunc == null) return;
+
+        isRunning_ = true;
+        loopFunc_ = loopFunc;
+
+        task_ =  new Task(ThreadLoop);
+        task_.Start();
+    }
+
+    async void ThreadLoop()
+    {
+        while (isRunning_)
+        {
+            try
+            {
+                loopFunc_();
+                await Task.Delay(IntervalMillisec);
+            }
+            catch (Exception e)
+            {
+                Debug.LogError(e.Message);
+                Debug.LogError(e.StackTrace);
+            }
+        }
+    }
+
+    public override void Stop(int timeoutMilliseconds = 3000)
+    {
+        if (!isRunning_) return;
+
+        isRunning_ = false;
+
+        if (!task_.IsCompleted)
+        {
+            task_.Wait(timeoutMilliseconds);
+        }
+    }
+}
+
+}
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Uwp/Thread.cs.meta b/Assets/External/uOSC/Runtime/Core/Uwp/Thread.cs.meta
new file mode 100644
index 000000000..b9e462613
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Uwp/Thread.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 1ebe8fba61e7ca547bd6993415cdbe64
+timeCreated: 1502677461
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Uwp/Udp.cs b/Assets/External/uOSC/Runtime/Core/Uwp/Udp.cs
new file mode 100644
index 000000000..1d5322b90
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Uwp/Udp.cs
@@ -0,0 +1,98 @@
+#if NETFX_CORE
+
+using UnityEngine;
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Networking;
+using Windows.Networking.Sockets;
+
+namespace uOSC.Uwp
+{
+
+public class Udp : uOSC.Udp
+{
+    private const int BufferSize = 8192;
+
+    DatagramSocket socket_;
+    HostName sendHost;
+    string sendPort;
+
+    object lockObject_ = new object();
+
+    Queue messageQueue_ = new Queue();
+    byte[] buffer = new byte[BufferSize];
+
+    public override int messageCount
+    {
+        get { return messageQueue_.Count; }
+    }
+
+    public override bool isRunning
+    {
+        get { return socket_ != null; }
+    }
+
+    public async override void StartServer(int port)
+    {
+        try 
+        {
+            socket_ = new DatagramSocket();
+            socket_.MessageReceived += OnMessage;
+            await socket_.BindServiceNameAsync(port.ToString());
+        } 
+        catch (Exception e) 
+        {
+            Debug.LogError(e.ToString());
+        }
+    }
+
+    async void OnMessage(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
+    {
+        using (var stream = args.GetDataStream().AsStreamForRead()) 
+        {
+            var size = await stream.ReadAsync(buffer, 0, BufferSize);
+            lock (lockObject_) 
+            {
+                var data = new byte[size];
+                Array.Copy(buffer, data, size);
+                messageQueue_.Enqueue(data);
+            }
+        }
+    }
+
+    public override void StartClient(string address, int port)
+    {
+        socket_ = new DatagramSocket();
+        sendHost = new HostName(address);
+        sendPort = port.ToString();
+    }
+
+    public override void Stop()
+    {
+        socket_.Dispose();
+        socket_ = null;
+    }
+
+    public async override void Send(byte[] data, int size)
+    {
+        var stream = await socket_.GetOutputStreamAsync(sendHost, sendPort);
+        var buffer = data.AsBuffer(0, size);
+        await stream.WriteAsync(buffer);
+    }
+
+    public override byte[] Receive()
+    {
+        byte[] buffer;
+        lock (lockObject_)
+        {
+            buffer = messageQueue_.Dequeue();
+        }
+        return buffer;
+    }
+}
+
+}
+
+#endif
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Uwp/Udp.cs.meta b/Assets/External/uOSC/Runtime/Core/Uwp/Udp.cs.meta
new file mode 100644
index 000000000..cec23534c
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Uwp/Udp.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6d6388037f25e40ee88df0fbff8e3c85
+timeCreated: 1502963364
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/Core/Writer.cs b/Assets/External/uOSC/Runtime/Core/Writer.cs
new file mode 100644
index 000000000..aa0a80de8
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Writer.cs
@@ -0,0 +1,73 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace uOSC
+{
+
+public static class Writer
+{
+    private static readonly byte Zero = Convert.ToByte('\0');
+    public static readonly byte[] Zeros = { Zero, Zero, Zero, Zero };
+
+    public static void Write(MemoryStream stream, int value)
+    {
+        var byteValue = BitConverter.GetBytes(value);
+        Array.Reverse(byteValue);
+        stream.Write(byteValue, 0, byteValue.Length);
+    }
+
+    public static void Write(MemoryStream stream, Timestamp value)
+    {
+        var byteValue = BitConverter.GetBytes(value.value);
+        Array.Reverse(byteValue);
+        stream.Write(byteValue, 0, byteValue.Length);
+    }
+
+    public static void Write(MemoryStream stream, float value)
+    {
+        var byteValue = BitConverter.GetBytes(value);
+        Array.Reverse(byteValue);
+        stream.Write(byteValue, 0, byteValue.Length);
+    }
+
+    public static void Write(MemoryStream stream, string value)
+    {
+        var byteValue = Encoding.UTF8.GetBytes(value);
+        var size = byteValue.Length;
+        stream.Write(byteValue, 0, size);
+
+        var offset = Util.GetStringAlignedSize(size) - size;
+        if (offset > 0)
+        {
+            stream.Write(Zeros, 0, offset);
+        }
+    }
+
+    public static void Write(MemoryStream stream, byte[] value, int size)
+    {
+        Write(stream, size);
+        stream.Write(value, 0, size);
+
+        var offset = Util.GetBufferAlignedSize(size) - size;
+        if (offset > 0)
+        {
+            stream.Write(Zeros, 0, offset);
+        }
+    }
+
+    public static void Write(MemoryStream stream, byte[] value)
+    {
+        Write(stream, value, value.Length);
+    }
+
+    public static void Write(MemoryStream stream, MemoryStream value)
+    {
+        var byteValue = Util.GetBuffer(value);
+        var size = (int)value.Position;
+        Write(stream, size);
+        stream.Write(byteValue, 0, size);
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/Core/Writer.cs.meta b/Assets/External/uOSC/Runtime/Core/Writer.cs.meta
new file mode 100644
index 000000000..e186b1825
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/Core/Writer.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 420f29ea0e2d34447b3b091b597fbe65
+timeCreated: 1503122577
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/UniGLTF/Samples/ScreenSpace/UniGLTF.Samples.ScreenSpace.asmdef b/Assets/External/uOSC/Runtime/uOSC.Runtime.asmdef
similarity index 69%
rename from Assets/External/UniGLTF/Samples/ScreenSpace/UniGLTF.Samples.ScreenSpace.asmdef
rename to Assets/External/uOSC/Runtime/uOSC.Runtime.asmdef
index 864265c64..c99deddcc 100644
--- a/Assets/External/UniGLTF/Samples/ScreenSpace/UniGLTF.Samples.ScreenSpace.asmdef
+++ b/Assets/External/uOSC/Runtime/uOSC.Runtime.asmdef
@@ -1,8 +1,7 @@
 {
-    "name": "UniGLTF.Samples.ScreenSpace",
-    "references": [
-        "GUID:8d76e605759c3f64a957d63ef96ada7c"
-    ],
+    "name": "uOSC.Runtime",
+    "rootNamespace": "",
+    "references": [],
     "includePlatforms": [],
     "excludePlatforms": [],
     "allowUnsafeCode": false,
diff --git a/Assets/External/uOSC/Runtime/uOSC.Runtime.asmdef.meta b/Assets/External/uOSC/Runtime/uOSC.Runtime.asmdef.meta
new file mode 100644
index 000000000..42950d3a5
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/uOSC.Runtime.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e8063cf3a345f9c46b7c7c4f14d54285
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/uOscClient.cs b/Assets/External/uOSC/Runtime/uOscClient.cs
new file mode 100644
index 000000000..f56b4832e
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/uOscClient.cs
@@ -0,0 +1,153 @@
+using UnityEngine;
+using System.IO;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace uOSC
+{
+
+public class uOscClient : MonoBehaviour
+{
+    [SerializeField]
+    public string address = "127.0.0.1";
+
+    [SerializeField]
+    public int port = 3333;
+
+    [SerializeField]
+    public int maxQueueSize = 100;
+
+    [SerializeField, Tooltip("milliseconds")]
+    public float dataTransimissionInterval = 0f;
+
+#if NETFX_CORE
+    Udp udp_ = new Uwp.Udp();
+    Thread thread_ = new Uwp.Thread();
+#else
+    Udp udp_ = new DotNet.Udp();
+    Thread thread_ = new DotNet.Thread();
+#endif
+    Queue messages_ = new Queue();
+    object lockObject_ = new object();
+
+    public ClientStartEvent onClientStarted = new ClientStartEvent();
+    public ClientStopEvent onClientStopped = new ClientStopEvent();
+
+    string address_ = "";
+    int port_ = 0;
+
+    public bool isRunning
+    {
+        get { return udp_.isRunning; }
+    }
+
+    void OnEnable()
+    {
+        StartClient();
+    }
+
+    void OnDisable()
+    {
+        StopClient();
+    }
+
+    public void StartClient()
+    {
+        udp_.StartClient(address, port);
+        thread_.Start(UpdateSend);
+        address_ = address;
+        port_ = port;
+        onClientStarted.Invoke(address, port);
+    }
+
+    public void StopClient()
+    {
+        thread_.Stop();
+        udp_.Stop();
+        onClientStopped.Invoke(address, port);
+    }
+
+    void Update()
+    {
+        UpdateChangePortAndAddress();
+    }
+
+    void UpdateChangePortAndAddress()
+    {
+        if (port_ == port && address_ == address) return;
+
+        StopClient();
+        StartClient();
+    }
+
+    void UpdateSend()
+    {
+        while (messages_.Count > 0)
+        {
+            var sw = Stopwatch.StartNew();
+
+            object message;
+            lock (lockObject_)
+            {
+                message = messages_.Dequeue();
+            }
+
+            using (var stream = new MemoryStream())
+            {
+                if (message is Message)
+                {
+                    ((Message)message).Write(stream);
+                }
+                else if (message is Bundle)
+                {
+                    ((Bundle)message).Write(stream);
+                }
+                else
+                {
+                    continue;
+                }
+                udp_.Send(Util.GetBuffer(stream), (int)stream.Position);
+            }
+
+            if (dataTransimissionInterval > 0f)
+            {
+                var ticks = (long)Mathf.Round(dataTransimissionInterval / 1000f * Stopwatch.Frequency);
+                while (sw.ElapsedTicks < ticks);
+            }
+        }
+    }
+
+    void Add(object data)
+    {
+        lock (lockObject_)
+        {
+            messages_.Enqueue(data);
+
+            while (messages_.Count > maxQueueSize)
+            {
+                messages_.Dequeue();
+            }
+        }
+    }
+
+    public void Send(string address, params object[] values)
+    {
+        Send(new Message() 
+        {
+            address = address,
+            values = values
+        });
+    }
+
+    public void Send(Message message)
+    {
+        Add(message);
+    }
+
+    public void Send(Bundle bundle)
+    {
+        Add(bundle);
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/uOscClient.cs.meta b/Assets/External/uOSC/Runtime/uOscClient.cs.meta
new file mode 100644
index 000000000..6c687a666
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/uOscClient.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d36dd9fcae25042bbb815255411ff524
+timeCreated: 1502524769
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Runtime/uOscServer.cs b/Assets/External/uOSC/Runtime/uOscServer.cs
new file mode 100644
index 000000000..af20f1798
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/uOscServer.cs
@@ -0,0 +1,119 @@
+using UnityEngine;
+
+namespace uOSC
+{
+
+public class uOscServer : MonoBehaviour
+{
+    [SerializeField]
+    public int port = 3333;
+
+    [SerializeField]
+    public bool autoStart = true;
+
+#if NETFX_CORE
+    Udp udp_ = new Uwp.Udp();
+    Thread thread_ = new Uwp.Thread();
+#else
+    Udp udp_ = new DotNet.Udp();
+    Thread thread_ = new DotNet.Thread();
+#endif
+    Parser parser_ = new Parser();
+
+    public DataReceiveEvent onDataReceived = new DataReceiveEvent();
+    public ServerStartEvent onServerStarted = new ServerStartEvent();
+    public ServerStopEvent onServerStopped = new ServerStopEvent();
+
+#if UNITY_EDITOR
+    public DataReceiveEvent _onDataReceivedEditor = new DataReceiveEvent();
+#endif
+
+    int port_ = 0;
+    bool isStarted_ = false;
+
+    public bool isRunning
+    {
+        get { return udp_.isRunning; }
+    }
+
+    void Awake()
+    {
+        port_ = port;
+    }
+
+    void OnEnable()
+    {
+        if (autoStart) 
+        {
+            StartServer();
+        }
+    }
+
+    void OnDisable()
+    {
+        StopServer();
+    }
+
+    public void StartServer()
+    {
+        if (isStarted_) return;
+
+        udp_.StartServer(port);
+        thread_.Start(UpdateMessage);
+
+        isStarted_ = true;
+
+        onServerStarted.Invoke(port);
+    }
+
+    public void StopServer()
+    {
+        if (!isStarted_) return;
+
+        thread_.Stop();
+        udp_.Stop();
+
+        isStarted_ = false;
+
+        onServerStopped.Invoke(port);
+    }
+
+    void Update()
+    {
+        UpdateReceive();
+        UpdateChangePort();
+    }
+
+    void UpdateReceive()
+    {
+        while (parser_.messageCount > 0)
+        {
+            var message = parser_.Dequeue();
+            onDataReceived.Invoke(message);
+#if UNITY_EDITOR
+            _onDataReceivedEditor.Invoke(message);
+#endif
+        }
+    }
+
+    void UpdateChangePort()
+    {
+        if (port_ == port) return;
+
+        StopServer();
+        StartServer();
+        port_ = port;
+    }
+
+    void UpdateMessage()
+    {
+        while (udp_.messageCount > 0) 
+        {
+            var buf = udp_.Receive();
+            int pos = 0;
+            parser_.Parse(buf, ref pos, buf.Length);
+        }
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Runtime/uOscServer.cs.meta b/Assets/External/uOSC/Runtime/uOscServer.cs.meta
new file mode 100644
index 000000000..6d3e020c1
--- /dev/null
+++ b/Assets/External/uOSC/Runtime/uOscServer.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ed41645692348410d84991648165334c
+timeCreated: 1502262159
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/UniGLTF/Samples.meta b/Assets/External/uOSC/Samples.meta
similarity index 77%
rename from Assets/External/UniGLTF/Samples.meta
rename to Assets/External/uOSC/Samples.meta
index fd83f1e22..97663b95d 100644
--- a/Assets/External/UniGLTF/Samples.meta
+++ b/Assets/External/uOSC/Samples.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 0f315984294ae8e45a5f86d663b88855
+guid: fc647f8bdf4b1db449c15f5ed62e0322
 folderAsset: yes
 DefaultImporter:
   externalObjects: {}
diff --git a/Assets/External/uOSC/Samples/Blob.meta b/Assets/External/uOSC/Samples/Blob.meta
new file mode 100644
index 000000000..a2f5bf93b
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 825fb6fd8f25dfb49a2ede0374dbecd3
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Blob/Blob.unity b/Assets/External/uOSC/Samples/Blob/Blob.unity
new file mode 100644
index 000000000..d4922bfb3
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/Blob.unity
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f0224021babc4588839bcc3e25592ca6259e968faa2a4c84891b7d263cc6f1bf
+size 12889
diff --git a/Assets/External/uOSC/Samples/Blob/Blob.unity.meta b/Assets/External/uOSC/Samples/Blob/Blob.unity.meta
new file mode 100644
index 000000000..53369f112
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/Blob.unity.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a0ace38c66dcf44898cffb8baf34fcd2
+timeCreated: 1502680972
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Blob/ClientBlobTest.cs b/Assets/External/uOSC/Samples/Blob/ClientBlobTest.cs
new file mode 100644
index 000000000..4c22350a5
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/ClientBlobTest.cs
@@ -0,0 +1,26 @@
+using UnityEngine;
+using uOSC;
+
+[RequireComponent(typeof(uOscClient))]
+public class ClientBlobTest : MonoBehaviour
+{
+    [SerializeField]
+    Texture2D texture;
+
+    byte[] byteTexture_;
+
+    void Start()
+    {
+#if UNITY_2017
+        byteTexture_ = ImageConversion.EncodeToPNG(texture);
+#else
+        byteTexture_ = texture.EncodeToPNG();
+#endif
+    }
+
+    void Update()
+    {
+        var client = GetComponent();
+        client.Send("/uOSC/blob", byteTexture_);
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Samples/Blob/ClientBlobTest.cs.meta b/Assets/External/uOSC/Samples/Blob/ClientBlobTest.cs.meta
new file mode 100644
index 000000000..35a96774b
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/ClientBlobTest.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ab88f05f6963e427081771a4139b18fb
+timeCreated: 1502692316
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Blob/ServerBlobTest.cs b/Assets/External/uOSC/Samples/Blob/ServerBlobTest.cs
new file mode 100644
index 000000000..5cef84d35
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/ServerBlobTest.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+using uOSC;
+
+[RequireComponent(typeof(uOscServer)),
+ RequireComponent(typeof(Renderer))]
+public class ServerBlobTest : MonoBehaviour
+{
+    Texture2D texture_;
+
+    void Start()
+    {
+        var server = GetComponent();
+        server.onDataReceived.AddListener(OnDataReceived);
+
+        texture_ = new Texture2D(256, 256, TextureFormat.ARGB32, true);
+
+        var renderer = GetComponent();
+        renderer.material.mainTexture = texture_;
+    }
+
+    void OnDataReceived(Message message)
+    {
+        if (message.address == "/uOSC/blob")
+        {
+            var byteTexture = (byte[])message.values[0];
+#if UNITY_2017
+            ImageConversion.LoadImage(texture_, byteTexture, true);
+#else
+            texture_.LoadImage(byteTexture);
+#endif
+        }
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Samples/Blob/ServerBlobTest.cs.meta b/Assets/External/uOSC/Samples/Blob/ServerBlobTest.cs.meta
new file mode 100644
index 000000000..490d2b2ed
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/ServerBlobTest.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6e7b927c883904a4f83bc8d9df69ae01
+timeCreated: 1502692326
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Blob/uOSC Blob.mat b/Assets/External/uOSC/Samples/Blob/uOSC Blob.mat
new file mode 100644
index 000000000..e4943ea21
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/uOSC Blob.mat	
@@ -0,0 +1,83 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_Name: uOSC Blob
+  m_Shader: {fileID: 10750, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _AlphaTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - PixelSnap: 0
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _EnableExternalAlpha: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+    - _Flip: {r: 1, g: 1, b: 1, a: 1}
+    - _RendererColor: {r: 1, g: 1, b: 1, a: 1}
diff --git a/Assets/External/uOSC/Samples/Blob/uOSC Blob.mat.meta b/Assets/External/uOSC/Samples/Blob/uOSC Blob.mat.meta
new file mode 100644
index 000000000..67033b6bb
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/uOSC Blob.mat.meta	
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: c639012380c1447228b7456cf1f7f370
+timeCreated: 1502693721
+licenseType: Pro
+NativeFormatImporter:
+  mainObjectFileID: 2100000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Blob/uOSC Sample Texture.png b/Assets/External/uOSC/Samples/Blob/uOSC Sample Texture.png
new file mode 100644
index 000000000..97e7e0c9a
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/uOSC Sample Texture.png	
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ab5db9c383c0e8b617bc4e2ca8e528370529d51f19fff0fbcb7f9cef240ae203
+size 6150
diff --git a/Assets/External/uOSC/Samples/Blob/uOSC Sample Texture.png.meta b/Assets/External/uOSC/Samples/Blob/uOSC Sample Texture.png.meta
new file mode 100644
index 000000000..2117b1f03
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Blob/uOSC Sample Texture.png.meta	
@@ -0,0 +1,82 @@
+fileFormatVersion: 2
+guid: 178fee4e4940742c3ade6bb820372b83
+timeCreated: 1502693042
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 4
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 1
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 0
+    aniso: -1
+    mipBias: -1
+    wrapU: 1
+    wrapV: 1
+    wrapW: 1
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaUsage: 1
+  alphaIsTransparency: 1
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  platformSettings:
+  - buildTarget: DefaultTexturePlatform
+    maxTextureSize: 256
+    textureFormat: -1
+    textureCompression: 0
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+  - buildTarget: Standalone
+    maxTextureSize: 256
+    textureFormat: -1
+    textureCompression: 0
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Bundle.meta b/Assets/External/uOSC/Samples/Bundle.meta
new file mode 100644
index 000000000..607375377
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Bundle.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e32809809d3b08a48af82e6b75fe69a9
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Bundle/Bundle.unity b/Assets/External/uOSC/Samples/Bundle/Bundle.unity
new file mode 100644
index 000000000..b63846b4b
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Bundle/Bundle.unity
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c474930ef84622adb6c0a276c67c18568917fedc4435bf31e65bd6efb54f65ec
+size 12155
diff --git a/Assets/External/uOSC/Samples/Bundle/Bundle.unity.meta b/Assets/External/uOSC/Samples/Bundle/Bundle.unity.meta
new file mode 100644
index 000000000..a25d8907a
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Bundle/Bundle.unity.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 11535c07a2b95472399dc7f854442c78
+timeCreated: 1503124696
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Bundle/ClientBundleTest.cs b/Assets/External/uOSC/Samples/Bundle/ClientBundleTest.cs
new file mode 100644
index 000000000..d68ebcb22
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Bundle/ClientBundleTest.cs
@@ -0,0 +1,30 @@
+using UnityEngine;
+using uOSC;
+
+[RequireComponent(typeof(uOscClient))]
+public class ClientBundleTest : MonoBehaviour
+{
+    void Update()
+    {
+        var client = GetComponent();
+
+        var bundle1 = new Bundle(Timestamp.Now);
+        bundle1.Add(new Message("/uOSC/root/bundle1/message1", 123, "hoge", new byte[] { 1, 2, 3, 4 }));
+        bundle1.Add(new Message("/uOSC/root/bundle1/message2", 1.2345f));
+        bundle1.Add(new Message("/uOSC/root/bundle1/message3", "abcdefghijklmn"));
+
+        var date2 = System.DateTime.UtcNow.AddSeconds(10);
+        var timestamp2 = Timestamp.CreateFromDateTime(date2);
+        var bundle2 = new Bundle(timestamp2);
+        bundle2.Add(new Message("/uOSC/root/bundle2/message1", 234, "fuga", new byte[] { 2, 3, 4 }));
+        bundle2.Add(new Message("/uOSC/root/bundle2/message2", 2.3456f));
+        bundle2.Add(new Message("/uOSC/root/bundle2/message3", "opqrstuvwxyz"));
+
+        var root = new Bundle(Timestamp.Immediate);
+        root.Add(bundle1);
+        root.Add(bundle2);
+        root.Add(new Message("/uOSC/root/message2"));
+
+        client.Send(root);
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Samples/Bundle/ClientBundleTest.cs.meta b/Assets/External/uOSC/Samples/Bundle/ClientBundleTest.cs.meta
new file mode 100644
index 000000000..8686d0d85
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Bundle/ClientBundleTest.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: edd396297d7304d15a06e6e5508d579c
+timeCreated: 1503124881
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Client to Server.meta b/Assets/External/uOSC/Samples/Client to Server.meta
new file mode 100644
index 000000000..4ed272618
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server.meta	
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b36ef58df8266d94c90e7bf988810ac1
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Client to Server/Client to Server.unity b/Assets/External/uOSC/Samples/Client to Server/Client to Server.unity
new file mode 100644
index 000000000..7c45042c1
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/Client to Server.unity	
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c6b5b8064fbe4480e90bc6cc151e5334e76056990ac54628bfbdf5042eaca957
+size 13875
diff --git a/Assets/External/uOSC/Samples/Client to Server/Client to Server.unity.meta b/Assets/External/uOSC/Samples/Client to Server/Client to Server.unity.meta
new file mode 100644
index 000000000..5a19ba558
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/Client to Server.unity.meta	
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e991686654be84140ac84795a6d4a09d
+timeCreated: 1502680504
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Client to Server/Client.unity b/Assets/External/uOSC/Samples/Client to Server/Client.unity
new file mode 100644
index 000000000..db455c738
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/Client.unity	
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ec0878f0175ee0354113963edcd5f580d0ec867a6add6de16c48e03552da5d5d
+size 10774
diff --git a/Assets/External/uOSC/Samples/Client to Server/Client.unity.meta b/Assets/External/uOSC/Samples/Client to Server/Client.unity.meta
new file mode 100644
index 000000000..ea99ab4ab
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/Client.unity.meta	
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4050a1969537d4d0c8a7c07807e1c44c
+timeCreated: 1502537341
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Client to Server/ClientTest.cs b/Assets/External/uOSC/Samples/Client to Server/ClientTest.cs
new file mode 100644
index 000000000..bf2ae7d34
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/ClientTest.cs	
@@ -0,0 +1,22 @@
+using UnityEngine;
+using uOSC;
+
+[RequireComponent(typeof(uOscClient))]
+public class ClientTest : MonoBehaviour
+{
+    void Update()
+    {
+        var client = GetComponent();
+        client.Send("/uOSC/test", 10, "hoge", "hogehoge", 1.234f, 123f, true, false);
+    }
+
+    public void OnClientStarted(string address, int port)
+    {
+        Debug.Log($"Start Client (address: {address}, port: {port})");
+    }
+
+    public void OnClientStopped(string address, int port)
+    {
+        Debug.Log($"Stop Client (address: {address}, port: {port})");
+    }
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Samples/Client to Server/ClientTest.cs.meta b/Assets/External/uOSC/Samples/Client to Server/ClientTest.cs.meta
new file mode 100644
index 000000000..709b6b556
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/ClientTest.cs.meta	
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9e0988d2b75da477ebe30db7123a03ca
+timeCreated: 1502619725
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Client to Server/Server.unity b/Assets/External/uOSC/Samples/Client to Server/Server.unity
new file mode 100644
index 000000000..4389e6bfa
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/Server.unity	
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:df1bd352fdf0cd4f53a278aa685c8e8b226668c68ae95cd0aac28474535b96ee
+size 11253
diff --git a/Assets/External/uOSC/Samples/Client to Server/Server.unity.meta b/Assets/External/uOSC/Samples/Client to Server/Server.unity.meta
new file mode 100644
index 000000000..a2762f7e5
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/Server.unity.meta	
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 664592c5d4b0c441ea8b1c68adb4de2f
+timeCreated: 1502638194
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/Samples/Client to Server/ServerTest.cs b/Assets/External/uOSC/Samples/Client to Server/ServerTest.cs
new file mode 100644
index 000000000..fc1b7e730
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/ServerTest.cs	
@@ -0,0 +1,36 @@
+using UnityEngine;
+
+namespace uOSC.Samples
+{
+
+public class ServerTest : MonoBehaviour
+{
+    public void OnDataReceived(Message message)
+    {
+        // address
+        var msg = message.address + ": ";
+
+        // timestamp
+        msg += "(" + message.timestamp.ToLocalTime() + ") ";
+
+        // values
+        foreach (var value in message.values)
+        {
+            msg += value.GetString() + " ";
+        }
+
+        Debug.Log(msg);
+    }
+
+    public void OnServerStarted(int port)
+    {
+        Debug.Log($"Start Server (port: {port})");
+    }
+
+    public void OnServerStopped(int port)
+    {
+        Debug.Log($"Stop Server (port: {port})");
+    }
+}
+
+}
\ No newline at end of file
diff --git a/Assets/External/uOSC/Samples/Client to Server/ServerTest.cs.meta b/Assets/External/uOSC/Samples/Client to Server/ServerTest.cs.meta
new file mode 100644
index 000000000..9c27e4ca3
--- /dev/null
+++ b/Assets/External/uOSC/Samples/Client to Server/ServerTest.cs.meta	
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2a7ac9cb3a9944ac584257dc6ef622f5
+timeCreated: 1502638868
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/External/uOSC/package.json b/Assets/External/uOSC/package.json
new file mode 100644
index 000000000..095fe5435
--- /dev/null
+++ b/Assets/External/uOSC/package.json
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c290209a710efcbf97cec8b5fa2bc22c1a2e757023937b55a264df6cd2dac173
+size 1005
diff --git a/Assets/External/uOSC/package.json.meta b/Assets/External/uOSC/package.json.meta
new file mode 100644
index 000000000..be63a97f4
--- /dev/null
+++ b/Assets/External/uOSC/package.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 09bee86b68bb87e479ac797ade39f46f
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: