private void addGLTFChannelDataToClip(GLTF.Schema.AnimationChannel channel, AnimationClip clip)
        {
            int animatedNodeIndex = channel.Target.Node.Id;

            if (!_importedObjects.ContainsKey(animatedNodeIndex))
            {
                Debug.Log("Node '" + animatedNodeIndex + "' found for animation, aborting.");
            }

            Transform animatedNode = _importedObjects[animatedNodeIndex].transform;
            string    nodePath     = AnimationUtility.CalculateTransformPath(animatedNode, _sceneObject.transform);

            bool isStepInterpolation = channel.Sampler.Value.Interpolation != InterpolationType.LINEAR;

            byte[]  timeBufferData = _assetCache.BufferCache[channel.Sampler.Value.Output.Value.BufferView.Value.Buffer.Id];
            float[] times          = GLTFHelpers.ParseKeyframeTimes(channel.Sampler.Value.Input.Value, timeBufferData);

            if (channel.Target.Path == GLTFAnimationChannelPath.translation || channel.Target.Path == GLTFAnimationChannelPath.scale)
            {
                byte[] bufferData             = _assetCache.BufferCache[channel.Sampler.Value.Output.Value.BufferView.Value.Buffer.Id];
                GLTF.Math.Vector3[] keyValues = GLTFHelpers.ParseVector3Keyframes(channel.Sampler.Value.Output.Value, bufferData);
                if (keyValues == null)
                {
                    return;
                }

                Vector3[]        values        = keyValues.ToUnityVector3();
                AnimationCurve[] vector3Curves = GLTFUtils.createCurvesFromArrays(times, values, isStepInterpolation, channel.Target.Path == GLTFAnimationChannelPath.translation);

                if (channel.Target.Path == GLTFAnimationChannelPath.translation)
                {
                    GLTFUtils.addTranslationCurvesToClip(vector3Curves, nodePath, ref clip);
                }
                else
                {
                    GLTFUtils.addScaleCurvesToClip(vector3Curves, nodePath, ref clip);
                }
            }
            else if (channel.Target.Path == GLTFAnimationChannelPath.rotation)
            {
                byte[]           bufferData     = _assetCache.BufferCache[channel.Sampler.Value.Output.Value.BufferView.Value.Buffer.Id];
                Vector4[]        values         = GLTFHelpers.ParseRotationKeyframes(channel.Sampler.Value.Output.Value, bufferData).ToUnityVector4();
                AnimationCurve[] rotationCurves = GLTFUtils.createCurvesFromArrays(times, values, isStepInterpolation);

                GLTFUtils.addRotationCurvesToClip(rotationCurves, nodePath, ref clip);
            }
            else if (channel.Target.Path == GLTFAnimationChannelPath.weights)
            {
                List <string> morphTargets = new List <string>();
                int           meshIndex    = _root.Nodes[animatedNodeIndex].Mesh.Id;
                for (int i = 0; i < _root.Meshes[meshIndex].Primitives[0].Targets.Count; ++i)
                {
                    morphTargets.Add(GLTFUtils.buildBlendShapeName(meshIndex, i));
                }

                byte[]           bufferData  = _assetCache.BufferCache[channel.Sampler.Value.Output.Value.BufferView.Value.Buffer.Id];
                float[]          values      = GLTFHelpers.ParseKeyframeTimes(channel.Sampler.Value.Output.Value, bufferData);
                AnimationCurve[] morphCurves = GLTFUtils.buildMorphAnimationCurves(times, values, morphTargets.Count);

                GLTFUtils.addMorphAnimationCurvesToClip(morphCurves, nodePath, morphTargets.ToArray(), ref clip);
            }
            else
            {
                Debug.Log("Unsupported animation channel target: " + channel.Target.Path);
            }
        }
        protected virtual void CreateMeshPrimitive(MeshPrimitive primitive, string meshName, int meshID, int primitiveIndex)
        {
            var meshAttributes = BuildMeshAttributes(primitive, meshID, primitiveIndex);
            var vertexCount    = primitive.Attributes[SemanticProperties.POSITION].Value.Count;

            UnityEngine.Mesh mesh = new UnityEngine.Mesh
            {
                vertices = primitive.Attributes.ContainsKey(SemanticProperties.POSITION)
                                        ? meshAttributes[SemanticProperties.POSITION].AccessorContent.AsVertices.ToUnityVector3()
                                        : null,
                normals = primitive.Attributes.ContainsKey(SemanticProperties.NORMAL)
                                        ? meshAttributes[SemanticProperties.NORMAL].AccessorContent.AsNormals.ToUnityVector3()
                                        : null,

                uv = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(0))
                                        ? meshAttributes[SemanticProperties.TexCoord(0)].AccessorContent.AsTexcoords.ToUnityVector2()
                                        : null,

                uv2 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(1))
                                        ? meshAttributes[SemanticProperties.TexCoord(1)].AccessorContent.AsTexcoords.ToUnityVector2()
                                        : null,

                uv3 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(2))
                                        ? meshAttributes[SemanticProperties.TexCoord(2)].AccessorContent.AsTexcoords.ToUnityVector2()
                                        : null,

                uv4 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(3))
                                        ? meshAttributes[SemanticProperties.TexCoord(3)].AccessorContent.AsTexcoords.ToUnityVector2()
                                        : null,

                colors = primitive.Attributes.ContainsKey(SemanticProperties.Color(0))
                                        ? meshAttributes[SemanticProperties.Color(0)].AccessorContent.AsColors.ToUnityColor()
                                        : null,

                triangles = primitive.Indices != null
                                        ? meshAttributes[SemanticProperties.INDICES].AccessorContent.AsTriangles
                                        : MeshPrimitive.GenerateTriangles(vertexCount),

                tangents = primitive.Attributes.ContainsKey(SemanticProperties.TANGENT)
                                        ? meshAttributes[SemanticProperties.TANGENT].AccessorContent.AsTangents.ToUnityVector4(true)
                                        : null
            };

            if (primitive.Attributes.ContainsKey(SemanticProperties.JOINT) && primitive.Attributes.ContainsKey(SemanticProperties.WEIGHT))
            {
                Vector4[] bones   = new Vector4[1];
                Vector4[] weights = new Vector4[1];

                LoadSkinnedMeshAttributes(meshID, primitiveIndex, ref bones, ref weights);
                if (bones.Length != mesh.vertices.Length || weights.Length != mesh.vertices.Length)
                {
                    Debug.LogError("Not enough skinning data (bones:" + bones.Length + " weights:" + weights.Length + "  verts:" + mesh.vertices.Length + ")");
                    return;
                }

                BoneWeight[] bws           = new BoneWeight[mesh.vertices.Length];
                int          maxBonesIndex = 0;
                for (int i = 0; i < bws.Length; ++i)
                {
                    // Unity seems expects the the sum of weights to be 1.
                    float[] normalizedWeights = GLTFUtils.normalizeBoneWeights(weights[i]);

                    bws[i].boneIndex0 = (int)bones[i].x;
                    bws[i].weight0    = normalizedWeights[0];

                    bws[i].boneIndex1 = (int)bones[i].y;
                    bws[i].weight1    = normalizedWeights[1];

                    bws[i].boneIndex2 = (int)bones[i].z;
                    bws[i].weight2    = normalizedWeights[2];

                    bws[i].boneIndex3 = (int)bones[i].w;
                    bws[i].weight3    = normalizedWeights[3];

                    maxBonesIndex = (int)Mathf.Max(maxBonesIndex, bones[i].x, bones[i].y, bones[i].z, bones[i].w);
                }

                mesh.boneWeights = bws;

                // initialize inverseBindMatrix array with identity matrix in order to output a valid mesh object
                Matrix4x4[] bindposes = new Matrix4x4[maxBonesIndex + 1];
                for (int j = 0; j <= maxBonesIndex; ++j)
                {
                    bindposes[j] = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one);
                }
                mesh.bindposes = bindposes;
            }

            if (primitive.Targets != null && primitive.Targets.Count > 0)
            {
                for (int b = 0; b < primitive.Targets.Count; ++b)
                {
                    Vector3[] deltaVertices = new Vector3[primitive.Targets[b]["POSITION"].Value.Count];
                    Vector3[] deltaNormals  = new Vector3[primitive.Targets[b]["POSITION"].Value.Count];
                    Vector3[] deltaTangents = new Vector3[primitive.Targets[b]["POSITION"].Value.Count];

                    if (primitive.Targets[b].ContainsKey("POSITION"))
                    {
                        NumericArray num = new NumericArray();
                        deltaVertices = primitive.Targets[b]["POSITION"].Value.AsVector3Array(ref num, _assetCache.BufferCache[0], false).ToUnityVector3(true);
                    }
                    if (primitive.Targets[b].ContainsKey("NORMAL"))
                    {
                        NumericArray num = new NumericArray();
                        deltaNormals = primitive.Targets[b]["NORMAL"].Value.AsVector3Array(ref num, _assetCache.BufferCache[0], true).ToUnityVector3(true);
                    }
                    //if (primitive.Targets[b].ContainsKey("TANGENT"))
                    //{
                    //	deltaTangents = primitive.Targets[b]["TANGENT"].Value.AsVector3Array(ref num, _assetCache.BufferCache[0], true).ToUnityVector3(true);
                    //}

                    mesh.AddBlendShapeFrame(GLTFUtils.buildBlendShapeName(meshID, b), 1.0f, deltaVertices, deltaNormals, deltaTangents);
                }
            }

            mesh.RecalculateBounds();
            mesh.RecalculateTangents();
            mesh = _assetManager.saveMesh(mesh, meshName + "_" + meshID + "_" + primitiveIndex);
            UnityEngine.Material material = primitive.Material != null && primitive.Material.Id >= 0 ? getMaterial(primitive.Material.Id) : defaultMaterial;

            _assetManager.addPrimitiveMeshData(meshID, primitiveIndex, mesh, material);
        }