diff --git a/Assets/VRM10/Runtime/Migration/MeshUpdater.cs b/Assets/VRM10/Runtime/Migration/MeshUpdater.cs
index aeb8611f5..1ca4c8d10 100644
--- a/Assets/VRM10/Runtime/Migration/MeshUpdater.cs
+++ b/Assets/VRM10/Runtime/Migration/MeshUpdater.cs
@@ -10,7 +10,12 @@ namespace UniVRM10
{
///
/// 座標系を変換した Model により、Mesh, Node, BindMatrices を更新する。
- /// buffer, bufferAccessor の更新もある。
+ ///
+ /// * gltf.images の参照する bufferView
+ /// * gltf.meshes の参照する index, VERTEX, MorphTarget の accessor, bufferView
+ /// * gltf.nodes の参照する skin の inverseBindMatrices 向けの accessor, bufferView
+ ///
+ /// を詰め込みなすことで bin を再構築する
///
class MeshUpdater
{
@@ -19,12 +24,23 @@ namespace UniVRM10
List _bufferViews = new List();
List _accessors = new List();
- public MeshUpdater(GltfData data)
+ MeshUpdater(GltfData data)
{
_data = data;
_buffer = new ArrayByteBuffer(new byte[data.Bin.Length]);
}
+ ///
+ /// data を model で更新する
+ ///
+ /// 更新前のオリジナル
+ /// 座標系の変換などの操作済み
+ ///
+ public static (glTF, ArraySegment) Execute(GltfData data, VrmLib.Model model)
+ {
+ return new MeshUpdater(data).Update(model);
+ }
+
int AddBuffer(NativeArray bytes)
{
var bufferView = _buffer.Extend(bytes);
@@ -64,7 +80,12 @@ namespace UniVRM10
public int? Normal;
};
- public (glTF, ArraySegment) Update(VrmLib.Model model)
+ ///
+ /// bufferView, accessor を push することで bin を再構築する
+ ///
+ /// meshの右手左手変換結果
+ ///
+ (glTF, ArraySegment) Update(VrmLib.Model model)
{
var gltf = _data.GLTF;
@@ -75,74 +96,14 @@ namespace UniVRM10
image.bufferView = AddBuffer(bytes);
}
- // update Mesh
- foreach (var (gltfMesh, mesh) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r.Meshes[0])))
+ // copy mesh
+ if (model.MeshGroups.All(x => x.Meshes.Count == 1))
{
- NativeArray indices;
- switch (mesh.IndexBuffer.Stride)
- {
- case 1:
- {
- // byte
- var byte_indices = mesh.IndexBuffer.GetSpan();
- indices = _data.NativeArrayManager.Convert(byte_indices, (byte x) => (uint)x);
- break;
- }
-
- case 2:
- {
- // ushort
- var ushort_indices = mesh.IndexBuffer.GetSpan();
- indices = _data.NativeArrayManager.Convert(ushort_indices, (ushort x) => (uint)x);
- break;
- }
-
- case 4:
- {
- // uint
- indices = mesh.IndexBuffer.GetSpan();
- break;
- }
-
- default:
- throw new NotImplementedException();
- }
- var position = AddAccessor(mesh.VertexBuffer.Positions);
- var normal = AddAccessor(mesh.VertexBuffer.Normals);
- var uv = AddAccessor(mesh.VertexBuffer.TexCoords);
- var weights = AddAccessor(mesh.VertexBuffer.Weights);
- var joints = AddAccessor(mesh.VertexBuffer.Joints);
- var color = AddAccessor(mesh.VertexBuffer.Colors);
-
- var morphTargets = new MorphAccessor[] { };
- if (mesh.MorphTargets != null)
- {
- morphTargets = mesh.MorphTargets.Select(x => new MorphAccessor
- {
- Position = AddAccessor(x.VertexBuffer.Positions),
- Normal = AddAccessor(x.VertexBuffer.Normals),
- }).ToArray();
- }
-
- foreach (var (gltfPrim, submesh) in Enumerable.Zip(gltfMesh.primitives, mesh.Submeshes, (l, r) => (l, r)))
- {
- var subIndices = indices.GetSubArray(submesh.Offset, submesh.DrawCount);
- gltfPrim.indices = AddAccessor(subIndices);
- gltfPrim.attributes.POSITION = position.Value;
- gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる
- gltfPrim.attributes.TANGENT = -1;
- gltfPrim.attributes.COLOR_0 = color.GetValueOrDefault(-1);
- gltfPrim.attributes.TEXCOORD_0 = uv.GetValueOrDefault(-1); // ありえる?
- gltfPrim.attributes.TEXCOORD_1 = -1;
- gltfPrim.attributes.WEIGHTS_0 = weights.GetValueOrDefault(-1);
- gltfPrim.attributes.JOINTS_0 = joints.GetValueOrDefault(-1);
- foreach (var (gltfMorph, morph) in Enumerable.Zip(gltfPrim.targets, morphTargets, (l, r) => (l, r)))
- {
- gltfMorph.POSITION = morph.Position.GetValueOrDefault(-1);
- gltfMorph.NORMAL = morph.Normal.GetValueOrDefault(-1);
- gltfMorph.TANGENT = -1;
- }
- }
+ UpdateSharedVertexBuffer(model);
+ }
+ else
+ {
+ UpdateDividedVertexBuffer(model);
}
// update nodes and remove unused skin
@@ -212,6 +173,167 @@ namespace UniVRM10
gltf.accessors = _accessors;
return (gltf, _buffer.Bytes);
+
+ }
+
+ ///
+ /// model はひとつのノードに複数の mesh をぶら下げることができる(meshGroup)
+ /// gltf.meshes[i].primitives[j] <-> model.meshGroups[i].meshes[0].submeshes[j]
+ ///
+ void UpdateSharedVertexBuffer(VrmLib.Model model)
+ {
+ var gltf = _data.GLTF;
+
+ // gltfMeshes[i] <=> MeshGroups[i].Meshes[0] ( MeshGroups[i].Meshes.Count == 1 )
+ foreach (var (gltfMesh, mesh) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r.Meshes[0])))
+ {
+ NativeArray indices;
+ switch (mesh.IndexBuffer.Stride)
+ {
+ case 1:
+ {
+ // byte
+ var byte_indices = mesh.IndexBuffer.GetSpan();
+ indices = _data.NativeArrayManager.Convert(byte_indices, (byte x) => (uint)x);
+ break;
+ }
+
+ case 2:
+ {
+ // ushort
+ var ushort_indices = mesh.IndexBuffer.GetSpan();
+ indices = _data.NativeArrayManager.Convert(ushort_indices, (ushort x) => (uint)x);
+ break;
+ }
+
+ case 4:
+ {
+ // uint
+ indices = mesh.IndexBuffer.GetSpan();
+ break;
+ }
+
+ default:
+ throw new NotImplementedException();
+ }
+ var position = AddAccessor(mesh.VertexBuffer.Positions);
+ var normal = AddAccessor(mesh.VertexBuffer.Normals);
+ var uv = AddAccessor(mesh.VertexBuffer.TexCoords);
+ var weights = AddAccessor(mesh.VertexBuffer.Weights);
+ var joints = AddAccessor(mesh.VertexBuffer.Joints);
+ var color = AddAccessor(mesh.VertexBuffer.Colors);
+
+ var morphTargets = new MorphAccessor[] { };
+ if (mesh.MorphTargets != null)
+ {
+ morphTargets = mesh.MorphTargets.Select(x => new MorphAccessor
+ {
+ Position = AddAccessor(x.VertexBuffer.Positions),
+ Normal = AddAccessor(x.VertexBuffer.Normals),
+ }).ToArray();
+ }
+
+ // gltfPrim[j] <=> mesh.Submeshes[j]
+ foreach (var (gltfPrim, submesh) in Enumerable.Zip(gltfMesh.primitives, mesh.Submeshes, (l, r) => (l, r)))
+ {
+ var subIndices = indices.GetSubArray(submesh.Offset, submesh.DrawCount);
+ gltfPrim.indices = AddAccessor(subIndices);
+ gltfPrim.attributes.POSITION = position.Value;
+ gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる
+ gltfPrim.attributes.TANGENT = -1;
+ gltfPrim.attributes.COLOR_0 = color.GetValueOrDefault(-1);
+ gltfPrim.attributes.TEXCOORD_0 = uv.GetValueOrDefault(-1); // ありえる?
+ gltfPrim.attributes.TEXCOORD_1 = -1;
+ gltfPrim.attributes.WEIGHTS_0 = weights.GetValueOrDefault(-1);
+ gltfPrim.attributes.JOINTS_0 = joints.GetValueOrDefault(-1);
+ foreach (var (gltfMorph, morph) in Enumerable.Zip(gltfPrim.targets, morphTargets, (l, r) => (l, r)))
+ {
+ gltfMorph.POSITION = morph.Position.GetValueOrDefault(-1);
+ gltfMorph.NORMAL = morph.Normal.GetValueOrDefault(-1);
+ gltfMorph.TANGENT = -1;
+ }
+ }
+ }
+ }
+
+ ///
+ /// model はひとつのノードに複数の mesh をぶら下げることができる(meshGroup)
+ /// gltf.meshes[i].primitives[j] <-> model.meshGroups[i].meshes[j].submeshes[0]
+ ///
+ void UpdateDividedVertexBuffer(VrmLib.Model model)
+ {
+ var gltf = _data.GLTF;
+
+ // gltfMesh[i] <=> meshGroups[i]
+ foreach (var (gltfMesh, meshGroup) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r)))
+ {
+ // gltfPrimitives[j] <=> meshGroup.Meshes[j] (meshGroup.Meshes[j].Submeshes.Count==1)
+ foreach (var (gltfPrim, mesh) in Enumerable.Zip(gltfMesh.primitives, meshGroup.Meshes, (l, r) => (l, r)))
+ {
+ NativeArray indices;
+ switch (mesh.IndexBuffer.Stride)
+ {
+ case 1:
+ {
+ // byte
+ var byte_indices = mesh.IndexBuffer.GetSpan();
+ indices = _data.NativeArrayManager.Convert(byte_indices, (byte x) => (uint)x);
+ break;
+ }
+
+ case 2:
+ {
+ // ushort
+ var ushort_indices = mesh.IndexBuffer.GetSpan();
+ indices = _data.NativeArrayManager.Convert(ushort_indices, (ushort x) => (uint)x);
+ break;
+ }
+
+ case 4:
+ {
+ // uint
+ indices = mesh.IndexBuffer.GetSpan();
+ break;
+ }
+
+ default:
+ throw new NotImplementedException();
+ }
+
+ var position = AddAccessor(mesh.VertexBuffer.Positions);
+ var normal = AddAccessor(mesh.VertexBuffer.Normals);
+ var uv = AddAccessor(mesh.VertexBuffer.TexCoords);
+ var weights = AddAccessor(mesh.VertexBuffer.Weights);
+ var joints = AddAccessor(mesh.VertexBuffer.Joints);
+ var color = AddAccessor(mesh.VertexBuffer.Colors);
+
+ var morphTargets = new MorphAccessor[] { };
+ if (mesh.MorphTargets != null)
+ {
+ morphTargets = mesh.MorphTargets.Select(x => new MorphAccessor
+ {
+ Position = AddAccessor(x.VertexBuffer.Positions),
+ Normal = AddAccessor(x.VertexBuffer.Normals),
+ }).ToArray();
+ }
+
+ gltfPrim.indices = AddAccessor(indices);
+ gltfPrim.attributes.POSITION = position.Value;
+ gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる
+ gltfPrim.attributes.TANGENT = -1;
+ gltfPrim.attributes.COLOR_0 = color.GetValueOrDefault(-1);
+ gltfPrim.attributes.TEXCOORD_0 = uv.GetValueOrDefault(-1); // ありえる?
+ gltfPrim.attributes.TEXCOORD_1 = -1;
+ gltfPrim.attributes.WEIGHTS_0 = weights.GetValueOrDefault(-1);
+ gltfPrim.attributes.JOINTS_0 = joints.GetValueOrDefault(-1);
+ foreach (var (gltfMorph, morph) in Enumerable.Zip(gltfPrim.targets, morphTargets, (l, r) => (l, r)))
+ {
+ gltfMorph.POSITION = morph.Position.GetValueOrDefault(-1);
+ gltfMorph.NORMAL = morph.Normal.GetValueOrDefault(-1);
+ gltfMorph.TANGENT = -1;
+ }
+ }
+ }
}
}
}
diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs
index 6311ccb2f..68584cc5b 100644
--- a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs
+++ b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs
@@ -38,7 +38,7 @@ namespace UniVRM10
// Unity -> VRM1
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1);
- var (gltf, bin) = new MeshUpdater(data).Update(model);
+ var (gltf, bin) = MeshUpdater.Execute(data, model);
gltf.extensions = null;
return MigrateVrm(gltf, bin, data.Json.ParseAsJson()["extensions"]["VRM"]);
}