示例#1
0
        public void MeshTest()
        {
            var model = new glTFMesh("mesh")
            {
                primitives = new List <glTFPrimitives>
                {
                    new glTFPrimitives
                    {
                        attributes = new glTFAttributes
                        {
                            POSITION = 0,
                        }
                    }
                },
            };

            var json = model.ToJson();

            Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""indices"":-1,""attributes"":{""POSITION"":0},""material"":0}]}", json);
            Debug.Log(json);

            var c = new JsonSchemaValidationContext("")
            {
                EnableDiagnosisForNotRequiredFields = true,
            };
            var json2 = JsonSchema.FromType <glTFMesh>().Serialize(model, c);

            Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""attributes"":{""POSITION"":0},""material"":0}]}", json2);
        }
示例#2
0
        public static bool TryGet(glTFMesh mesh, out List <string> targetNames)
        {
            if (mesh.extras is glTFExtensionImport meshExtras)
            {
                foreach (var kv in meshExtras.ObjectItems())
                {
                    if (kv.Key.GetUtf8String() == ExtraNameUtf8)
                    {
                        targetNames = Deserialize(kv.Value);
                        return(true);
                    }
                }
            }

            // use first primitive
            if (mesh.primitives.Count > 0 && mesh.primitives[0].extras is glTFExtensionImport primExtras)
            {
                foreach (var kv in primExtras.ObjectItems())
                {
                    if (kv.Key.GetUtf8String() == ExtraNameUtf8)
                    {
                        targetNames = Deserialize(kv.Value);
                        return(true);
                    }
                }
            }

            targetNames = default;
            return(false);
        }
        public static string ToJson(this glTFMesh self)
        {
            var f = new JsonFormatter();

            GltfSerializer.Serialize_gltf_meshes_ITEM(f, self);
            return(f.ToString());
        }
示例#4
0
        /// <summary>
        /// バッファ共有方式(vrm-0.x)の判定。
        /// import の後方互換性のためで、vrm-1.0 export では使いません。
        ///
        /// * バッファ共用方式は VertexBuffer が同じでSubMeshの index buffer がスライドしていく方式
        /// * バッファがひとつのとき
        /// * すべての primitive の attribute が 同一の accessor を使用している時
        ///
        /// </summary>
        private static bool HasSharedVertexBuffer(glTFMesh gltfMesh)
        {
            glTFAttributes lastAttributes = null;

            foreach (var prim in gltfMesh.primitives)
            {
                if (lastAttributes != null && !prim.attributes.Equals(lastAttributes))
                {
                    return(false);
                }
                lastAttributes = prim.attributes;
            }
            return(true);
        }
示例#5
0
 public void RenameBlendShape(glTFMesh gltfMesh)
 {
     if (gltf_mesh_extras_targetNames.TryGet(gltfMesh, out List <string> targetNames))
     {
         for (var i = 0; i < BlendShapes.Count; i++)
         {
             if (i >= targetNames.Count)
             {
                 Debug.LogWarning($"invalid primitive.extras.targetNames length");
                 break;
             }
             BlendShapes[i].Name = targetNames[i];
         }
     }
 }
示例#6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="mesh"></param>
        /// <param name="gltf"></param>
        /// <param name="bufferIndex"></param>
        /// <param name="unityMesh"></param>
        /// <param name="unityMaterials"></param>
        /// <param name="settings"></param>
        /// <param name="axisInverter"></param>
        /// <returns></returns>
        public static (glTFMesh mesh, Dictionary <int, int> blendShapeIndexMap) ExportMesh(glTF gltf, int bufferIndex,
                                                                                           MeshWithRenderer unityMesh, List <Material> unityMaterials,
                                                                                           MeshExportSettings settings, IAxisInverter axisInverter)
        {
            glTFMesh gltfMesh           = default;
            var      blendShapeIndexMap = new Dictionary <int, int>();

            if (settings.DivideVertexBuffer)
            {
                gltfMesh = MeshExporterDivided.Export(gltf, bufferIndex, unityMesh, unityMaterials, axisInverter, settings);
            }
            else
            {
                gltfMesh = ExportSharedVertexBuffer(gltf, bufferIndex, unityMesh, unityMaterials, axisInverter, settings);

                var targetNames = new List <string>();

                int exportBlendShapes = 0;
                for (int j = 0; j < unityMesh.Mesh.blendShapeCount; ++j)
                {
                    var morphTarget = ExportMorphTarget(gltf, bufferIndex,
                                                        unityMesh.Mesh, j,
                                                        settings.UseSparseAccessorForMorphTarget,
                                                        settings.ExportOnlyBlendShapePosition, axisInverter);
                    if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0)
                    {
                        continue;
                    }

                    // maybe skip
                    var blendShapeName = unityMesh.Mesh.GetBlendShapeName(j);
                    blendShapeIndexMap.Add(j, exportBlendShapes++);
                    targetNames.Add(blendShapeName);

                    //
                    // all primitive has same blendShape
                    //
                    for (int k = 0; k < gltfMesh.primitives.Count; ++k)
                    {
                        gltfMesh.primitives[k].targets.Add(morphTarget);
                    }
                }

                gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);
            }

            return(gltfMesh, blendShapeIndexMap);
        }
示例#7
0
        static bool HasSharedVertexBuffer(glTFMesh gltfMesh)
        {
            glTFAttributes lastAttributes   = null;
            var            sharedAttributes = true;

            foreach (var prim in gltfMesh.primitives)
            {
                if (lastAttributes != null && !prim.attributes.Equals(lastAttributes))
                {
                    sharedAttributes = false;
                    break;
                }

                lastAttributes = prim.attributes;
            }
            return(sharedAttributes);
        }
示例#8
0
        private void RenameBlendShape(glTFMesh gltfMesh)
        {
            if (!gltf_mesh_extras_targetNames.TryGet(gltfMesh, out var targetNames))
            {
                return;
            }
            for (var i = 0; i < _blendShapes.Count; i++)
            {
                if (i >= targetNames.Count)
                {
                    Debug.LogWarning($"invalid primitive.extras.targetNames length");
                    break;
                }

                _blendShapes[i].Name = targetNames[i];
            }
        }
示例#9
0
        public static bool TryGet(glTFMesh mesh, out List <string> targetNames)
        {
            if (mesh.extras is glTFExtensionImport meshExtras)
            {
                foreach (var kv in meshExtras.ObjectItems())
                {
                    if (kv.Key.GetUtf8String() == ExtraNameUtf8)
                    {
                        targetNames = Deserialize(kv.Value);
                        return(true);
                    }
                }
            }

            // use first primitive
            if (mesh.primitives.Count > 0 && mesh.primitives[0].extras is glTFExtensionImport primExtras)
            {
                foreach (var kv in primExtras.ObjectItems())
                {
                    if (kv.Key.GetUtf8String() == ExtraNameUtf8)
                    {
                        targetNames = Deserialize(kv.Value);
                        return(true);
                    }
                }
            }

            if (mesh.primitives.Count > 0)
            {
                var prim = mesh.primitives[0];
                if (prim.targets.Count > 0)
                {
                    // 名無しには連番を付ける
                    targetNames = new List <string>();
                    for (int i = 0; i < prim.targets.Count; ++i)
                    {
                        targetNames.Add($"{i}");
                    }
                    return(true);
                }
            }

            targetNames = default;
            return(false);
        }
