private static void ExportFromMenu()
        {
            var go = Selection.activeObject as GameObject;

            // BoneNormalizer.Execute はコピーを正規化する。UNDO無用
            Selection.activeGameObject = BoneNormalizer.Execute(go, true, false);
        }
Esempio n. 2
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());
            }
        }
        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;
        }
Esempio n. 4
0
        void Export(string path, List <GameObject> destroy)
        {
            var target = Source;

            if (IsPrefab(target))
            {
                using (new RecordDisposer(Source.transform.Traverse().ToArray(), "before normalize"))
                {
                    target = GameObject.Instantiate(target);
                    destroy.Add(target);
                }
            }
            if (PoseFreeze)
            {
                using (new RecordDisposer(target.transform.Traverse().ToArray(), "before normalize"))
                {
                    var normalized = BoneNormalizer.Execute(target, ForceTPose, false);
                    CopyVRMComponents(target, normalized.Root, normalized.BoneMap);
                    target = normalized.Root;
                    destroy.Add(target);
                }
            }

            {
                var sw  = System.Diagnostics.Stopwatch.StartNew();
                var vrm = VRMExporter.Export(target);
                vrm.extensions.VRM.meta.title  = Title;
                vrm.extensions.VRM.meta.author = Author;

                var bytes = vrm.ToGlbBytes();
                File.WriteAllBytes(path, bytes);
                Debug.LogFormat("Export elapsed {0}", sw.Elapsed);
            }

            if (path.StartsWithUnityAssetPath())
            {
                AssetDatabase.ImportAsset(path.ToUnityRelativePath());
            }
        }
Esempio n. 5
0
        public void MapBoneWeightTest()
        {
            {
                var map = new BoneMap();
                map.Add(new GameObject("a"), new GameObject("A"));
                map.Add(new GameObject("b"), new GameObject("B"));
                map.Add(new GameObject("c"), new GameObject("C"));
                map.Add(new GameObject("d"), new GameObject("D"));
                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,
                                                                 map.SrcBones.ToArray(), map.DstBones.ToArray());

                // 正常系
                // exception が出なければよい
            }

            {
                var map = new BoneMap();
                map.Add(new GameObject("a"), new GameObject("A"));
                map.Add(new GameObject("b"), new GameObject("B"));
                map.Add(new GameObject("c"), new GameObject("C"));
                map.Add(new GameObject("d"), new GameObject("D"));
                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,
                                                                 map.SrcBones.ToArray(), map.DstBones.ToArray());

                // 4 つめが 0 になる
                Assert.AreEqual(0, newBoneWeight[1].boneIndex0);
                Assert.AreEqual(0, newBoneWeight[1].weight0);
                // 5 つめ以降が 0 になる。out of range
                Assert.AreEqual(0, newBoneWeight[1].boneIndex1);
                Assert.AreEqual(0, newBoneWeight[1].weight1);
            }
        }
Esempio n. 6
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);

            {
                // copy元
                var animator         = settings.Source.GetComponent <Animator>();
                var beforeTransforms = settings.Source.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 = BoneNormalizer.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());
            }
        }
