diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs index 5589bd310..c8368436f 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs @@ -106,13 +106,15 @@ namespace UniGLTF static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, Mesh mesh, int j, - bool useSparseAccessorForMorphTarget) + bool useSparseAccessorForMorphTarget, + bool exportOnlyBlendShapePosition) { var blendShapeVertices = mesh.vertices; var usePosition = blendShapeVertices != null && blendShapeVertices.Length > 0; var blendShapeNormals = mesh.normals; var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length; + // var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length && !exportOnlyBlendShapePosition; var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray(); //var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length; @@ -228,7 +230,8 @@ namespace UniGLTF public static void ExportMeshes(glTF gltf, int bufferIndex, List unityMeshes, List unityMaterials, - bool useSparseAccessorForMorphTarget) + bool useSparseAccessorForMorphTarget, + bool exportOnlyBlendShapePosition) { for (int i = 0; i < unityMeshes.Count; ++i) { @@ -244,7 +247,8 @@ namespace UniGLTF { var morphTarget = ExportMorphTarget(gltf, bufferIndex, mesh, j, - useSparseAccessorForMorphTarget); + useSparseAccessorForMorphTarget, + exportOnlyBlendShapePosition); // // all primitive has same blendShape diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs index 1c5b59dd5..d30be935a 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs @@ -468,7 +468,7 @@ namespace UniGLTF { mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, blendShape.Positions.ToArray(), - (meshContext.normals != null && meshContext.normals.Length == mesh.vertexCount) ? blendShape.Normals.ToArray() : null, + (meshContext.normals != null && meshContext.normals.Length == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, null ); } diff --git a/Assets/VRM/UniGLTF/Scripts/IO/gltfExporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/gltfExporter.cs index 1a4a6e39d..3e5226390 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/gltfExporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/gltfExporter.cs @@ -60,6 +60,12 @@ namespace UniGLTF set; } + public bool ExportOnlyBlendShapePosition + { + get; + set; + } + public GameObject Copy { get; @@ -240,7 +246,7 @@ namespace UniGLTF return true; }) .ToList(); - MeshExporter.ExportMeshes(gltf, bufferIndex, unityMeshes, Materials, useSparseAccessorForMorphTarget); + MeshExporter.ExportMeshes(gltf, bufferIndex, unityMeshes, Materials, useSparseAccessorForMorphTarget, ExportOnlyBlendShapePosition); Meshes = unityMeshes.Select(x => x.Mesh).ToList(); #endregion diff --git a/Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs b/Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs index 49019ea86..d0abcc143 100644 --- a/Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs +++ b/Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs @@ -6,6 +6,7 @@ using UniGLTF; using System.IO; #if UNITY_EDITOR using UnityEditor; + #endif @@ -32,6 +33,8 @@ namespace VRM public bool UseExperimentalExporter = true; + public bool ReduceBlendshapeSize = true; + public IEnumerable CanExport() { if (Source == null) @@ -142,7 +145,7 @@ namespace VRM var dstColliderGroup = dst.gameObject.AddComponent(); dstColliderGroup.Colliders = src.Colliders.Select(y => { - var offset = dst.worldToLocalMatrix.MultiplyPoint(src.transform.localToWorldMatrix.MultiplyPoint(y.Offset)); + var offset =dst.worldToLocalMatrix.MultiplyPoint(src.transform.localToWorldMatrix.MultiplyPoint(y.Offset)); return new VRMSpringBoneColliderGroup.SphereCollider { Offset = offset, @@ -164,11 +167,13 @@ namespace VRM { dst.m_center = map[src.m_center]; } + dst.RootBones = src.RootBones.Select(x => map[x]).ToList(); dst.m_hitRadius = src.m_hitRadius; if (src.ColliderGroups != null) { - dst.ColliderGroups = src.ColliderGroups.Select(x => map[x.transform].GetComponent()).ToArray(); + dst.ColliderGroups = src.ColliderGroups + .Select(x => map[x.transform].GetComponent()).ToArray(); } } } @@ -270,6 +275,7 @@ namespace VRM destroy.Add(target); } } + if (PoseFreeze) { using (new RecordDisposer(target.transform.Traverse().ToArray(), "before normalize")) @@ -281,9 +287,95 @@ namespace VRM } } + // remove unused blendShape + if (ReduceBlendshapeSize) + { + var proxy = target.GetComponent(); + + // 元のBlendShapeClipに変更を加えないように複製 + var copyBlendShapeAvatar = GameObject.Instantiate(proxy.BlendShapeAvatar); + var copyBlendShapClips = new List(); + + foreach (var clip in proxy.BlendShapeAvatar.Clips) + { + copyBlendShapClips.Add(GameObject.Instantiate(clip)); + } + + var skinnedMeshRenderers = target.GetComponentsInChildren(); + + var names = new Dictionary(); + var vs = new Dictionary(); + var ns = new Dictionary(); + var ts = new Dictionary(); + + 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); + var vrm = VRMExporter.Export(target, ReduceBlendshapeSize); vrm.extensions.VRM.meta.title = Title; vrm.extensions.VRM.meta.version = Version; vrm.extensions.VRM.meta.author = Author; @@ -296,6 +388,12 @@ namespace VRM Debug.LogFormat("Export elapsed {0}", sw.Elapsed); } +#if UNITY_2018_3_OR_NEWER + PrefabUtility.RevertPrefabInstance(target, InteractionMode.AutomatedAction); +#else + PrefabUtility.RevertPrefabInstance(target); +#endif + if (path.StartsWithUnityAssetPath()) { AssetDatabase.ImportAsset(path.ToUnityRelativePath()); @@ -303,4 +401,4 @@ namespace VRM } #endif } -} +} \ No newline at end of file diff --git a/Assets/VRM/UniVRM/Scripts/Format/VRMExporter.cs b/Assets/VRM/UniVRM/Scripts/Format/VRMExporter.cs index a72d0cf6f..8a03bb0db 100644 --- a/Assets/VRM/UniVRM/Scripts/Format/VRMExporter.cs +++ b/Assets/VRM/UniVRM/Scripts/Format/VRMExporter.cs @@ -19,7 +19,7 @@ namespace VRM gltf.extensions.VRM = new glTF_VRM_extensions(); } - public new static glTF Export(GameObject go) + public new static glTF Export(GameObject go, bool exportOnlyBlendShapePosition = false) { var gltf = new glTF(); @@ -27,12 +27,14 @@ namespace VRM { #if VRM_EXPORTER_USE_SPARSE // experimental - UseSparseAccessorForBlendShape=true + UseSparseAccessorForBlendShape = true #endif + ExportOnlyBlendShapePosition = exportOnlyBlendShapePosition }) { _Export(gltf, exporter, go); } + return gltf; } @@ -60,6 +62,7 @@ namespace VRM // use description gltf.extensions.VRM.humanoid.Apply(description, nodes); } + if (isCreated) { GameObject.DestroyImmediate(description); @@ -119,6 +122,7 @@ namespace VRM { gltf.extensions.VRM.meta.texture = TextureIO.ExportTexture(gltf, gltf.buffers.Count - 1, meta.Thumbnail, glTFTextureTypes.Unknown); } + gltf.extensions.VRM.meta.licenseType = meta.LicenseType; gltf.extensions.VRM.meta.otherLicenseUrl = meta.OtherLicenseUrl; gltf.extensions.VRM.meta.reference = meta.Reference; @@ -208,4 +212,4 @@ namespace VRM } } } -} +} \ No newline at end of file