示例#10
0
            public void RenameBlendShape(glTFMesh gltfMesh)
            {
                if (gltfMesh.extras != null && gltfMesh.extras.targetNames != null)
                {
                    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++)
                    {
                        BlendShapes[i].Name = targetNames[i];
                    }
                    return;
                }

                var prim = gltfMesh.primitives[0];
                {
                    if (prim.extras != null && prim.extras.targetNames != null)
                    {
                        var targetNames = prim.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++)
                        {
                            BlendShapes[i].Name = targetNames[i];
                        }
                    }
                }
            }
        public void MeshTest()
        {
            var model = new glTFMesh("mesh")
            {
                primitives = new List <glTFPrimitives>
                {
                    new glTFPrimitives
                    {
                        indices    = 0,
                        attributes = new glTFAttributes
                        {
                            POSITION = 1,
                        }
                    }
                },
            };

            var json = model.ToJson();

            Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""indices"":0,""attributes"":{""POSITION"":1},""material"":0}]}", json);
            Debug.Log(json);
        }
示例#12
0
        public static void Serialize(glTFMesh gltfMesh, IEnumerable <string> targetNames)
        {
            // targetNames
            var f = new JsonFormatter();

            f.BeginList();
            foreach (var n in targetNames)
            {
                f.Value(n);
            }
            f.EndList();
            var targetNamesJson = f.GetStore().Bytes;

            var meshExtras = glTFExtensionExport.GetOrCreate(ref gltfMesh.extras);

            meshExtras.Add(ExtraName, targetNamesJson);

            foreach (var prim in gltfMesh.primitives)
            {
                var primExtras = glTFExtensionExport.GetOrCreate(ref prim.extras);
                primExtras.Add(ExtraName, targetNamesJson);
            }
        }
示例#13
0
        public static void Serialize_gltf_meshes_ITEM(JsonFormatter f, glTFMesh value)
        {
            f.BeginMap();


            if (!string.IsNullOrEmpty(value.name))
            {
                f.Key("name");
                f.Value(value.name);
            }

            if (value.primitives != null && value.primitives.Count >= 1)
            {
                f.Key("primitives");
                Serialize_gltf_meshes__primitives(f, value.primitives);
            }

            if (value.weights != null && value.weights.Length >= 1)
            {
                f.Key("weights");
                Serialize_gltf_meshes__weights(f, value.weights);
            }

            if (value.extras != null)
            {
                f.Key("extras");
                value.extras.Serialize(f);
            }

            if (value.extensions != null)
            {
                f.Key("extensions");
                value.extensions.Serialize(f);
            }

            f.EndMap();
        }
示例#14
0
        public void MeshTest()
        {
            var mesh = new glTFMesh("mesh")
            {
                primitives = new List <glTFPrimitives>
                {
                    new glTFPrimitives
                    {
                        attributes = new glTFAttributes
                        {
                            POSITION = 0,
                        }
                    }
                }
            };

            var f = new JsonFormatter();

            f.Serialize(mesh);

            var json = new Utf8String(f.GetStoreBytes()).ToString();

            Debug.Log(json);
        }
示例#15
0
        public static (int VertexCapacity, int IndexCapacity) GetCapacity(GltfData data, glTFMesh gltfMesh)
        {
            var vertexCount = 0;
            var indexCount  = 0;

            foreach (var primitive in gltfMesh.primitives)
            {
                var positions = data.GLTF.accessors[primitive.attributes.POSITION];
                vertexCount += positions.count;

                if (primitive.indices == -1)
                {
                    indexCount += positions.count;
                }
                else
                {
                    var accessor = data.GLTF.accessors[primitive.indices];
                    indexCount += accessor.count;
                }
            }
            return(vertexCount, indexCount);
        }
示例#16
0
        // multiple submesh sharing same VertexBuffer
        private static MeshContext _ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh)
        {
            var context = new MeshContext();

            {
                var prim = gltfMesh.primitives.First();
                context.positions = ctx.GLTF.GetArrayFromAccessor <Vector3>(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ());

                // normal
                if (prim.attributes.NORMAL != -1)
                {
                    context.normals = ctx.GLTF.GetArrayFromAccessor <Vector3>(prim.attributes.NORMAL).SelectInplace(x => x.ReverseZ());
                }

                // tangent
                if (prim.attributes.TANGENT != -1)
                {
                    context.tangents = ctx.GLTF.GetArrayFromAccessor <Vector4>(prim.attributes.TANGENT).SelectInplace(x => x.ReverseZ());
                }

                // uv
                if (prim.attributes.TEXCOORD_0 != -1)
                {
                    context.uv = ctx.GLTF.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseY());
                }
                else
                {
                    // for inconsistent attributes in primitives
                    context.uv = new Vector2[context.positions.Length];
                }

                // color
                if (prim.attributes.COLOR_0 != -1)
                {
                    context.colors = 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);
                    for (int i = 0; i < weights0.Length; ++i)
                    {
                        weights0[i] = weights0[i].One();
                    }

                    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;

                        context.boneWeights.Add(bw);
                    }
                }

                // blendshape
                if (prim.targets != null && prim.targets.Count > 0)
                {
                    context.blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape(
                                                                         i < prim.extras.targetNames.Count && !string.IsNullOrEmpty(prim.extras.targetNames[i])
                        ? prim.extras.targetNames[i]
                        : i.ToString())));
                    for (int i = 0; i < prim.targets.Count; ++i)
                    {
                        //var name = string.Format("target{0}", i++);
                        var primTarget = prim.targets[i];
                        var blendShape = context.blendShapes[i];

                        if (primTarget.POSITION != -1)
                        {
                            blendShape.Positions.Assign(
                                ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.POSITION), x => x.ReverseZ());
                        }
                        if (primTarget.NORMAL != -1)
                        {
                            blendShape.Normals.Assign(
                                ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.NORMAL), x => x.ReverseZ());
                        }
                        if (primTarget.TANGENT != -1)
                        {
                            blendShape.Tangents.Assign(
                                ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.TANGENT), x => x.ReverseZ());
                        }
                    }
                }
            }

            foreach (var prim in gltfMesh.primitives)
            {
                if (prim.indices == -1)
                {
                    context.subMeshes.Add(TriangleUtil.FlipTriangle(Enumerable.Range(0, context.positions.Length)).ToArray());
                }
                else
                {
                    var indices = ctx.GLTF.GetIndices(prim.indices);
                    context.subMeshes.Add(indices);
                }

                // material
                context.materialIndices.Add(prim.material);
            }

            return(context);
        }
