コード例 #1
0
        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);
        }
コード例 #2
0
ファイル: VRMExportMeshes.cs プロジェクト: yoshivb/UniVRM
        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);
                }
            }
        }
コード例 #3
0
ファイル: VRMExporterWizard.cs プロジェクト: yoshivb/UniVRM
        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;
        }
コード例 #4
0
        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;
        }
コード例 #5
0
        /// <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());
            }
        }
コード例 #6
0
        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");
        }
コード例 #7
0
ファイル: VRMExporterWizard.cs プロジェクト: yoshivb/UniVRM
        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);
        }
コード例 #8
0
        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;
        }
コード例 #9
0
 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);
             }
         }
     }
 }
コード例 #10
0
        /// <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);
                }
            }
        }
コード例 #11
0
        /// <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);
                }
            }
        }
コード例 #12
0
        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;
        }
コード例 #13
0
        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);
        }
コード例 #14
0
ファイル: VRMExporterWizard.cs プロジェクト: kodzitive/UniVRM
        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()));
        }
コード例 #15
0
        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();
        }
コード例 #16
0
        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);
        }
コード例 #17
0
 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;
 }
コード例 #18
0
        /// <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();
        }
コード例 #19
0
        /// <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();
        }
コード例 #20
0
        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)
                    ;
                }
            };
        }
コード例 #21
0
        /// <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);
                }
            }
        }
コード例 #22
0
        /// <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());
            }
        }
コード例 #23
0
        /// <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);
        }
コード例 #24
0
        /// <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());
            }
        }
コード例 #25
0
        public void DetectFileNameLength(string fileName, bool isIllegal)
        {
            var result = VRMExportSettings.IsFileNameLengthTooLong(fileName);

            Assert.AreEqual(result, isIllegal);
        }
コード例 #26
0
        /// <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);
        }
コード例 #27
0
        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));
                }
            }
        }
コード例 #28
0
ファイル: VRMExportMeshes.cs プロジェクト: yoshivb/UniVRM
        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);
        }
コード例 #29
0
ファイル: VRMExportMeshes.cs プロジェクト: yoshivb/UniVRM
        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();
        }