Merge pull request #380 from mkc1370/support_mesh_sharing_morph_target

Support mesh sharing morph target
This commit is contained in:
ousttrue 2020-02-26 15:32:30 +09:00 committed by GitHub
commit ed255dbc77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 209 additions and 12 deletions

View File

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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 97b77d4c1c0d44b594e9187e41b3152d
timeCreated: 1582269878

View File

@ -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()
{

View File

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