示例#17
0
        // 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);
        }
        static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex,
                                         MeshWithRenderer unityMesh, List <Material> unityMaterials)
        {
            var mesh                  = unityMesh.Mesh;
            var materials             = unityMesh.Renderer.sharedMaterials;
            var positions             = mesh.vertices.Select(y => y.ReverseZ()).ToArray();
            var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER);

            gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
            gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();

            var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.normalized.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);

#if GLTF_EXPORT_TANGENTS
            var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
#endif
            var uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);
            var uvAccessorIndex1 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv2.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);

            var colorAccessorIndex = -1;

            var vColorState = MeshExportInfo.DetectVertexColor(mesh, materials);
            if (vColorState == MeshExportInfo.VertexColorState.ExistsAndIsUsed || // VColor使っている
                vColorState == MeshExportInfo.VertexColorState.ExistsAndMixed // VColorを使っているところと使っていないところが混在(とりあえずExportする)
                )
            {
                // UniUnlit で Multiply 設定になっている
                colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER);
            }

            var boneweights         = mesh.boneWeights;
            var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
            var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y =>
                                                                                                           new UShort4(
                                                                                                               (ushort)unityMesh.GetJointIndex(y.boneIndex0),
                                                                                                               (ushort)unityMesh.GetJointIndex(y.boneIndex1),
                                                                                                               (ushort)unityMesh.GetJointIndex(y.boneIndex2),
                                                                                                               (ushort)unityMesh.GetJointIndex(y.boneIndex3))
                                                                                                           ).ToArray(), glBufferTarget.ARRAY_BUFFER);

            var attributes = new glTFAttributes
            {
                POSITION = positionAccessorIndex,
            };
            if (normalAccessorIndex != -1)
            {
                attributes.NORMAL = normalAccessorIndex;
            }
#if GLTF_EXPORT_TANGENTS
            if (tangentAccessorIndex != -1)
            {
                attributes.TANGENT = tangentAccessorIndex;
            }
#endif
            if (uvAccessorIndex0 != -1)
            {
                attributes.TEXCOORD_0 = uvAccessorIndex0;
            }
            if (uvAccessorIndex1 != -1)
            {
                attributes.TEXCOORD_1 = uvAccessorIndex1;
            }
            if (colorAccessorIndex != -1)
            {
                attributes.COLOR_0 = colorAccessorIndex;
            }
            if (weightAccessorIndex != -1)
            {
                attributes.WEIGHTS_0 = weightAccessorIndex;
            }
            if (jointsAccessorIndex != -1)
            {
                attributes.JOINTS_0 = jointsAccessorIndex;
            }

            var gltfMesh = new glTFMesh(mesh.name);
            var indices  = new List <uint>();
            for (int j = 0; j < mesh.subMeshCount; ++j)
            {
                indices.Clear();

                var triangles = mesh.GetIndices(j);
                if (triangles.Length == 0)
                {
                    // https://github.com/vrm-c/UniVRM/issues/664
                    continue;
                }

                for (int i = 0; i < triangles.Length; i += 3)
                {
                    var i0 = triangles[i];
                    var i1 = triangles[i + 1];
                    var i2 = triangles[i + 2];

                    // flip triangle
                    indices.Add((uint)i2);
                    indices.Add((uint)i1);
                    indices.Add((uint)i0);
                }

                var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER);
                if (indicesAccessorIndex < 0)
                {
                    // https://github.com/vrm-c/UniVRM/issues/664
                    throw new Exception();
                }

                if (j >= materials.Length)
                {
                    Debug.LogWarningFormat("{0}.materials is not enough", unityMesh.Renderer.name);
                    break;
                }

                gltfMesh.primitives.Add(new glTFPrimitives
                {
                    attributes = attributes,
                    indices    = indicesAccessorIndex,
                    mode       = 4, // triangles ?
                    material   = unityMaterials.IndexOf(materials[j])
                });
            }
            return(gltfMesh);
        }
示例#19
0
        // 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);
        }
示例#20
0
        /// <summary>
        /// 各 primitive の attribute の要素が同じでない。=> uv が有るものと無いものが混在するなど
        /// glTF 的にはありうる。
        ///
        /// primitive を独立した(Independent) Mesh として扱いこれを連結する。
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="gltfMesh"></param>
        /// <returns></returns>
        private void ImportMeshIndependentVertexBuffer(GltfData data, glTFMesh gltfMesh, IAxisInverter inverter)
        {
            bool isOldVersion = data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16);

            foreach (var primitives in gltfMesh.primitives)
            {
                var vertexOffset     = _currentVertexCount;
                var indexBufferCount = primitives.indices;

                // position は必ずある
                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
                            // backward compatibility
                            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 (var i = 0; i < primitives.targets.Count; ++i)
                    {
                        var primTarget = primitives.targets[i];
                        var blendShape = GetOrCreateBlendShape(i);
                        if (primTarget.POSITION != -1)
                        {
                            var array = data.GetArrayFromAccessor <Vector3>(primTarget.POSITION);
                            if (array.Length != positions.Length)
                            {
                                throw new Exception("different length");
                            }

                            blendShape.Positions.AddRange(array.Select(inverter.InvertVector3).ToArray());
                        }

                        if (primTarget.NORMAL != -1)
                        {
                            var array = data.GetArrayFromAccessor <Vector3>(primTarget.NORMAL);
                            if (array.Length != positions.Length)
                            {
                                throw new Exception("different length");
                            }

                            blendShape.Normals.AddRange(array.Select(inverter.InvertVector3).ToArray());
                        }

                        if (primTarget.TANGENT != -1)
                        {
                            var array = data.GetArrayFromAccessor <Vector3>(primTarget.TANGENT);
                            if (array.Length != positions.Length)
                            {
                                throw new Exception("different length");
                            }

                            blendShape.Tangents.AddRange(array.Select(inverter.InvertVector3).ToArray());
                        }
                    }
                }

                if (indexBufferCount >= 0)
                {
                    var indexOffset = _currentIndexCount;
                    var dataIndices = data.GetIndicesFromAccessorIndex(indexBufferCount);
                    PushIndices(dataIndices, vertexOffset);
                    _subMeshes.Add(new SubMeshDescriptor(indexOffset, dataIndices.Count));
                }
                else
                {
                    var indexOffset = _currentIndexCount;
                    for (int i = 0; i < positions.Count(); i += 3)
                    {
                        // flip triangle
                        AddIndex(i + vertexOffset + 2);
                        AddIndex(i + vertexOffset + 1);
                        AddIndex(i + vertexOffset);
                    }
                    _subMeshes.Add(new SubMeshDescriptor(indexOffset, positions.Count()));
                }

                // material
                _materialIndices.Add(primitives.material);
            }
        }
