/// <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; }
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()); } }
/// <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()); } }
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()); } }
/// <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); }