private AccessorId AccessorToId(Accessor accessor, EntryBufferView bufferView)
        {
            if (root.Accessors == null)
            {
                root.Accessors = new List<Accessor>();
            }

            accessor.BufferView = bufferView.id;
            accessor.Name = bufferView.view.Name;
            root.Accessors.Add(accessor);

            return new AccessorId { Id = root.Accessors.Count - 1, Root = root };
        }
        public Pair<MeshId, bool> SaveMesh(UnityEngine.Mesh mesh, Renderer renderer)
        {
            if (root.Meshes == null)
            {
                root.Meshes = new List<GLTF.Schema.Mesh>();
            }

            string materialsId = "";
            foreach (var mat in renderer.sharedMaterials)
            {
                materialsId += mat.GetInstanceID();
            }

            if (_mesh2Id.ContainsKey(mesh) && _mesh2Id[mesh].ContainsKey(materialsId))
            {
                return new Pair<MeshId, bool>(_mesh2Id[mesh][materialsId], false);
            }

            var m = new GLTF.Schema.Mesh();
            var attributes = GenerateAttributes(mesh);
            var targets = GenerateMorphTargets(mesh, m);
            m.Name = mesh.name;
            m.Primitives = new List<MeshPrimitive>();

            EntryBufferView indices = null;

            for (int i = 0; i < mesh.subMeshCount; i += 1)
            {
                var primitive = new MeshPrimitive();
                m.Primitives.Add(primitive);
                primitive.Attributes = attributes;
                primitive.Mode = DrawMode.Triangles;
                if (targets.Count > 0)
                {
                    primitive.Targets = targets;
                }
                SaveIndices(mesh, primitive, i, ref indices);
            }

            root.Meshes.Add(m);
            var id = new MeshId { Id = root.Meshes.Count - 1, Root = root };

            if (!_mesh2Id.ContainsKey(mesh))
            {
                _mesh2Id.Add(mesh, new Dictionary<string, MeshId>());
            }
            _mesh2Id[mesh].Add(materialsId, id);

            return new Pair<MeshId, bool>(id, true);
        }
        public EntryBufferView CreateStreamBufferView(string name)
        {
            if (root.BufferViews == null)
            {
                root.BufferViews = new List<BufferView>();
            }

            var bufferView = new EntryBufferView();
            bufferView.streamBuffer = new MemoryStream();
            bufferView.view.Name = name;
            _bufferViews.Add(bufferView);
            root.BufferViews.Add(bufferView.view);
            bufferView.id = new BufferViewId { Id = root.BufferViews.Count - 1, Root = root };

            return bufferView;
        }
        public EntryBufferView CreateByteBufferView(string name, int size, int stride)
        {
            if (root.BufferViews == null)
            {
                root.BufferViews = new List<BufferView>();
            }

            var bufferView = new EntryBufferView();
            bufferView.byteBuffer = new byte[size];
            bufferView.view.Name = name;
            bufferView.view.ByteStride = stride;
            _bufferViews.Add(bufferView);
            root.BufferViews.Add(bufferView.view);
            bufferView.id = new BufferViewId { Id = root.BufferViews.Count - 1, Root = root };

            return bufferView;
        }
        private AccessorId PackAttrToBufferShort<DataType>(EntryBufferView bufferView, DataType[] data, int offset, Func<DataType[], int, DataType> getValueByIndex = null)
        {
            var accessor = ExporterUtils.PackToBuffer(bufferView.byteBuffer, data, GLTFComponentType.UnsignedShort, offset, bufferView.view.ByteStride, getValueByIndex);

            return AccessorToId(accessor, bufferView);
        }
        private void SaveIndices(UnityEngine.Mesh mesh, MeshPrimitive primitive, int i, ref EntryBufferView bufferView)
        {
            primitive.Mode = DrawMode.Triangles;

            if (_mesh2indices.ContainsKey(mesh) && _mesh2indices[mesh].ContainsKey(i))
            {
                primitive.Indices = _mesh2indices[mesh][i];
                return;
            }

            if (bufferView == null)
            {
                bufferView = CreateStreamBufferView(mesh.name + "-indices");
            }

            primitive.Indices = AccessorToId(
                ExporterUtils.PackToBuffer(bufferView.streamBuffer, mesh.GetTriangles(i), GLTFComponentType.UnsignedShort, (int[] data, int index) => {
                    var offset = index % 3;

                    return data[offset == 0 ? index : offset == 1 ? index + 1 : index - 1];
                }),
                bufferView
            );
            primitive.Indices.Value.Name += "-" + i;

            if (!_mesh2indices.ContainsKey(mesh))
            {
                _mesh2indices.Add(mesh, new Dictionary<int, AccessorId>());
            }

            _mesh2indices[mesh].Add(i, primitive.Indices);
        }