示例#21
0
        public static glTFMesh Export(glTF gltf, int bufferIndex,
            MeshWithRenderer unityMesh, List<Material> unityMaterials,
            IAxisInverter axisInverter, MeshExportSettings settings)
        {
            var mesh = unityMesh.Mesh;
            var gltfMesh = new glTFMesh(mesh.name);

            if (settings.ExportTangents)
            {
                // support しない
                throw new NotImplementedException();
            }

            var positions = mesh.vertices;
            var normals = mesh.normals;
            var uv = mesh.uv;
            var boneWeights = mesh.boneWeights;

            Func<int, int> getJointIndex = null;
            if (boneWeights != null && boneWeights.Length == positions.Length)
            {
                getJointIndex = unityMesh.GetJointIndex;
            }

            Vector3[] blendShapePositions = new Vector3[mesh.vertexCount];
            Vector3[] blendShapeNormals = new Vector3[mesh.vertexCount];

            var usedIndices = new List<int>();
            for (int i = 0; i < mesh.subMeshCount; ++i)
            {
                var indices = mesh.GetIndices(i);

                // mesh
                // index の順に attributes を蓄える                
                var buffer = new MeshExportUtil.VertexBuffer(indices.Length, getJointIndex);
                usedIndices.Clear();
                for (int k = 0; k < positions.Length; ++k)
                {
                    if (indices.Contains(k))
                    {
                        // indices から参照される頂点だけを蓄える
                        usedIndices.Add(k);
                        buffer.Push(k, axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV());
                        if (getJointIndex != null)
                        {
                            buffer.Push(boneWeights[k]);
                        }
                    }
                }

                var material = unityMesh.Renderer.sharedMaterials[i];
                var materialIndex = -1;
                if (material != null)
                {
                    materialIndex = unityMaterials.IndexOf(material);
                }

                var flipped = new List<int>();
                for (int j = 0; j < indices.Length; j += 3)
                {
                    var t0 = indices[j];
                    var t1 = indices[j + 1];
                    var t2 = indices[j + 2];
                    flipped.Add(t2);
                    flipped.Add(t1);
                    flipped.Add(t0);
                }
                var gltfPrimitive = buffer.ToGltfPrimitive(gltf, bufferIndex, materialIndex, flipped);

                // blendShape
                for (int j = 0; j < mesh.blendShapeCount; ++j)
                {
                    var blendShape = new MeshExportUtil.BlendShapeBuffer(indices.Length);

                    // index の順に attributes を蓄える                
                    mesh.GetBlendShapeFrameVertices(j, 0, blendShapePositions, blendShapeNormals, null);
                    foreach (var k in usedIndices)
                    {
                        blendShape.Push(
                            axisInverter.InvertVector3(blendShapePositions[k]),
                            axisInverter.InvertVector3(blendShapeNormals[k]));
                    }

                    gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, bufferIndex, !settings.ExportOnlyBlendShapePosition));
                }

                gltfMesh.primitives.Add(gltfPrimitive);
            }

            var targetNames = Enumerable.Range(0, mesh.blendShapeCount).Select(x => mesh.GetBlendShapeName(x)).ToArray();
            gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);

            return gltfMesh;
        }
        /// <summary>
        /// primitive 間で vertex を共有する形で Export する。
        /// UniVRM-0.71.0 以降は、MeshExporterDivided.Export もある。
        ///
        /// * GLB/GLTF は shared(default) と divided を選択可能
        /// * VRM0 は shared 仕様
        /// * VRM1 は divided 仕様
        ///
        /// /// </summary>
        /// <param name="gltf"></param>
        /// <param name="bufferIndex"></param>
        /// <param name="unityMesh"></param>
        /// <param name="unityMaterials"></param>
        /// <param name="axisInverter"></param>
        /// <param name="settings"></param>
        /// <returns></returns>
        public static (glTFMesh, Dictionary <int, int> blendShapeIndexMap) Export(ExportingGltfData data,
                                                                                  MeshExportInfo unityMesh, List <Material> unityMaterials,
                                                                                  IAxisInverter axisInverter, GltfExportSettings settings)
        {
            var mesh                  = unityMesh.Mesh;
            var materials             = unityMesh.Materials;
            var positions             = mesh.vertices.Select(axisInverter.InvertVector3).ToArray();
            var positionAccessorIndex = data.ExtendBufferAndGetAccessorIndex(positions, glBufferTarget.ARRAY_BUFFER);

            data.GLTF.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
            data.GLTF.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();

            var normalAccessorIndex = data.ExtendBufferAndGetAccessorIndex(mesh.normals.Select(y => axisInverter.InvertVector3(y.normalized)).ToArray(), glBufferTarget.ARRAY_BUFFER);

            int?tangentAccessorIndex = default;

            if (settings.ExportTangents)
            {
                tangentAccessorIndex = data.ExtendBufferAndGetAccessorIndex(mesh.tangents.Select(axisInverter.InvertVector4).ToArray(), glBufferTarget.ARRAY_BUFFER);
            }

            var uvAccessorIndex0 = data.ExtendBufferAndGetAccessorIndex(mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);
            var uvAccessorIndex1 = data.ExtendBufferAndGetAccessorIndex(mesh.uv2.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);

            var colorAccessorIndex = -1;

            var vColorState = VertexColorUtility.DetectVertexColor(mesh, materials);

            if (vColorState == VertexColorState.ExistsAndIsUsed || // VColor使っている
                vColorState == VertexColorState.ExistsAndMixed // VColorを使っているところと使っていないところが混在(とりあえずExportする)
                )
            {
                // UniUnlit で Multiply 設定になっている
                colorAccessorIndex = data.ExtendBufferAndGetAccessorIndex(mesh.colors, glBufferTarget.ARRAY_BUFFER);
            }

            var boneweights         = mesh.boneWeights;
            var weightAccessorIndex = data.ExtendBufferAndGetAccessorIndex(boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
            var jointsAccessorIndex = data.ExtendBufferAndGetAccessorIndex(boneweights.Select(y =>
                                                                                              new UShort4(
                                                                                                  (ushort)unityMesh.GetJointIndex(y.boneIndex0),
                                                                                                  (ushort)unityMesh.GetJointIndex(y.boneIndex1),
                                                                                                  (ushort)unityMesh.GetJointIndex(y.boneIndex2),
                                                                                                  (ushort)unityMesh.GetJointIndex(y.boneIndex3))
                                                                                              ).ToArray(), glBufferTarget.ARRAY_BUFFER);

            var attributes = new glTFAttributes
            {
                POSITION = positionAccessorIndex,
            };

            if (normalAccessorIndex != -1)
            {
                attributes.NORMAL = normalAccessorIndex;
            }

            if (tangentAccessorIndex.HasValue)
            {
                attributes.TANGENT = tangentAccessorIndex.Value;
            }

            if (uvAccessorIndex0 != -1)
            {
                attributes.TEXCOORD_0 = uvAccessorIndex0;
            }
            if (uvAccessorIndex1 != -1)
            {
                attributes.TEXCOORD_1 = uvAccessorIndex1;
            }
            if (colorAccessorIndex != -1)
            {
                attributes.COLOR_0 = colorAccessorIndex;
            }
            if (weightAccessorIndex != -1)
            {
                attributes.WEIGHTS_0 = weightAccessorIndex;
            }
            if (jointsAccessorIndex != -1)
            {
                attributes.JOINTS_0 = jointsAccessorIndex;
            }

            var gltfMesh = new glTFMesh(mesh.name);
            var indices  = new List <uint>();

            for (int j = 0; j < mesh.subMeshCount; ++j)
            {
                indices.Clear();

                var triangles = mesh.GetIndices(j);
                if (triangles.Length == 0)
                {
                    // https://github.com/vrm-c/UniVRM/issues/664
                    continue;
                }

                for (int i = 0; i < triangles.Length; i += 3)
                {
                    var i0 = triangles[i];
                    var i1 = triangles[i + 1];
                    var i2 = triangles[i + 2];

                    // flip triangle
                    indices.Add((uint)i2);
                    indices.Add((uint)i1);
                    indices.Add((uint)i0);
                }

                var indicesAccessorIndex = data.ExtendBufferAndGetAccessorIndex(indices.ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER);
                if (indicesAccessorIndex < 0)
                {
                    // https://github.com/vrm-c/UniVRM/issues/664
                    throw new Exception();
                }

                if (j >= materials.Length)
                {
                    Debug.LogWarningFormat("{0}.materials is not enough", unityMesh.Mesh.name);
                    break;
                }

                gltfMesh.primitives.Add(new glTFPrimitives
                {
                    attributes = attributes,
                    indices    = indicesAccessorIndex,
                    mode       = 4, // triangles ?
                    material   = unityMaterials.IndexOf(materials[j])
                });
            }

            var blendShapeIndexMap = new Dictionary <int, int>();

            {
                var targetNames = new List <string>();

                int exportBlendShapes = 0;
                for (int j = 0; j < unityMesh.Mesh.blendShapeCount; ++j)
                {
                    var morphTarget = ExportMorphTarget(data,
                                                        unityMesh.Mesh, j,
                                                        settings.UseSparseAccessorForMorphTarget,
                                                        settings.ExportOnlyBlendShapePosition, axisInverter);
                    if (morphTarget.POSITION < 0)
                    {
                        // Skip empty blendShape.
                        // Shift blendShape's index.
                        continue;
                    }

                    var blendShapeName = unityMesh.Mesh.GetBlendShapeName(j);
                    blendShapeIndexMap.Add(j, exportBlendShapes++);
                    targetNames.Add(blendShapeName);

                    //
                    // all primitive has same blendShape
                    //
                    for (int k = 0; k < gltfMesh.primitives.Count; ++k)
                    {
                        gltfMesh.primitives[k].targets.Add(morphTarget);
                    }
                }

                gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);
            }

            return(gltfMesh, blendShapeIndexMap);
        }
