static void OnExportClicked(GameObject root, VRMMetaObject meta, VRMExportSettings settings, VRMExportMeshes meshes) { string directory; if (string.IsNullOrEmpty(m_lastExportDir)) { directory = Directory.GetParent(Application.dataPath).ToString(); } else { directory = m_lastExportDir; } // save dialog var path = EditorUtility.SaveFilePanel( "Save vrm", directory, root.name + EXTENSION, EXTENSION.Substring(1)); if (string.IsNullOrEmpty(path)) { return; } m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); // export VRMEditorExporter.Export(path, root, meta, settings, meshes.Meshes); }
public void SetRoot(GameObject ExportRoot, VRMExportSettings settings) { m_validations.Clear(); Meshes.Clear(); if (ExportRoot == null) { return; } var clips = new List <BlendShapeClip>(); var proxy = ExportRoot.GetComponent <VRMBlendShapeProxy>(); if (proxy != null) { // Export サイズ の 計算 if (proxy.BlendShapeAvatar != null) { clips.AddRange(proxy.BlendShapeAvatar.Clips); } } foreach (var renderer in ExportRoot.GetComponentsInChildren <Renderer>(true)) { if (TryGetMeshInfo(ExportRoot, renderer, clips, settings, out UniGLTF.MeshExportInfo info)) { Meshes.Add(info); } } }
void OnDisable() { ExportRoot = null; // Debug.Log("OnDisable"); Selection.selectionChanged -= OnWizardUpdate; Undo.willFlushUndoRecord -= OnWizardUpdate; // m_metaEditor UnityEditor.Editor.DestroyImmediate(m_metaEditor); m_metaEditor = null; // m_settingsInspector UnityEditor.Editor.DestroyImmediate(m_settingsInspector); m_settingsInspector = null; // m_meshesInspector UnityEditor.Editor.DestroyImmediate(m_meshesInspector); m_meshesInspector = null; // Meta Meta = null; ScriptableObject.DestroyImmediate(m_tmpMeta); m_tmpMeta = null; // m_settings ScriptableObject.DestroyImmediate(m_settings); m_settings = null; // m_meshes ScriptableObject.DestroyImmediate(m_meshes); m_meshes = null; }
void OnDisable() { m_state.Dispose(); // Debug.Log("OnDisable"); Selection.selectionChanged -= Repaint; Undo.willFlushUndoRecord -= Repaint; // m_metaEditor UnityEditor.Editor.DestroyImmediate(m_metaEditor); m_metaEditor = null; // m_settingsInspector UnityEditor.Editor.DestroyImmediate(m_settingsInspector); m_settingsInspector = null; // m_meshesInspector UnityEditor.Editor.DestroyImmediate(m_meshesInspector); m_meshesInspector = null; // Meta Meta = null; ScriptableObject.DestroyImmediate(m_tmpMeta); m_tmpMeta = null; // m_settings ScriptableObject.DestroyImmediate(m_settings); m_settings = null; // m_meshes ScriptableObject.DestroyImmediate(m_meshes); m_meshes = null; }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="settings"></param> /// <param name="destroy">作業が終わったらDestoryするべき一時オブジェクト</param> static void Export(string path, VRMExportSettings settings, List <GameObject> destroy) { var target = settings.Source; // 常にコピーする。シーンを変化させない target = GameObject.Instantiate(target); destroy.Add(target); // 正規化 if (settings.PoseFreeze) { // BoneNormalizer.Execute は Copy を作って正規化する。UNDO無用 target = BoneNormalizer.Execute(target, settings.ForceTPose, false); destroy.Add(target); } // 元のBlendShapeClipに変更を加えないように複製 var proxy = target.GetComponent <VRMBlendShapeProxy>(); var copyBlendShapeAvatar = CopyBlendShapeAvatar(proxy.BlendShapeAvatar, settings.ReduceBlendshapeClip); proxy.BlendShapeAvatar = copyBlendShapeAvatar; // BlendShape削減 if (settings.ReduceBlendshape) { foreach (SkinnedMeshRenderer smr in target.GetComponentsInChildren <SkinnedMeshRenderer>()) { // 未使用のBlendShapeを間引く ReplaceMesh(target, smr, copyBlendShapeAvatar); } } // 出力 { var sw = System.Diagnostics.Stopwatch.StartNew(); var vrm = VRMExporter.Export(target, new VRMExporterConfiguration { UseSparseAccessorForBlendShape = settings.UseSparseAccessor, ExportOnlyBlendShapePosition = settings.OnlyBlendshapePosition, RemoveVertexColor = settings.RemoveVertexColor }); vrm.extensions.VRM.meta.title = settings.Title; vrm.extensions.VRM.meta.version = settings.Version; vrm.extensions.VRM.meta.author = settings.Author; vrm.extensions.VRM.meta.contactInformation = settings.ContactInformation; vrm.extensions.VRM.meta.reference = settings.Reference; var bytes = vrm.ToGlbBytes(settings.UseExperimentalExporter ? SerializerTypes.Generated : SerializerTypes.UniJSON); File.WriteAllBytes(path, bytes); Debug.LogFormat("Export elapsed {0}", sw.Elapsed); } if (path.StartsWithUnityAssetPath()) { // 出力ファイルのインポートを発動 AssetDatabase.ImportAsset(path.ToUnityRelativePath()); } }
private static void ExportFromMenu() { var go = Selection.activeObject as GameObject; var normalized = VRM.BoneNormalizer.Execute(go, true); VRMExportSettings.CopyVRMComponents(go, normalized.Root, normalized.BoneMap); Selection.activeGameObject = normalized.Root; Undo.RegisterCreatedObjectUndo(normalized.Root, "normalize"); }
void OnEnable() { // Debug.Log("OnEnable"); Undo.willFlushUndoRecord += OnWizardUpdate; Selection.selectionChanged += OnWizardUpdate; m_tmpMeta = ScriptableObject.CreateInstance <VRMMetaObject>(); m_settings = ScriptableObject.CreateInstance <VRMExportSettings>(); m_settingsInspector = Editor.CreateEditor(m_settings); m_meshes = ScriptableObject.CreateInstance <VRMExportMeshes>(); m_meshesInspector = Editor.CreateEditor(m_meshes); }
private static void ExportFromMenu() { var go = Selection.activeObject as GameObject; GameObject normalizedRoot = null; using (new VRMExportSettings.RecordDisposer(go.transform.Traverse().ToArray(), "before normalize")) { var normalized = BoneNormalizer.Execute(go, true, false); VRMExportSettings.CopyVRMComponents(go, normalized.Root, normalized.BoneMap); normalizedRoot = normalized.Root; } Selection.activeGameObject = normalizedRoot; }
public VRMBlendShapeExportFilter(GameObject exportRoot, VRMExportSettings settings) { VRMExportSettings = settings; Clips = new List <BlendShapeClip>(); if (exportRoot != null) { var proxy = exportRoot.GetComponent <VRMBlendShapeProxy>(); if (proxy != null) { if (proxy.BlendShapeAvatar != null) { Clips.AddRange(proxy.BlendShapeAvatar.Clips); } } } }
/// <summary> /// Editor向けのエクスポート処理 /// </summary> /// <param name="path">出力先</param> /// <param name="settings">エクスポート設定</param> public static byte[] Export(GameObject exportRoot, VRMMetaObject meta, VRMExportSettings settings) { List <GameObject> destroy = new List <GameObject>(); try { return(Export(exportRoot, meta, settings, destroy)); } finally { foreach (var x in destroy) { Debug.LogFormat("destroy: {0}", x.name); GameObject.DestroyImmediate(x); } } }
/// <summary> /// Editor向けのエクスポート処理 /// </summary> /// <param name="path">出力先</param> /// <param name="settings">エクスポート設定</param> public static void Export(string path, GameObject exportRoot, VRMExportSettings settings) { List <GameObject> destroy = new List <GameObject>(); try { Export(path, exportRoot, settings, destroy); } finally { foreach (var x in destroy) { Debug.LogFormat("destroy: {0}", x.name); GameObject.DestroyImmediate(x); } } }
void OnEnable() { // Debug.Log("OnEnable"); Undo.willFlushUndoRecord += Repaint; Selection.selectionChanged += Repaint; m_tmpMeta = ScriptableObject.CreateInstance <VRMMetaObject>(); m_settings = ScriptableObject.CreateInstance <VRMExportSettings>(); m_settingsInspector = Editor.CreateEditor(m_settings); m_meshes = ScriptableObject.CreateInstance <VRMExportMeshes>(); m_meshesInspector = Editor.CreateEditor(m_meshes); m_state = new MeshUtility.ExporterDialogState(); m_state.ExportRootChanged += (root) => { // update meta if (root == null) { Meta = null; } else { var meta = root.GetComponent <VRMMeta>(); if (meta != null) { Meta = meta.Meta; } else { Meta = null; } // default setting m_settings.PoseFreeze = MeshUtility.Validators.HumanoidValidator.HasRotationOrScale(root) || m_meshes.Meshes.Any(x => x.ExportBlendShapeCount > 0 && !x.HasSkinning) ; } Repaint(); }; m_state.ExportRoot = Selection.activeObject as GameObject; }
public void SetRoot(GameObject ExportRoot, VRMExportSettings settings) { VRMExportSettings = settings; Clips = new List <BlendShapeClip>(); if (ExportRoot != null) { var proxy = ExportRoot.GetComponent <VRMBlendShapeProxy>(); if (proxy != null) { if (proxy.BlendShapeAvatar != null) { Clips.AddRange(proxy.BlendShapeAvatar.Clips); } } } SetRoot(ExportRoot, settings.MeshExportSettings); }
void OnEnable() { // Debug.Log("OnEnable"); Undo.willFlushUndoRecord += OnWizardUpdate; Selection.selectionChanged += OnWizardUpdate; m_tmpMeta = ScriptableObject.CreateInstance <VRMMetaObject>(); if (m_settings == null) { m_settings = ScriptableObject.CreateInstance <VRMExportSettings>(); } if (m_Inspector == null) { m_Inspector = Editor.CreateEditor(m_settings); } m_lang = EnumUtil.TryParseOrDefault <VRMExporterWizardMessages.Languages>(EditorPrefs.GetString(LANG_KEY, default(VRMExporterWizardMessages.Languages).ToString())); }
void OnEnable() { // Debug.Log("OnEnable"); Undo.willFlushUndoRecord += OnWizardUpdate; Selection.selectionChanged += OnWizardUpdate; m_tmpMeta = ScriptableObject.CreateInstance <VRMMetaObject>(); if (m_settings == null) { m_settings = ScriptableObject.CreateInstance <VRMExportSettings>(); } if (m_Inspector == null) { m_Inspector = Editor.CreateEditor(m_settings); } M17N.Getter.OnGuiSelectLang(); }
static int CalcMeshSize(string relativePath, Mesh m, VRMExportSettings m_settings, List <BlendShapeClip> clips) { int size = 0; // vertices size += m.vertexCount * 4 * 3; // vector3 if (m.normals != null) { size += m.vertexCount * 4 * 3; } if (m.uv != null) { size += m.vertexCount * 4 * 2; } if (m.colors != null) { size += m.vertexCount * 4 * 4; } // indices size += m.triangles.Length * 4; // int ? // blendshapes for (var i = 0; i < m.blendShapeCount; ++i) { // var name = m.GetBlendShapeName(i); if (m_settings.ReduceBlendshape) { if (!ClipsContainsName(clips, m_settings.ReduceBlendshapeClip, new BlendShapeBinding { Index = i, RelativePath = relativePath, })) { // skip continue; } } size += m.vertexCount * 4 * (3 + 3); } return(size); }
protected override void Clear() { // m_metaEditor UnityEditor.Editor.DestroyImmediate(m_metaEditor); m_metaEditor = null; // m_settingsInspector UnityEditor.Editor.DestroyImmediate(m_settingsInspector); m_settingsInspector = null; // m_meshesInspector UnityEditor.Editor.DestroyImmediate(m_meshesInspector); m_meshesInspector = null; // Meta Meta = null; ScriptableObject.DestroyImmediate(m_tmpMeta); m_tmpMeta = null; // m_settings ScriptableObject.DestroyImmediate(m_settings); m_settings = null; // m_meshes ScriptableObject.DestroyImmediate(m_meshes); m_meshes = null; }
/// <summary> /// エクスポート可能か検証する。 /// </summary> /// <returns></returns> public void Validate(GameObject ExportRoot, VRMExportSettings m_settings, VRMMetaObject meta) { m_validations.Clear(); if (ExportRoot == null) { return; } var proxy = ExportRoot.GetComponent <VRMBlendShapeProxy>(); m_validations.AddRange(_Validate(ExportRoot, m_settings)); m_validations.AddRange(VRMSpringBoneValidator.Validate(ExportRoot)); var firstPerson = ExportRoot.GetComponent <VRMFirstPerson>(); if (firstPerson != null) { m_validations.AddRange(firstPerson.Validate()); } if (proxy != null) { m_validations.AddRange(proxy.Validate()); // Export サイズ の 計算 var clips = new List <BlendShapeClip>(); if (proxy.BlendShapeAvatar != null) { clips.AddRange(proxy.BlendShapeAvatar.Clips); } ExpectedByteSize = 0; foreach (var renderer in ExportRoot.GetComponentsInChildren <Renderer>()) { var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, ExportRoot.transform); var mesh = GetMesh(renderer); ExpectedByteSize += CalcMeshSize(relativePath, mesh, m_settings, clips); } } MetaHasError = meta.Validate().Any(); }
/// <summary> /// エクスポート可能か検証する。 /// </summary> /// <returns></returns> public void Validate(GameObject ExportRoot, VRMExportSettings m_settings, VRMMetaObject meta) { m_validations.Clear(); if (ExportRoot == null) { return; } var proxy = ExportRoot.GetComponent <VRMBlendShapeProxy>(); m_validations.AddRange(_Validate(ExportRoot, m_settings)); m_validations.AddRange(VRMSpringBoneValidator.Validate(ExportRoot)); var firstPerson = ExportRoot.GetComponent <VRMFirstPerson>(); if (firstPerson != null) { m_validations.AddRange(firstPerson.Validate()); } if (proxy != null) { m_validations.AddRange(proxy.Validate()); } MetaHasError = meta.Validate().Any(); }
protected override void Initialize() { m_tmpMeta = ScriptableObject.CreateInstance <VRMMetaObject>(); m_settings = ScriptableObject.CreateInstance <VRMExportSettings>(); m_settingsInspector = Editor.CreateEditor(m_settings); m_meshes = ScriptableObject.CreateInstance <VRMExportMeshes>(); m_meshesInspector = Editor.CreateEditor(m_meshes); State.ExportRootChanged += (root) => { // update meta if (root == null) { Meta = null; } else { var meta = root.GetComponent <VRMMeta>(); if (meta != null) { Meta = meta.Meta; } else { Meta = null; } // default setting m_settings.PoseFreeze = HumanoidValidator.HasRotationOrScale(root) || m_meshes.Meshes.Any(x => x.ExportBlendShapeCount > 0 && !x.HasSkinning) ; } }; }
/// <summary> /// Editor向けのエクスポート処理 /// </summary> /// <param name="path">出力先</param> /// <param name="settings">エクスポート設定</param> public static void Export(string path, GameObject exportRoot, VRMMetaObject meta, VRMExportSettings settings, IReadOnlyList <MeshUtility.MeshExportInfo> info) { List <GameObject> destroy = new List <GameObject>(); try { Export(path, exportRoot, meta, settings, info, destroy); } finally { foreach (var x in destroy) { Debug.LogFormat("destroy: {0}", x.name); GameObject.DestroyImmediate(x); } } }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="settings"></param> /// <param name="destroy">作業が終わったらDestoryするべき一時オブジェクト</param> static void Export(string path, GameObject exportRoot, VRMMetaObject meta, VRMExportSettings settings, IReadOnlyList <MeshUtility.MeshExportInfo> info, List <GameObject> destroy) { var target = exportRoot; // 常にコピーする。シーンを変化させない target = GameObject.Instantiate(target); destroy.Add(target); var metaBehaviour = target.GetComponent <VRMMeta>(); if (metaBehaviour == null) { metaBehaviour = target.AddComponent <VRMMeta>(); metaBehaviour.Meta = meta; } if (metaBehaviour.Meta == null) { // 来ないはず throw new Exception("meta required"); } { // copy元 var animator = exportRoot.GetComponent <Animator>(); var beforeTransforms = exportRoot.GetComponentsInChildren <Transform>(); // copy先 var afterTransforms = target.GetComponentsInChildren <Transform>(); // copy先のhumanoidBoneのリストを得る var bones = (HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones)); var humanTransforms = bones .Where(x => x != HumanBodyBones.LastBone) .Select(x => animator.GetBoneTransform(x)) .Where(x => x != null) .Select(x => afterTransforms[Array.IndexOf(beforeTransforms, x)]) // copy 先を得る .ToArray(); var nameCount = target.GetComponentsInChildren <Transform>() .GroupBy(x => x.name) .ToDictionary(x => x.Key, x => x.Count()); foreach (var t in target.GetComponentsInChildren <Transform>()) { if (humanTransforms.Contains(t)) { // keep original name continue; } if (nameCount[t.name] > 1) { // 重複するボーン名をリネームする ForceUniqueName(t, nameCount); } } } // 正規化 if (settings.PoseFreeze) { // BoneNormalizer.Execute は Copy を作って正規化する。UNDO無用 target = VRMBoneNormalizer.Execute(target, settings.ForceTPose, false); destroy.Add(target); } // 元のBlendShapeClipに変更を加えないように複製 var proxy = target.GetComponent <VRMBlendShapeProxy>(); if (proxy != null) { var copyBlendShapeAvatar = CopyBlendShapeAvatar(proxy.BlendShapeAvatar, settings.ReduceBlendshapeClip); proxy.BlendShapeAvatar = copyBlendShapeAvatar; // BlendShape削減 if (settings.ReduceBlendshape) { foreach (SkinnedMeshRenderer smr in target.GetComponentsInChildren <SkinnedMeshRenderer>()) { // 未使用のBlendShapeを間引く ReplaceMesh(target, smr, copyBlendShapeAvatar); } } } // 出力 var sw = System.Diagnostics.Stopwatch.StartNew(); var gltf = new UniGLTF.glTF(); using (var exporter = new VRMExporter(gltf)) { exporter.Prepare(target); exporter.Export(settings.MeshExportSettings); } var bytes = gltf.ToGlbBytes(); File.WriteAllBytes(path, bytes); Debug.LogFormat("Export elapsed {0}", sw.Elapsed); if (path.StartsWithUnityAssetPath()) { // 出力ファイルのインポートを発動 AssetDatabase.ImportAsset(path.ToUnityRelativePath()); } }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="settings"></param> /// <param name="destroy">作業が終わったらDestoryするべき一時オブジェクト</param> static byte[] Export(GameObject exportRoot, VRMMetaObject meta, VRMExportSettings settings, List <GameObject> destroy) { var target = exportRoot; // 常にコピーする。シーンを変化させない target = GameObject.Instantiate(target); destroy.Add(target); var metaBehaviour = target.GetComponent <VRMMeta>(); if (metaBehaviour == null) { metaBehaviour = target.AddComponent <VRMMeta>(); metaBehaviour.Meta = meta; } if (metaBehaviour.Meta == null) { // 来ないはず throw new Exception("meta required"); } { // copy元 var animator = exportRoot.GetComponent <Animator>(); var beforeTransforms = exportRoot.GetComponentsInChildren <Transform>(); // copy先 var afterTransforms = target.GetComponentsInChildren <Transform>(); // copy先のhumanoidBoneのリストを得る var bones = (HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones)); var humanTransforms = bones .Where(x => x != HumanBodyBones.LastBone) .Select(x => animator.GetBoneTransform(x)) .Where(x => x != null) .Select(x => afterTransforms[Array.IndexOf(beforeTransforms, x)]) // copy 先を得る .ToArray(); var nameCount = target.GetComponentsInChildren <Transform>() .GroupBy(x => x.name) .ToDictionary(x => x.Key, x => x.Count()); foreach (var t in target.GetComponentsInChildren <Transform>()) { if (humanTransforms.Contains(t)) { // keep original name continue; } if (nameCount[t.name] > 1) { // 重複するボーン名をリネームする ForceUniqueName(t, nameCount); } } } // 正規化 if (settings.PoseFreeze) { // BoneNormalizer.Execute は Copy を作って正規化する。UNDO無用 target = VRMBoneNormalizer.Execute(target, settings.ForceTPose); destroy.Add(target); } var fp = target.GetComponent <VRMFirstPerson>(); // 元のBlendShapeClipに変更を加えないように複製 var proxy = target.GetComponent <VRMBlendShapeProxy>(); if (proxy != null) { var copyBlendShapeAvatar = CopyBlendShapeAvatar(proxy.BlendShapeAvatar, settings.ReduceBlendshapeClip); proxy.BlendShapeAvatar = copyBlendShapeAvatar; // BlendShape削減 if (settings.ReduceBlendshape) { foreach (SkinnedMeshRenderer smr in target.GetComponentsInChildren <SkinnedMeshRenderer>()) { // 未使用のBlendShapeを間引く ReplaceMesh(target, smr, copyBlendShapeAvatar); } } } // 出力 var sw = System.Diagnostics.Stopwatch.StartNew(); var data = new UniGLTF.ExportingGltfData(); var gltfExportSettings = settings.GltfExportSettings; using (var exporter = new VRMExporter(data, gltfExportSettings, settings.KeepAnimation ? new EditorAnimationExporter() : null)) { exporter.Prepare(target); exporter.Export(new EditorTextureSerializer()); } var bytes = data.ToGlbBytes(); Debug.LogFormat("Export elapsed {0}", sw.Elapsed); return(bytes); }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="settings"></param> /// <param name="destroy">作業が終わったらDestoryするべき一時オブジェクト</param> static void Export(string path, GameObject exportRoot, VRMExportSettings settings, List <GameObject> destroy) { var target = exportRoot; // 常にコピーする。シーンを変化させない target = GameObject.Instantiate(target); destroy.Add(target); { // copy元 var animator = exportRoot.GetComponent <Animator>(); var beforeTransforms = exportRoot.GetComponentsInChildren <Transform>(); // copy先 var afterTransforms = target.GetComponentsInChildren <Transform>(); // copy先のhumanoidBoneのリストを得る var bones = (HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones)); var humanTransforms = bones .Where(x => x != HumanBodyBones.LastBone) .Select(x => animator.GetBoneTransform(x)) .Where(x => x != null) .Select(x => afterTransforms[Array.IndexOf(beforeTransforms, x)]) // copy 先を得る .ToArray(); var nameCount = target.GetComponentsInChildren <Transform>() .GroupBy(x => x.name) .ToDictionary(x => x.Key, x => x.Count()); foreach (var t in target.GetComponentsInChildren <Transform>()) { if (humanTransforms.Contains(t)) { // keep original name continue; } if (nameCount[t.name] > 1) { // 重複するボーン名をリネームする ForceUniqueName(t, nameCount); } } } // 正規化 if (settings.PoseFreeze) { // BoneNormalizer.Execute は Copy を作って正規化する。UNDO無用 target = VRMBoneNormalizer.Execute(target, settings.ForceTPose, false); destroy.Add(target); } // 元のBlendShapeClipに変更を加えないように複製 var proxy = target.GetComponent <VRMBlendShapeProxy>(); if (proxy != null) { var copyBlendShapeAvatar = CopyBlendShapeAvatar(proxy.BlendShapeAvatar, settings.ReduceBlendshapeClip); proxy.BlendShapeAvatar = copyBlendShapeAvatar; // BlendShape削減 if (settings.ReduceBlendshape) { foreach (SkinnedMeshRenderer smr in target.GetComponentsInChildren <SkinnedMeshRenderer>()) { // 未使用のBlendShapeを間引く ReplaceMesh(target, smr, copyBlendShapeAvatar); } } } // 出力 { var sw = System.Diagnostics.Stopwatch.StartNew(); var vrm = VRMExporter.Export(target, new VRMExporterConfiguration { UseSparseAccessorForBlendShape = settings.UseSparseAccessor, ExportOnlyBlendShapePosition = settings.OnlyBlendshapePosition, RemoveVertexColor = settings.RemoveVertexColor }); // vrm.extensions.VRM.meta.title = settings.Title; // vrm.extensions.VRM.meta.version = settings.Version; // vrm.extensions.VRM.meta.author = settings.Author; // vrm.extensions.VRM.meta.contactInformation = settings.ContactInformation; // vrm.extensions.VRM.meta.reference = settings.Reference; var bytes = vrm.ToGlbBytes(settings.UseExperimentalExporter ? SerializerTypes.Generated : SerializerTypes.UniJSON); File.WriteAllBytes(path, bytes); Debug.LogFormat("Export elapsed {0}", sw.Elapsed); } if (path.StartsWithUnityAssetPath()) { // 出力ファイルのインポートを発動 AssetDatabase.ImportAsset(path.ToUnityRelativePath()); } }
public void DetectFileNameLength(string fileName, bool isIllegal) { var result = VRMExportSettings.IsFileNameLengthTooLong(fileName); Assert.AreEqual(result, isIllegal); }
/// <summary> /// ExportDialogを表示する前に確認する。 /// </summary> /// <param name="ExportRoot"></param> /// <param name="m_settings"></param> /// <returns></returns> public bool RootAndHumanoidCheck(GameObject ExportRoot, VRMExportSettings m_settings, IReadOnlyList <UniGLTF.MeshExportInfo> info) { // // root // if (ExportRoot == null) { Validation.Error(Msg(VRMExporterWizardMessages.ROOT_EXISTS)).DrawGUI(); return(false); } if (ExportRoot.transform.parent != null) { Validation.Error(Msg(VRMExporterWizardMessages.NO_PARENT)).DrawGUI(); return(false); } var renderers = ExportRoot.GetComponentsInChildren <Renderer>(); if (renderers.All(x => !x.EnableForExport())) { Validation.Error(Msg(VRMExporterWizardMessages.NO_ACTIVE_MESH)).DrawGUI(); return(false); } if (HasRotationOrScale(ExportRoot) || info.Any(x => x.ExportBlendShapeCount > 0 && !x.HasSkinning)) { // 正規化必用 if (m_settings.PoseFreeze) { // する EditorGUILayout.HelpBox("PoseFreeze checked. OK", MessageType.Info); } else { // しない Validation.Warning(Msg(VRMExporterWizardMessages.ROTATION_OR_SCALEING_INCLUDED_IN_NODE)).DrawGUI(); } } else { // 不要 if (m_settings.PoseFreeze) { // する Validation.Warning(Msg(VRMExporterWizardMessages.IS_POSE_FREEZE_DONE)).DrawGUI(); } else { // しない EditorGUILayout.HelpBox("Root OK", MessageType.Info); } } // // animator // var animator = ExportRoot.GetComponent <Animator>(); if (animator == null) { Validation.Error(Msg(VRMExporterWizardMessages.NO_ANIMATOR)).DrawGUI(); return(false); } var avatar = animator.avatar; if (avatar == null) { Validation.Error(Msg(VRMExporterWizardMessages.NO_AVATAR_IN_ANIMATOR)).DrawGUI(); return(false); } if (!avatar.isValid) { Validation.Error(Msg(VRMExporterWizardMessages.AVATAR_IS_NOT_VALID)).DrawGUI(); return(false); } if (!avatar.isHuman) { Validation.Error(Msg(VRMExporterWizardMessages.AVATAR_IS_NOT_HUMANOID)).DrawGUI(); return(false); } { var l = animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg); var r = animator.GetBoneTransform(HumanBodyBones.RightUpperLeg); var f = GetForward(l, r); if (Vector3.Dot(f, Vector3.forward) < 0.8f) { Validation.Error(Msg(VRMExporterWizardMessages.FACE_Z_POSITIVE_DIRECTION)).DrawGUI(); return(false); } } var jaw = animator.GetBoneTransform(HumanBodyBones.Jaw); if (jaw != null) { Validation.Warning(Msg(VRMExporterWizardMessages.JAW_BONE_IS_INCLUDED)).DrawGUI(); } else { EditorGUILayout.HelpBox("Animator OK", MessageType.Info); } return(true); }
IEnumerable <Validation> _Validate(GameObject ExportRoot, VRMExportSettings m_settings) { if (ExportRoot == null) { yield break; } if (DuplicateBoneNameExists(ExportRoot)) { yield return(Validation.Warning(Msg(VRMExporterWizardMessages.DUPLICATE_BONE_NAME_EXISTS))); } if (m_settings.ReduceBlendshape && ExportRoot.GetComponent <VRMBlendShapeProxy>() == null) { yield return(Validation.Error(Msg(VRMExporterWizardMessages.NEEDS_VRM_BLENDSHAPE_PROXY))); } var renderers = ExportRoot.GetComponentsInChildren <Renderer>(); foreach (var r in renderers) { for (int i = 0; i < r.sharedMaterials.Length; ++i) { if (r.sharedMaterials[i] == null) { yield return(Validation.Error($"Renderer: {r.name}.Materials[{i}] is null. please fix it")); } } } var materials = renderers.SelectMany(x => x.sharedMaterials).Where(x => x != null).Distinct(); foreach (var material in materials) { if (material == null) { continue; } if (material.shader.name == "Standard") { // standard continue; } if (VRMMaterialExporter.UseUnlit(material.shader.name)) { // unlit continue; } if (VRMMaterialExporter.VRMExtensionShaders.Contains(material.shader.name)) { // VRM supported continue; } yield return(Validation.Warning($"Material: {material.name}. Unknown Shader: \"{material.shader.name}\" is used. {Msg(VRMExporterWizardMessages.UNKNOWN_SHADER)}")); } foreach (var material in materials) { if (IsFileNameLengthTooLong(material.name)) { yield return(Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + material.name)); } } var textureNameList = new List <string>(); foreach (var material in materials) { var shader = material.shader; int propertyCount = ShaderUtil.GetPropertyCount(shader); for (int i = 0; i < propertyCount; i++) { if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv) { if ((material.GetTexture(ShaderUtil.GetPropertyName(shader, i)) != null)) { var textureName = material.GetTexture(ShaderUtil.GetPropertyName(shader, i)).name; if (!textureNameList.Contains(textureName)) { textureNameList.Add(textureName); } } } } } foreach (var textureName in textureNameList) { if (IsFileNameLengthTooLong(textureName)) { yield return(Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + textureName)); } } var vrmMeta = ExportRoot.GetComponent <VRMMeta>(); if (vrmMeta != null && vrmMeta.Meta != null && vrmMeta.Meta.Thumbnail != null) { var thumbnailName = vrmMeta.Meta.Thumbnail.name; if (IsFileNameLengthTooLong(thumbnailName)) { yield return(Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + thumbnailName)); } } var meshFilters = ExportRoot.GetComponentsInChildren <MeshFilter>(); var meshesName = meshFilters.Select(x => x.sharedMesh.name).Distinct(); foreach (var meshName in meshesName) { if (IsFileNameLengthTooLong(meshName)) { yield return(Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + meshName)); } } var skinnedmeshRenderers = ExportRoot.GetComponentsInChildren <SkinnedMeshRenderer>(); var skinnedmeshesName = skinnedmeshRenderers.Select(x => x.sharedMesh.name).Distinct(); foreach (var skinnedmeshName in skinnedmeshesName) { if (IsFileNameLengthTooLong(skinnedmeshName)) { yield return(Validation.Error(Msg(VRMExporterWizardMessages.FILENAME_TOO_LONG) + skinnedmeshName)); } } }
bool TryGetMeshInfo(GameObject root, Renderer renderer, IReadOnlyList <BlendShapeClip> clips, VRMExportSettings settings, out UniGLTF.MeshExportInfo info) { info = default; if (root == null) { info.Summary = ""; return(false); } if (renderer == null) { info.Summary = "no Renderer"; return(false); } info.Renderer = renderer; if (renderer is SkinnedMeshRenderer smr) { info.Skinned = true; info.Mesh = smr.sharedMesh; info.IsRendererActive = smr.EnableForExport(); } else if (renderer is MeshRenderer mr) { var filter = mr.GetComponent <MeshFilter>(); if (filter != null) { info.Mesh = filter.sharedMesh; } info.IsRendererActive = mr.EnableForExport(); } else { info.Summary = "no Mesh"; return(false); } info.VertexColor = UniGLTF.MeshExportInfo.DetectVertexColor(info.Mesh, info.Renderer.sharedMaterials); var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, root.transform); CalcMeshSize(ref info, relativePath, settings, clips); return(true); }
public static void CalcMeshSize(ref UniGLTF.MeshExportInfo info, string relativePath, VRMExportSettings settings, IReadOnlyList <BlendShapeClip> clips) { var sb = new StringBuilder(); if (!info.IsRendererActive) { sb.Append("[NotActive]"); } info.VertexCount = info.Mesh.vertexCount; info.ExportVertexSize = 0; info.TotalBlendShapeCount = 0; info.ExportBlendShapeCount = 0; // float4 x 3 // vertices sb.Append($"(Pos"); if (info.HasNormal) { sb.Append("+Nom"); info.ExportVertexSize += 4 * 3; } if (info.HasUV) { sb.Append("+UV"); info.ExportVertexSize += 4 * 2; } if (info.HasVertexColor) { sb.Append("+Col"); info.ExportVertexSize += 4 * 4; } if (info.HasSkinning) { // short, float x 4 weights sb.Append("+Skin"); info.ExportVertexSize += (2 + 4) * 4; } // indices info.IndexCount = info.Mesh.triangles.Length; // postion + normal ?. always tangent is ignored info.TotalBlendShapeCount = info.Mesh.blendShapeCount; info.ExportBlendShapeVertexSize = settings.OnlyBlendshapePosition ? 4 * 3 : 4 * (3 + 3); for (var i = 0; i < info.Mesh.blendShapeCount; ++i) { // var name = Mesh.GetBlendShapeName(i); if (settings.ReduceBlendshape) { if (!ClipsContainsName(clips, settings.ReduceBlendshapeClip, new BlendShapeBinding { Index = i, RelativePath = relativePath, })) { // skip continue; } } ++info.ExportBlendShapeCount; } if (info.ExportBlendShapeCount > 0) { sb.Append($"+Morph x {info.ExportBlendShapeCount}"); } sb.Append($") x {info.Mesh.vertexCount}"); switch (info.VertexColor) { case UniGLTF.MeshExportInfo.VertexColorState.ExistsAndIsUsed: case UniGLTF.MeshExportInfo.VertexColorState.ExistsAndMixed: // エクスポートする sb.Insert(0, "[use vcolor]"); break; case UniGLTF.MeshExportInfo.VertexColorState.ExistsButNotUsed: sb.Insert(0, "[remove vcolor]"); break; } if (info.ExportBlendShapeCount > 0 && !info.HasSkinning) { sb.Insert(0, "[morph without skin]"); } // total bytes sb.Insert(0, $"{info.ExportByteSize:#,0} Bytes = "); info.Summary = sb.ToString(); }