Merge pull request #304 from Kohei-Yanagida/reduce_blendshape_size

add VRM Export Option. Reduce BlendShape Size
This commit is contained in:
hiroj 2019-12-13 22:39:37 +09:00 committed by GitHub
commit c842e577c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 124 additions and 12 deletions

View File

@ -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<MeshWithRenderer> unityMeshes, List<Material> 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

View File

@ -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
);
}

View File

@ -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

View File

@ -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<string> CanExport()
{
if (Source == null)
@ -142,7 +145,7 @@ namespace VRM
var dstColliderGroup = dst.gameObject.AddComponent<VRMSpringBoneColliderGroup>();
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<VRMSpringBoneColliderGroup>()).ToArray();
dst.ColliderGroups = src.ColliderGroups
.Select(x => map[x.transform].GetComponent<VRMSpringBoneColliderGroup>()).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<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);
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
}
}
}

View File

@ -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
}
}
}
}
}