示例#23
0
        /// <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);
            }
        }
示例#24
0
        /// <summary>
        /// Divide vertex buffer(Position, Normal, UV, VertexColor, Skinning and BlendShapes) by submesh usage, then export
        /// </summary>
        /// <param name="gltf"></param>
        /// <param name="gltfBuffer"></param>
        /// <param name="unityMesh"></param>
        /// <param name="unityMaterials"></param>
        /// <param name="axisInverter"></param>
        /// <param name="settings"></param>
        /// <returns></returns>
        public static (glTFMesh, Dictionary <int, int>) Export(glTF gltf, int gltfBuffer,
                                                               MeshExportInfo unityMesh, List <Material> unityMaterials,
                                                               IAxisInverter axisInverter, GltfExportSettings settings)
        {
            var mesh     = unityMesh.Mesh;
            var gltfMesh = new glTFMesh(mesh.name);

            if (settings.ExportTangents)
            {
                // no support
                throw new NotImplementedException();
            }

            var positions   = mesh.vertices;
            var normals     = mesh.normals;
            var uv          = mesh.uv;
            var boneWeights = mesh.boneWeights;

            Func <int, int> getJointIndex = null;

            if (boneWeights != null && boneWeights.Length == positions.Length)
            {
                getJointIndex = unityMesh.GetJointIndex;
            }

            Vector3[] blendShapePositions = new Vector3[mesh.vertexCount];
            Vector3[] blendShapeNormals   = new Vector3[mesh.vertexCount];

            var usedIndices = new List <int>();

            for (int i = 0; i < mesh.subMeshCount; ++i)
            {
                var indices = mesh.GetIndices(i);
                var hash    = new HashSet <int>(indices);

                // aggrigate vertex attributes
                var buffer = new MeshExportUtil.VertexBuffer(indices.Length, getJointIndex);
                usedIndices.Clear();
                for (int k = 0; k < positions.Length; ++k)
                {
                    if (hash.Contains(k))
                    {
                        // aggrigate indices
                        usedIndices.Add(k);
                        buffer.Push(k, axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV());
                        if (getJointIndex != null)
                        {
                            buffer.Push(boneWeights[k]);
                        }
                    }
                }

                var material      = unityMesh.Materials[i];
                var materialIndex = -1;
                if (material != null)
                {
                    materialIndex = unityMaterials.IndexOf(material);
                }

                var flipped = new List <int>();
                for (int j = 0; j < indices.Length; j += 3)
                {
                    var t0 = indices[j];
                    var t1 = indices[j + 1];
                    var t2 = indices[j + 2];
                    flipped.Add(t2);
                    flipped.Add(t1);
                    flipped.Add(t0);
                }
                var gltfPrimitive = buffer.ToGltfPrimitive(gltf, gltfBuffer, materialIndex, flipped);

                // blendShape(morph target)
                for (int j = 0; j < mesh.blendShapeCount; ++j)
                {
                    var blendShape = new MeshExportUtil.BlendShapeBuffer(usedIndices.Count);

                    // aggriage morph target
                    mesh.GetBlendShapeFrameVertices(j, 0, blendShapePositions, blendShapeNormals, null);
                    int l = 0;
                    foreach (var k in usedIndices)
                    {
                        blendShape.Set(l++,
                                       axisInverter.InvertVector3(blendShapePositions[k]),
                                       axisInverter.InvertVector3(blendShapeNormals[k]));
                    }

                    gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, gltfBuffer, !settings.ExportOnlyBlendShapePosition,
                                                                settings.UseSparseAccessorForMorphTarget));
                }

                gltfMesh.primitives.Add(gltfPrimitive);
            }

            var targetNames = Enumerable.Range(0, mesh.blendShapeCount).Select(x => mesh.GetBlendShapeName(x)).ToArray();

            gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);

            return(gltfMesh, Enumerable.Range(0, mesh.blendShapeCount).ToDictionary(x => x, x => x));
        }
        /// <summary>
        /// Divide vertex buffer(Position, Normal, UV, VertexColor, Skinning and BlendShapes) by submesh usage, then export
        /// </summary>
        /// <param name="gltf"></param>
        /// <param name="gltfBuffer"></param>
        /// <param name="unityMesh"></param>
        /// <param name="unityMaterials"></param>
        /// <param name="axisInverter"></param>
        /// <param name="settings"></param>
        /// <returns></returns>
        public static (glTFMesh, Dictionary <int, int>) Export(ExportingGltfData data,
                                                               MeshExportInfo unityMesh, List <Material> unityMaterials,
                                                               IAxisInverter axisInverter, GltfExportSettings settings)
        {
            var mesh     = unityMesh.Mesh;
            var gltfMesh = new glTFMesh(mesh.name);

            if (settings.ExportTangents)
            {
                // no support
                throw new NotImplementedException();
            }

            var positions   = mesh.vertices;
            var normals     = mesh.normals;
            var uv          = mesh.uv;
            var boneWeights = mesh.boneWeights;

            if (boneWeights.All(x => x.weight0 == 0 && x.weight1 == 0 && x.weight2 == 0 && x.weight3 == 0))
            {
                boneWeights = null;
            }
            var colors = mesh.colors;

            Func <int, int> getJointIndex = null;

            if (boneWeights != null && boneWeights.Length == positions.Length)
            {
                getJointIndex = unityMesh.GetJointIndex;
            }

            Vector3[] blendShapePositions = new Vector3[mesh.vertexCount];
            Vector3[] blendShapeNormals   = new Vector3[mesh.vertexCount];

            var vColorState       = VertexColorUtility.DetectVertexColor(mesh, unityMaterials);
            var exportVertexColor = (
                (settings.KeepVertexColor && mesh.colors != null && mesh.colors.Length == mesh.vertexCount) || // vertex color を残す設定
                vColorState == VertexColorState.ExistsAndIsUsed || // VColor使っている
                vColorState == VertexColorState.ExistsAndMixed    // VColorを使っているところと使っていないところが混在(とりあえずExportする)
                );

            var usedIndices = new List <int>();

            for (int i = 0; i < mesh.subMeshCount; ++i)
            {
                var indices = mesh.GetIndices(i);
                var hash    = new HashSet <int>(indices);

                // aggregate vertex attributes
                var buffer = new MeshExportUtil.VertexBuffer(indices.Length, getJointIndex);
                usedIndices.Clear();
                for (int k = 0; k < positions.Length; ++k)
                {
                    if (hash.Contains(k))
                    {
                        // aggregate indices
                        usedIndices.Add(k);
                        buffer.PushVertex(k,
                                          axisInverter.InvertVector3(positions[k]), // POSITION
                                          axisInverter.InvertVector3(normals[k]),   // NORMAL
                                          uv[k].ReverseUV()                         // UV
                                          );
                        if (getJointIndex != null)
                        {
                            buffer.PushBoneWeight(boneWeights[k]);
                        }
                        if (exportVertexColor)
                        {
                            buffer.PushColor(colors[k]);
                        }
                    }
                }

                var material      = unityMesh.Materials[i];
                var materialIndex = -1;
                if (material != null)
                {
                    materialIndex = unityMaterials.IndexOf(material);
                }

                var flipped = new List <int>();
                for (int j = 0; j < indices.Length; j += 3)
                {
                    var t0 = indices[j];
                    var t1 = indices[j + 1];
                    var t2 = indices[j + 2];
                    flipped.Add(t2);
                    flipped.Add(t1);
                    flipped.Add(t0);
                }
                var gltfPrimitive = buffer.ToGltfPrimitive(data, materialIndex, flipped);

                // blendShape(morph target)
                for (int j = 0; j < mesh.blendShapeCount; ++j)
                {
                    var blendShape = new MeshExportUtil.BlendShapeBuffer(usedIndices.Count);

                    // aggriage morph target
                    mesh.GetBlendShapeFrameVertices(j, 0, blendShapePositions, blendShapeNormals, null);
                    int l = 0;
                    foreach (var k in usedIndices)
                    {
                        blendShape.Set(l++,
                                       axisInverter.InvertVector3(blendShapePositions[k]),
                                       axisInverter.InvertVector3(blendShapeNormals[k]));
                    }

                    gltfPrimitive.targets.Add(blendShape.ToGltf(data, !settings.ExportOnlyBlendShapePosition,
                                                                settings.UseSparseAccessorForMorphTarget));
                }

                gltfMesh.primitives.Add(gltfPrimitive);
            }

            var targetNames = Enumerable.Range(0, mesh.blendShapeCount).Select(x => mesh.GetBlendShapeName(x)).ToArray();

            gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);

            return(gltfMesh, Enumerable.Range(0, mesh.blendShapeCount).ToDictionary(x => x, x => x));
        }
