mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-21 02:07:58 -05:00
Merge pull request #380 from mkc1370/support_mesh_sharing_morph_target
Support mesh sharing morph target
This commit is contained in:
commit
ed255dbc77
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/KhronosGroup/glTF/issues/1036
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public partial class glTFMesh_extras : ExtraBase<glTFMesh_extras>
|
||||
{
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<string> targetNames = new List<string>();
|
||||
|
||||
[JsonSerializeMembers]
|
||||
void PrimitiveMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (targetNames.Count > 0)
|
||||
{
|
||||
f.Key("targetNames");
|
||||
f.BeginList();
|
||||
foreach (var x in targetNames)
|
||||
{
|
||||
f.Value(x);
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 97b77d4c1c0d44b594e9187e41b3152d
|
||||
timeCreated: 1582269878
|
||||
|
|
@ -146,9 +146,11 @@ namespace UniGLTF
|
|||
[JsonSchema(MinItems = 1)]
|
||||
public float[] weights;
|
||||
|
||||
[JsonSchema(SkipSchemaComparison = true)]
|
||||
public glTFMesh_extras extras = null;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
public glTFMesh()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,155 @@ namespace UniGLTF
|
|||
const float FRAME_WEIGHT = 100.0f;
|
||||
|
||||
|
||||
// mesh is sharing morph targets.
|
||||
private static MeshContext _ImportMeshSharingMorphTarget(ImporterContext ctx, glTFMesh gltfMesh)
|
||||
{
|
||||
var positions = new List<Vector3>();
|
||||
var normals = new List<Vector3>();
|
||||
var tangents = new List<Vector4>();
|
||||
var uv = new List<Vector2>();
|
||||
var colors = new List<Color>();
|
||||
var blendShapes = new List<BlendShape>();
|
||||
var meshContext = new MeshContext();
|
||||
|
||||
// blendshapes
|
||||
var targetNames = gltfMesh.extras.targetNames;
|
||||
for (int i = 1; i < gltfMesh.primitives.Count; ++i)
|
||||
{
|
||||
if (gltfMesh.primitives[i].targets.Count != targetNames.Count)
|
||||
{
|
||||
throw new FormatException(string.Format("different targets length: {0} with targetNames length.",
|
||||
gltfMesh.primitives[i]));
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < targetNames.Count; i++)
|
||||
{
|
||||
var blendShape = new BlendShape(!string.IsNullOrEmpty(targetNames[i]) ? targetNames[i] : i.ToString());
|
||||
blendShapes.Add(blendShape);
|
||||
}
|
||||
|
||||
foreach (var prim in gltfMesh.primitives)
|
||||
{
|
||||
var indexOffset = positions.Count;
|
||||
var indexBuffer = prim.indices;
|
||||
|
||||
var positionCount = positions.Count;
|
||||
positions.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector3>(prim.attributes.POSITION).Select(x => x.ReverseZ()));
|
||||
positionCount = positions.Count - positionCount;
|
||||
|
||||
// normal
|
||||
if (prim.attributes.NORMAL != -1)
|
||||
{
|
||||
normals.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector3>(prim.attributes.NORMAL).Select(x => x.ReverseZ()));
|
||||
}
|
||||
|
||||
if (prim.attributes.TANGENT != -1)
|
||||
{
|
||||
tangents.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector4>(prim.attributes.TANGENT).Select(x => x.ReverseZ()));
|
||||
}
|
||||
|
||||
// uv
|
||||
if (prim.attributes.TEXCOORD_0 != -1)
|
||||
{
|
||||
if (ctx.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
{
|
||||
#pragma warning disable 0612
|
||||
// backward compatibility
|
||||
uv.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY()));
|
||||
#pragma warning restore 0612
|
||||
}
|
||||
else
|
||||
{
|
||||
uv.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseUV()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// for inconsistent attributes in primitives
|
||||
uv.AddRange(new Vector2[positionCount]);
|
||||
}
|
||||
|
||||
// color
|
||||
if (prim.attributes.COLOR_0 != -1)
|
||||
{
|
||||
colors.AddRange(ctx.GLTF.GetArrayFromAccessor<Color>(prim.attributes.COLOR_0));
|
||||
}
|
||||
|
||||
// skin
|
||||
if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1)
|
||||
{
|
||||
var joints0 = ctx.GLTF.GetArrayFromAccessor<UShort4>(prim.attributes.JOINTS_0); // uint4
|
||||
var weights0 = ctx.GLTF.GetArrayFromAccessor<Float4>(prim.attributes.WEIGHTS_0).Select(x => x.One()).ToArray();
|
||||
|
||||
for (int j = 0; j < joints0.Length; ++j)
|
||||
{
|
||||
var bw = new BoneWeight();
|
||||
|
||||
bw.boneIndex0 = joints0[j].x;
|
||||
bw.weight0 = weights0[j].x;
|
||||
|
||||
bw.boneIndex1 = joints0[j].y;
|
||||
bw.weight1 = weights0[j].y;
|
||||
|
||||
bw.boneIndex2 = joints0[j].z;
|
||||
bw.weight2 = weights0[j].z;
|
||||
|
||||
bw.boneIndex3 = joints0[j].w;
|
||||
bw.weight3 = weights0[j].w;
|
||||
|
||||
meshContext.boneWeights.Add(bw);
|
||||
}
|
||||
}
|
||||
|
||||
// blendshape
|
||||
if (prim.targets != null && prim.targets.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < prim.targets.Count; ++i)
|
||||
{
|
||||
var primTarget = prim.targets[i];
|
||||
if (primTarget.POSITION != -1)
|
||||
{
|
||||
blendShapes[i].Positions.AddRange(
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray());
|
||||
}
|
||||
if (primTarget.NORMAL != -1)
|
||||
{
|
||||
blendShapes[i].Normals.AddRange(
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray());
|
||||
}
|
||||
if (primTarget.TANGENT != -1)
|
||||
{
|
||||
blendShapes[i].Tangents.AddRange(
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var indices =
|
||||
(indexBuffer >= 0)
|
||||
? ctx.GLTF.GetIndices(indexBuffer)
|
||||
: TriangleUtil.FlipTriangle(Enumerable.Range(0, meshContext.positions.Length)).ToArray() // without index array
|
||||
;
|
||||
for (int i = 0; i < indices.Length; ++i)
|
||||
{
|
||||
indices[i] += indexOffset;
|
||||
}
|
||||
|
||||
meshContext.subMeshes.Add(indices);
|
||||
|
||||
// material
|
||||
meshContext.materialIndices.Add(prim.material);
|
||||
}
|
||||
|
||||
meshContext.positions = positions.ToArray();
|
||||
meshContext.normals = normals.ToArray();
|
||||
meshContext.tangents = tangents.ToArray();
|
||||
meshContext.uv = uv.ToArray();
|
||||
meshContext.blendShapes = blendShapes;
|
||||
|
||||
return meshContext;
|
||||
}
|
||||
|
||||
// multiple submMesh is not sharing a VertexBuffer.
|
||||
// each subMesh use a independent VertexBuffer.
|
||||
private static MeshContext _ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh)
|
||||
|
|
@ -352,22 +501,33 @@ namespace UniGLTF
|
|||
public MeshContext ReadMesh(ImporterContext ctx, int meshIndex)
|
||||
{
|
||||
var gltfMesh = ctx.GLTF.meshes[meshIndex];
|
||||
glTFAttributes lastAttributes = null;
|
||||
var sharedAttributes = true;
|
||||
foreach (var prim in gltfMesh.primitives)
|
||||
|
||||
bool sharedMorphTarget = gltfMesh.extras != null && gltfMesh.extras.targetNames.Count > 0;
|
||||
MeshContext meshContext;
|
||||
if (sharedMorphTarget)
|
||||
{
|
||||
if (lastAttributes != null && !prim.attributes.Equals(lastAttributes))
|
||||
meshContext = _ImportMeshSharingMorphTarget(ctx, gltfMesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTFAttributes lastAttributes = null;
|
||||
var sharedAttributes = true;
|
||||
foreach (var prim in gltfMesh.primitives)
|
||||
{
|
||||
sharedAttributes = false;
|
||||
break;
|
||||
if (lastAttributes != null && !prim.attributes.Equals(lastAttributes))
|
||||
{
|
||||
sharedAttributes = false;
|
||||
break;
|
||||
}
|
||||
|
||||
lastAttributes = prim.attributes;
|
||||
}
|
||||
lastAttributes = prim.attributes;
|
||||
|
||||
meshContext = sharedAttributes
|
||||
? _ImportMeshSharingVertexBuffer(ctx, gltfMesh)
|
||||
: _ImportMeshIndependentVertexBuffer(ctx, gltfMesh);
|
||||
}
|
||||
|
||||
var meshContext = sharedAttributes
|
||||
? _ImportMeshSharingVertexBuffer(ctx, gltfMesh)
|
||||
: _ImportMeshIndependentVertexBuffer(ctx, gltfMesh)
|
||||
;
|
||||
meshContext.name = gltfMesh.name;
|
||||
if (string.IsNullOrEmpty(meshContext.name))
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user