Esempio n. 7
0
        void Export(string path, List <GameObject> destroy)
        {
            var target = Source;

            if (IsPrefab(target))
            {
                using (new RecordDisposer(Source.transform.Traverse().ToArray(), "before normalize"))
                {
                    target = GameObject.Instantiate(target);
                    destroy.Add(target);
                }
            }

            if (PoseFreeze)
            {
                using (new RecordDisposer(target.transform.Traverse().ToArray(), "before normalize"))
                {
                    var normalized = BoneNormalizer.Execute(target, ForceTPose, false);
                    CopyVRMComponents(target, normalized.Root, normalized.BoneMap);
                    target = normalized.Root;
                    destroy.Add(target);
                }
            }

            // remove unused blendShape
            if (ReduceBlendshapeSize)
            {
                var proxy = target.GetComponent <VRMBlendShapeProxy>();

                // 元のBlendShapeClipに変更を加えないように複製
                var copyBlendShapeAvatar = GameObject.Instantiate(proxy.BlendShapeAvatar);
                var copyBlendShapClips   = new List <BlendShapeClip>();

                foreach (var clip in proxy.BlendShapeAvatar.Clips)
                {
                    copyBlendShapClips.Add(GameObject.Instantiate(clip));
                }

                var skinnedMeshRenderers = target.GetComponentsInChildren <SkinnedMeshRenderer>();

                var names = new Dictionary <int, string>();
                var vs    = new Dictionary <int, Vector3[]>();
                var ns    = new Dictionary <int, Vector3[]>();
                var ts    = new Dictionary <int, Vector3[]>();

                foreach (SkinnedMeshRenderer smr in skinnedMeshRenderers)
                {
                    Mesh mesh = smr.sharedMesh;
                    if (mesh == null)
                    {
                        continue;
                    }
                    if (mesh.blendShapeCount == 0)
                    {
                        continue;
                    }

                    var copyMesh = mesh.Copy(true);
                    var vCount   = copyMesh.vertexCount;
                    names.Clear();

                    vs.Clear();
                    ns.Clear();
                    ts.Clear();

                    var usedBlendshapeIndexArray = copyBlendShapClips
                                                   .SelectMany(clip => clip.Values)
                                                   .Where(val => target.transform.Find(val.RelativePath) == smr.transform)
                                                   .Select(val => val.Index)
                                                   .Distinct()
                                                   .ToArray();

                    foreach (var i in usedBlendshapeIndexArray)
                    {
                        var name     = copyMesh.GetBlendShapeName(i);
                        var vertices = new Vector3[vCount];
                        var normals  = new Vector3[vCount];
                        var tangents = new Vector3[vCount];
                        copyMesh.GetBlendShapeFrameVertices(i, 0, vertices, normals, tangents);

                        names.Add(i, name);
                        vs.Add(i, vertices);
                        ns.Add(i, normals);
                        ts.Add(i, tangents);
                    }

                    copyMesh.ClearBlendShapes();

                    foreach (var i in usedBlendshapeIndexArray)
                    {
                        copyMesh.AddBlendShapeFrame(names[i], 100f, vs[i], ns[i], ts[i]);
                    }

                    var indexMapper = usedBlendshapeIndexArray
                                      .Select((x, i) => new { x, i })
                                      .ToDictionary(pair => pair.x, pair => pair.i);

                    foreach (var clip in copyBlendShapClips)
                    {
                        for (var i = 0; i < clip.Values.Length; ++i)
                        {
                            var value = clip.Values[i];
                            if (target.transform.Find(value.RelativePath) != smr.transform)
                            {
                                continue;
                            }
                            value.Index    = indexMapper[value.Index];
                            clip.Values[i] = value;
                        }
                    }

                    copyBlendShapeAvatar.Clips = copyBlendShapClips;

                    proxy.BlendShapeAvatar = copyBlendShapeAvatar;

                    smr.sharedMesh = copyMesh;
                }
            }

            {
                var sw  = System.Diagnostics.Stopwatch.StartNew();
                var vrm = VRMExporter.Export(target, ReduceBlendshapeSize);
                vrm.extensions.VRM.meta.title              = Title;
                vrm.extensions.VRM.meta.version            = Version;
                vrm.extensions.VRM.meta.author             = Author;
                vrm.extensions.VRM.meta.contactInformation = ContactInformation;
                vrm.extensions.VRM.meta.reference          = Reference;


                var bytes = vrm.ToGlbBytes(UseExperimentalExporter?SerializerTypes.Generated:SerializerTypes.UniJSON);
                File.WriteAllBytes(path, bytes);
                Debug.LogFormat("Export elapsed {0}", sw.Elapsed);
            }
            if (IsPrefab(Source))
            {
#if UNITY_2018_3_OR_NEWER
                PrefabUtility.RevertPrefabInstance(Source, InteractionMode.AutomatedAction);
#else
                PrefabUtility.RevertPrefabInstance(target);
#endif
            }

            if (path.StartsWithUnityAssetPath())
            {
                AssetDatabase.ImportAsset(path.ToUnityRelativePath());
            }
        }
Esempio n. 8
0
        /// <summary>
        /// モデルの正規化を実行する
        /// </summary>
        /// <param name="go">対象モデルのルート</param>
        /// <param name="forceTPose">強制的にT-Pose化するか</param>
        /// <returns>正規化済みのモデル</returns>
        public static GameObject Execute(GameObject go, bool forceTPose)
        {
            //
            // T-Poseにする
            //
            if (forceTPose)
            {
                var hips         = go.GetComponent <Animator>().GetBoneTransform(HumanBodyBones.Hips);
                var hipsPosition = hips.position;
                var hipsRotation = hips.rotation;
                try
                {
                    EnforceTPose(go);
                }
                finally
                {
                    hips.position = hipsPosition; // restore hipsPosition
                    hips.rotation = hipsRotation;
                }
            }

            //
            // 正規化されたヒエラルキーを作る
            //
            var(normalized, bMap) = BoneNormalizer.Execute(go, (_src, dst, boneMap) =>
            {
                var src = _src.GetComponent <Animator>();

                var srcHumanBones = Enum.GetValues(typeof(HumanBodyBones))
                                    .Cast <HumanBodyBones>()
                                    .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 <Animator>() == null)
                {
                    var animator = dst.AddComponent <Animator>();
                }
                var vrmHuman          = go.GetComponent <VRMHumanoidDescription>();
                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);
        }