static void BuildBlendShape(Mesh mesh, MeshContext meshContext, BlendShape blendShape, Vector3[] emptyVertices) { if (blendShape.Positions.Count > 0) { if (blendShape.Positions.Count == mesh.vertexCount) { mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, blendShape.Positions.ToArray(), (meshContext.Normals.Count == mesh.vertexCount && blendShape.Normals.Count == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, null ); } else { Debug.LogWarningFormat("May be partial primitive has blendShape. Require separate mesh or extend blend shape, but not implemented: {0}", blendShape.Name); } } else { // Debug.LogFormat("empty blendshape: {0}.{1}", mesh.name, blendShape.Name); // add empty blend shape for keep blend shape index mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, emptyVertices, null, null ); } }
private BlendShape GetOrCreateBlendShape(int i) { if (i < _blendShapes.Count && _blendShapes[i] != null) { return(_blendShapes[i]); } while (_blendShapes.Count <= i) { _blendShapes.Add(null); } var blendShape = new BlendShape(i.ToString()); _blendShapes[i] = blendShape; return(blendShape); }
// multiple submMesh is not sharing a VertexBuffer. // each subMesh use a independent VertexBuffer. private static MeshContext _ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) { //Debug.LogWarning("_ImportMeshIndependentVertexBuffer"); var targets = gltfMesh.primitives[0].targets; for (int i = 1; i < gltfMesh.primitives.Count; ++i) { if (!gltfMesh.primitives[i].targets.SequenceEqual(targets)) { throw new NotImplementedException(string.Format("diffirent targets: {0} with {1}", gltfMesh.primitives[i], targets)); } } 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 meshContext = new MeshContext(); 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) { uv.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY())); } 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 name = string.Format("target{0}", i++); var primTarget = prim.targets[i]; var blendShape = new BlendShape(!string.IsNullOrEmpty(prim.extras.targetNames[i]) ? prim.extras.targetNames[i] : i.ToString()) ; if (primTarget.POSITION != -1) { blendShape.Positions.AddRange( ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.NORMAL != -1) { blendShape.Normals.AddRange( ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.TANGENT != -1) { blendShape.Tangents.AddRange( ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); } meshContext.blendShapes.Add(blendShape); } } 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(); return(meshContext); }
// 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); }
private static async Task BuildBlendShapeAsync(IAwaitCaller awaitCaller, Mesh mesh, BlendShape blendShape, Vector3[] emptyVertices) { Vector3[] positions = null; Vector3[] normals = null; await awaitCaller.Run(() => { positions = blendShape.Positions.ToArray(); normals = blendShape.Normals.ToArray(); }); Profiler.BeginSample("MeshImporter.BuildBlendShapeAsync"); if (blendShape.Positions.Count > 0) { if (blendShape.Positions.Count == mesh.vertexCount) { mesh.AddBlendShapeFrame(blendShape.Name, FrameWeight, blendShape.Positions.ToArray(), normals.Length == mesh.vertexCount && normals.Length == positions.Length ? normals : null, null ); } else { Debug.LogWarningFormat( "May be partial primitive has blendShape. Require separate mesh or extend blend shape, but not implemented: {0}", blendShape.Name); } } else { // Debug.LogFormat("empty blendshape: {0}.{1}", mesh.name, blendShape.Name); // add empty blend shape for keep blend shape index mesh.AddBlendShapeFrame(blendShape.Name, FrameWeight, emptyVertices, null, null ); } Profiler.EndSample(); }
/// <summary> /// 各 primitive の attribute の要素が同じでない。=> uv が有るものと無いものが混在するなど /// glTF 的にはありうる。 /// /// primitive を独立した(Independent) Mesh として扱いこれを連結する。 /// </summary> /// <param name="ctx"></param> /// <param name="gltfMesh"></param> /// <returns></returns> public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) { foreach (var prim in gltfMesh.primitives) { var indexOffset = m_positions.Count; var indexBuffer = prim.indices; // position は必ずある var positionCount = m_positions.Count; m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector3>(prim.attributes.POSITION).Select(x => x.ReverseZ())); positionCount = m_positions.Count - positionCount; // normal if (prim.attributes.NORMAL != -1) { FillZero(m_normals); m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector3>(prim.attributes.NORMAL).Select(x => x.ReverseZ())); } #if false if (prim.attributes.TANGENT != -1) { FillZero(tangetns); tangents.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector4>(prim.attributes.TANGENT).Select(x => x.ReverseZ())); } #endif // uv if (prim.attributes.TEXCOORD_0 != -1) { FillZero(m_uv); if (ctx.IsGeneratedUniGLTFAndOlder(1, 16)) { #pragma warning disable 0612 // backward compatibility m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY())); #pragma warning restore 0612 } else { m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseUV())); } } // uv2 if (prim.attributes.TEXCOORD_1 != -1) { FillZero(m_uv2); m_uv2.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); } // color if (prim.attributes.COLOR_0 != -1) { FillZero(m_colors); m_colors.AddRange(ctx.GLTF.GetArrayFromAccessor <Color>(prim.attributes.COLOR_0)); } // skin if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) { FillZero(m_boneWeights); 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; m_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]; var blendShape = new BlendShape(i.ToString()); if (primTarget.POSITION != -1) { FillZero(blendShape.Positions); blendShape.Positions.AddRange( ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.NORMAL != -1) { FillZero(blendShape.Normals); blendShape.Normals.AddRange( ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.TANGENT != -1) { FillZero(blendShape.Tangents); blendShape.Tangents.AddRange( ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); } m_blendShapes.Add(blendShape); } } var indices = (indexBuffer >= 0) ? ctx.GLTF.GetIndices(indexBuffer) : TriangleUtil.FlipTriangle(Enumerable.Range(0, m_positions.Count)).ToArray() // without index array ; for (int i = 0; i < indices.Length; ++i) { indices[i] += indexOffset; } m_subMeshes.Add(indices); // material m_materialIndices.Add(prim.material); } }
/// <summary> /// /// 各primitiveが同じ attribute を共有している場合専用のローダー。 /// /// </summary> /// <param name="ctx"></param> /// <param name="gltfMesh"></param> /// <returns></returns> private void ImportMeshSharingVertexBuffer(GltfData data, glTFMesh gltfMesh, IAxisInverter inverter) { var isOldVersion = data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16); { // 同じVertexBufferを共有しているので先頭のモノを使う var primitives = gltfMesh.primitives.First(); var positions = primitives.GetPositions(data); var normals = primitives.GetNormals(data, positions.Length); var texCoords0 = primitives.GetTexCoords0(data, positions.Length); var texCoords1 = primitives.GetTexCoords1(data, positions.Length); var colors = primitives.GetColors(data, positions.Length); var skinning = SkinningInfo.Create(data, gltfMesh, primitives); AssignBoneWeight = skinning.ShouldSetRendererNodeAsBone; CheckAttributeUsages(primitives); for (var i = 0; i < positions.Length; ++i) { var position = inverter.InvertVector3(positions[i]); var normal = normals != null?inverter.InvertVector3(normals.Value[i]) : Vector3.zero; var texCoord0 = Vector2.zero; if (texCoords0 != null) { if (isOldVersion) { #pragma warning disable 0612 texCoord0 = texCoords0.Value[i].ReverseY(); #pragma warning restore 0612 } else { texCoord0 = texCoords0.Value[i].ReverseUV(); } } var texCoord1 = texCoords1 != null ? texCoords1.Value[i].ReverseUV() : Vector2.zero; var color = colors != null ? colors.Value[i] : Color.white; AddVertex( new MeshVertex( position, normal, texCoord0, texCoord1, color)); var skin = skinning.GetSkinnedVertex(i); if (skin.HasValue) { AddSkin(skin.Value); } } // blendshape if (primitives.targets != null && primitives.targets.Count > 0) { for (int i = 0; i < primitives.targets.Count; ++i) { var primTarget = primitives.targets[i]; var hasPosition = primTarget.POSITION != -1 && data.GLTF.accessors[primTarget.POSITION].count == positions.Length; var hasNormal = primTarget.NORMAL != -1 && data.GLTF.accessors[primTarget.NORMAL].count == positions.Length; var hasTangent = primTarget.TANGENT != -1 && data.GLTF.accessors[primTarget.TANGENT].count == positions.Length; var blendShape = new BlendShape(i.ToString(), positions.Length, hasPosition, hasNormal, hasTangent); _blendShapes.Add(blendShape); if (hasPosition) { var morphPositions = data.GetArrayFromAccessor <Vector3>(primTarget.POSITION); blendShape.Positions.Capacity = morphPositions.Length; for (var j = 0; j < positions.Length; ++j) { blendShape.Positions.Add(inverter.InvertVector3(morphPositions[j])); } } if (hasNormal) { var morphNormals = data.GetArrayFromAccessor <Vector3>(primTarget.NORMAL); blendShape.Normals.Capacity = morphNormals.Length; for (var j = 0; j < positions.Length; ++j) { blendShape.Normals.Add(inverter.InvertVector3(morphNormals[j])); } } if (hasTangent) { var morphTangents = data.GetArrayFromAccessor <Vector3>(primTarget.TANGENT); blendShape.Tangents.Capacity = morphTangents.Length; for (var j = 0; j < positions.Length; ++j) { blendShape.Tangents.Add(inverter.InvertVector3(morphTangents[j])); } } } } } foreach (var primitive in gltfMesh.primitives) { if (primitive.indices >= 0) { var indexOffset = _currentIndexCount; var indices = data.GetIndicesFromAccessorIndex(primitive.indices); PushIndices(indices, 0); _subMeshes.Add(new SubMeshDescriptor(indexOffset, indices.Count)); } else { var indexOffset = _currentIndexCount; var positions = data.GLTF.accessors[primitive.attributes.POSITION]; for (int i = 0; i < positions.count; i += 3) { // flip triangle AddIndex(i + 2); AddIndex(i + 1); AddIndex(i); } _subMeshes.Add(new SubMeshDescriptor(indexOffset, positions.count)); } // material _materialIndices.Add(primitive.material); } }