示例#26
0
            /// <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);
                }
            }
示例#27
0
            /// <summary>
            ///
            /// 各primitiveが同じ attribute を共有している場合専用のローダー。
            ///
            /// </summary>
            /// <param name="ctx"></param>
            /// <param name="gltfMesh"></param>
            /// <returns></returns>
            public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh)
            {
                {
                    //  同じVertexBufferを共有しているので先頭のモノを使う
                    var prim = gltfMesh.primitives.First();
                    m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector3>(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ()));

                    // normal
                    if (prim.attributes.NORMAL != -1)
                    {
                        m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector3>(prim.attributes.NORMAL).SelectInplace(x => x.ReverseZ()));
                    }

#if false
                    // tangent
                    if (prim.attributes.TANGENT != -1)
                    {
                        tangents.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector4>(prim.attributes.TANGENT).SelectInplace(x => x.ReverseZ()));
                    }
#endif

                    // uv
                    if (prim.attributes.TEXCOORD_0 != -1)
                    {
                        if (ctx.IsGeneratedUniGLTFAndOlder(1, 16))
                        {
#pragma warning disable 0612
                            // backward compatibility
                            m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseY()));
#pragma warning restore 0612
                        }
                        else
                        {
                            m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseUV()));
                        }
                    }

                    // uv2
                    if (prim.attributes.TEXCOORD_1 != -1)
                    {
                        m_uv2.AddRange(ctx.GLTF.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_1).SelectInplace(x => x.ReverseUV()));
                    }

                    // color
                    if (prim.attributes.COLOR_0 != -1)
                    {
                        if (ctx.GLTF.accessors[prim.attributes.COLOR_0].TypeCount == 3)
                        {
                            var vec3Color = ctx.GLTF.GetArrayFromAccessor <Vector3>(prim.attributes.COLOR_0);
                            m_colors.AddRange(new Color[vec3Color.Length]);

                            for (int i = 0; i < vec3Color.Length; i++)
                            {
                                Vector3 color = vec3Color[i];
                                m_colors[i] = new Color(color.x, color.y, color.z);
                            }
                        }
                        else if (ctx.GLTF.accessors[prim.attributes.COLOR_0].TypeCount == 4)
                        {
                            m_colors.AddRange(ctx.GLTF.GetArrayFromAccessor <Color>(prim.attributes.COLOR_0));
                        }
                        else
                        {
                            throw new NotImplementedException(string.Format("unknown color type {0}", ctx.GLTF.accessors[prim.attributes.COLOR_0].type));
                        }
                    }

                    // 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);
                        for (int i = 0; i < weights0.Length; ++i)
                        {
                            weights0[i] = weights0[i].One();
                        }

                        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)
                    {
                        m_blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape(i.ToString())));
                        for (int i = 0; i < prim.targets.Count; ++i)
                        {
                            //var name = string.Format("target{0}", i++);
                            var primTarget = prim.targets[i];
                            var blendShape = m_blendShapes[i];

                            if (primTarget.POSITION != -1)
                            {
                                blendShape.Positions.Assign(
                                    ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.POSITION), x => x.ReverseZ());
                            }
                            if (primTarget.NORMAL != -1)
                            {
                                blendShape.Normals.Assign(
                                    ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.NORMAL), x => x.ReverseZ());
                            }
                            if (primTarget.TANGENT != -1)
                            {
                                blendShape.Tangents.Assign(
                                    ctx.GLTF.GetArrayFromAccessor <Vector3>(primTarget.TANGENT), x => x.ReverseZ());
                            }
                        }
                    }
                }

                foreach (var prim in gltfMesh.primitives)
                {
                    if (prim.indices == -1)
                    {
                        m_subMeshes.Add(TriangleUtil.FlipTriangle(Enumerable.Range(0, m_positions.Count)).ToArray());
                    }
                    else
                    {
                        var indices = ctx.GLTF.GetIndices(prim.indices);
                        m_subMeshes.Add(indices);
                    }

                    // material
                    m_materialIndices.Add(prim.material);
                }
            }
示例#28
0
        static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex,
                                         string rendererName,
                                         Mesh mesh, Material[] materials,
                                         List <Material> unityMaterials)
        {
            var positions             = mesh.vertices.Select(y => y.ReverseZ()).ToArray();
            var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER);

            gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
            gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();

            var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);

#if GLTF_EXPORT_TANGENTS
            var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
#endif
            var uvAccessorIndex    = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);
            var colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER);

            var boneweights         = mesh.boneWeights;
            var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
            var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4((ushort)y.boneIndex0, (ushort)y.boneIndex1, (ushort)y.boneIndex2, (ushort)y.boneIndex3)).ToArray(), glBufferTarget.ARRAY_BUFFER);

            var attributes = new glTFAttributes
            {
                POSITION = positionAccessorIndex,
            };
            if (normalAccessorIndex != -1)
            {
                attributes.NORMAL = normalAccessorIndex;
            }
#if GLTF_EXPORT_TANGENTS
            if (tangentAccessorIndex != -1)
            {
                attributes.TANGENT = tangentAccessorIndex;
            }
#endif
            if (uvAccessorIndex != -1)
            {
                attributes.TEXCOORD_0 = uvAccessorIndex;
            }
            if (colorAccessorIndex != -1)
            {
                attributes.COLOR_0 = colorAccessorIndex;
            }
            if (weightAccessorIndex != -1)
            {
                attributes.WEIGHTS_0 = weightAccessorIndex;
            }
            if (jointsAccessorIndex != -1)
            {
                attributes.JOINTS_0 = jointsAccessorIndex;
            }

            var gltfMesh = new glTFMesh(mesh.name);
            for (int j = 0; j < mesh.subMeshCount; ++j)
            {
                var indices = TriangleUtil.FlipTriangle(mesh.GetIndices(j)).Select(y => (uint)y).ToArray();
                var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices, glBufferTarget.ELEMENT_ARRAY_BUFFER);

                if (j >= materials.Length)
                {
                    Debug.LogWarningFormat("{0}.materials is not enough", rendererName);
                    break;
                }

                gltfMesh.primitives.Add(new glTFPrimitives
                {
                    attributes = attributes,
                    indices    = indicesAccessorIndex,
                    mode       = 4, // triangels ?
                    material   = unityMaterials.IndexOf(materials[j])
                });
            }
            return(gltfMesh);
        }
        static MeshWithMaterials ImportMesh(glTF gltf, int meshIndex, glTFMesh gltfMesh,
                                            List <Material> materials,
                                            GetBlendShapeName getBlendShapeName
                                            )
        {
            glTFAttributes lastAttributes   = null;
            var            sharedAttributes = true;

            foreach (var prim in gltfMesh.primitives)
            {
                if (lastAttributes != null && !prim.attributes.Equals(lastAttributes))
                {
                    sharedAttributes = false;
                    break;
                }
                lastAttributes = prim.attributes;
            }

            var positions       = new List <Vector3>();
            var normals         = new List <Vector3>();
            var tangents        = new List <Vector4>();
            var colors          = new List <Vector4>();
            var uv              = new List <Vector2>();
            var boneWeights     = new List <BoneWeight>();
            var subMeshes       = new List <int[]>();
            var materialIndices = new List <int>();

            BlendShape[] blendShapes = null;

            if (sharedAttributes)
            {
                // multiple submesh sharing same VertexBuffer
                {
                    var prim = gltfMesh.primitives.First();
                    positions.AddRange(gltf.GetArrayFromAccessor <Vector3>(prim.attributes.POSITION).Select(x => x.ReverseZ()));

                    // normal
                    if (prim.attributes.NORMAL != -1)
                    {
                        normals.AddRange(gltf.GetArrayFromAccessor <Vector3>(prim.attributes.NORMAL).Select(x => x.ReverseZ()));
                    }

                    // tangent
                    if (prim.attributes.TANGENT != -1)
                    {
                        tangents.AddRange(gltf.GetArrayFromAccessor <Vector4>(prim.attributes.TANGENT).Select(x => x.ReverseZ()));
                    }

                    // vertex color
                    if (prim.attributes.COLOR_0 != -1)
                    {
                        colors.AddRange(gltf.GetArrayFromAccessor <Vector4>(prim.attributes.COLOR_0));
                    }

                    // uv
                    if (prim.attributes.TEXCOORD_0 != -1)
                    {
                        uv.AddRange(gltf.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY()));
                    }
                    else
                    {
                        // for inconsistent attributes in primitives
                        uv.AddRange(new Vector2[positions.Count]);
                    }

                    // skin
                    if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1)
                    {
                        var joints0  = gltf.GetArrayFromAccessor <UShort4>(prim.attributes.JOINTS_0); // uint4
                        var weights0 = 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;

                            boneWeights.Add(bw);
                        }
                    }

                    // blendshape
                    if (prim.targets != null && prim.targets.Count > 0)
                    {
                        if (blendShapes == null)
                        {
                            blendShapes = prim.targets.Select((x, i) => new BlendShape(getBlendShapeName(meshIndex, i))).ToArray();
                        }
                        for (int i = 0; i < prim.targets.Count; ++i)
                        {
                            //var name = string.Format("target{0}", i++);
                            var primTarget = prim.targets[i];
                            var blendShape = blendShapes[i];

                            if (primTarget.POSITION != -1)
                            {
                                blendShape.Positions.AddRange(
                                    gltf.GetArrayFromAccessor <Vector3>(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray());
                            }
                            if (primTarget.NORMAL != -1)
                            {
                                blendShape.Normals.AddRange(
                                    gltf.GetArrayFromAccessor <Vector3>(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray());
                            }
                            if (primTarget.TANGENT != -1)
                            {
                                blendShape.Tangents.AddRange(
                                    gltf.GetArrayFromAccessor <Vector3>(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray());
                            }
                        }
                    }
                }

                foreach (var prim in gltfMesh.primitives)
                {
                    var indices = gltf.GetIndices(prim.indices).Select(x => x).ToArray();
                    subMeshes.Add(indices);

                    // material
                    materialIndices.Add(prim.material);
                }
            }
            else
            {
                // multiple submMesh is not sharing a VertexBuffer.
                // each subMesh use a independent VertexBuffer.

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

                foreach (var prim in gltfMesh.primitives)
                {
                    var indexOffset = positions.Count;
                    var indexBuffer = prim.indices;

                    var positionCount = positions.Count;
                    positions.AddRange(gltf.GetArrayFromAccessor <Vector3>(prim.attributes.POSITION).Select(x => x.ReverseZ()));
                    positionCount = positions.Count - positionCount;

                    // normal
                    if (prim.attributes.NORMAL != -1)
                    {
                        normals.AddRange(gltf.GetArrayFromAccessor <Vector3>(prim.attributes.NORMAL).Select(x => x.ReverseZ()));
                    }

                    if (prim.attributes.TANGENT != -1)
                    {
                        tangents.AddRange(gltf.GetArrayFromAccessor <Vector4>(prim.attributes.TANGENT).Select(x => x.ReverseZ()));
                    }

                    // vertex color
                    if (prim.attributes.COLOR_0 != -1)
                    {
                        colors.AddRange(gltf.GetArrayFromAccessor <Vector4>(prim.attributes.COLOR_0));
                    }

                    // uv
                    if (prim.attributes.TEXCOORD_0 != -1)
                    {
                        uv.AddRange(gltf.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY()));
                    }
                    else
                    {
                        // for inconsistent attributes in primitives
                        uv.AddRange(new Vector2[positionCount]);
                    }

                    // skin
                    if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1)
                    {
                        var joints0  = gltf.GetArrayFromAccessor <UShort4>(prim.attributes.JOINTS_0); // uint4
                        var weights0 = 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;

                            boneWeights.Add(bw);
                        }
                    }

                    // blendshape
                    if (prim.targets != null && prim.targets.Count > 0)
                    {
                        if (blendShapes == null)
                        {
                            blendShapes = prim.targets.Select((x, i) => new BlendShape(i.ToString())).ToArray();
                        }
                        for (int i = 0; i < prim.targets.Count; ++i)
                        {
                            //var name = string.Format("target{0}", i++);
                            var primTarget = prim.targets[i];
                            var blendShape = blendShapes[i];

                            if (primTarget.POSITION != -1)
                            {
                                blendShape.Positions.AddRange(
                                    gltf.GetArrayFromAccessor <Vector3>(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray());
                            }
                            if (primTarget.NORMAL != -1)
                            {
                                blendShape.Normals.AddRange(
                                    gltf.GetArrayFromAccessor <Vector3>(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray());
                            }
                            if (primTarget.TANGENT != -1)
                            {
                                blendShape.Tangents.AddRange(
                                    gltf.GetArrayFromAccessor <Vector3>(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray());
                            }
                        }
                    }

                    var indices =
                        (indexBuffer >= 0)
                     ? gltf.GetIndices(indexBuffer).Select(x => x + indexOffset).ToArray()
                     : TriangleUtil.FlipTriangle(Enumerable.Range(0, positions.Count)).ToArray() // without index array
                    ;
                    subMeshes.Add(indices);

                    // material
                    materialIndices.Add(prim.material);
                }
            }
            if (!materialIndices.Any())
            {
                materialIndices.Add(0);
            }

            //Debug.Log(prims.ToJson());
            var mesh = new Mesh();

            mesh.name = gltfMesh.name;

            if (positions.Count > UInt16.MaxValue)
            {
#if UNITY_2017_3_OR_NEWER
                mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
#else
                Debug.LogWarningFormat("vertices {0} exceed 65535. not implemented. Unity2017.3 supports large mesh", positions.Count);
#endif
            }

            mesh.vertices = positions.ToArray();
            if (normals.Any())
            {
                mesh.normals = normals.ToArray();
            }
            else
            {
                mesh.RecalculateNormals();
            }
            if (tangents.Any())
            {
                mesh.tangents = tangents.ToArray();
            }
            else
            {
                mesh.RecalculateTangents();
            }
            if (colors.Any())
            {
                mesh.colors = colors.ConvertAll(x => new Color(x.x, x.y, x.z, 1f)).ToArray();
            }
            if (uv.Any())
            {
                mesh.uv = uv.ToArray();
            }
            if (boneWeights.Any())
            {
                mesh.boneWeights = boneWeights.ToArray();
            }
            mesh.subMeshCount = subMeshes.Count;
            for (int i = 0; i < subMeshes.Count; ++i)
            {
                mesh.SetTriangles(subMeshes[i], i);
            }
            var result = new MeshWithMaterials
            {
                Mesh      = mesh,
                Materials = materialIndices.Select(x => materials[x]).ToArray()
            };

            List <Material> matList = result.Materials.ToList();
            matList.RemoveAll(x => x == null);
            result.Materials = matList.ToArray();

            if (blendShapes != null)
            {
                foreach (var blendShape in blendShapes)
                {
                    if (blendShape.Positions.Count > 0)
                    {
                        if (blendShape.Positions.Count == mesh.vertexCount)
                        {
                            mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT,
                                                    blendShape.Positions.ToArray(),
                                                    normals.Count == mesh.vertexCount ? blendShape.Normals.ToArray() : null,
                                                    null
                                                    );
                        }
                        else
                        {
                            Debug.LogWarningFormat("May be partial primitive has blendShape. Rquire separete mesh or extend blend shape, but not implemented: {0}", blendShape.Name);
                        }
                    }
                }
            }

            return(result);
        }