function addMorphTargets( geometry, targets, accessors ) {

        var hasMorphPosition = false;
        var hasMorphNormal = false;

        for ( var i = 0, il = targets.length; i < il; i ++ ) {

            var target = targets[ i ];

            if ( target.POSITION !== undefined ) hasMorphPosition = true;
            if ( target.NORMAL !== undefined ) hasMorphNormal = true;

            if ( hasMorphPosition && hasMorphNormal ) break;

        }

        if ( ! hasMorphPosition && ! hasMorphNormal ) return;

        var morphPositions = [];
        var morphNormals = [];

        for ( var i = 0, il = targets.length; i < il; i ++ ) {

            var target = targets[ i ];
            var attributeName = 'morphTarget' + i;

            if ( hasMorphPosition ) {

                // Three.js morph position is absolute value. The formula is
                //   basePosition
                //     + weight0 * ( morphPosition0 - basePosition )
                //     + weight1 * ( morphPosition1 - basePosition )
                //     ...
                // while the glTF one is relative
                //   basePosition
                //     + weight0 * glTFmorphPosition0
                //     + weight1 * glTFmorphPosition1
                //     ...
                // then we need to convert from relative to absolute here.

                if ( target.POSITION !== undefined ) {

                    // Cloning not to pollute original accessor
                    var positionAttribute = cloneBufferAttribute( accessors[ target.POSITION ] );
                    positionAttribute.name = attributeName;

                    var position = geometry.attributes.position;

                    for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {

                        positionAttribute.setXYZ(
                            j,
                            positionAttribute.getX( j ) + position.getX( j ),
                            positionAttribute.getY( j ) + position.getY( j ),
                            positionAttribute.getZ( j ) + position.getZ( j )
                        );

                    }

                } else {

                    positionAttribute = geometry.attributes.position;

                }

                morphPositions.push( positionAttribute );

            }

            if ( hasMorphNormal ) {

                // see target.POSITION's comment

                var normalAttribute;

                if ( target.NORMAL !== undefined ) {

                    var normalAttribute = cloneBufferAttribute( accessors[ target.NORMAL ] );
                    normalAttribute.name = attributeName;

                    var normal = geometry.attributes.normal;

                    for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {

                        normalAttribute.setXYZ(
                            j,
                            normalAttribute.getX( j ) + normal.getX( j ),
                            normalAttribute.getY( j ) + normal.getY( j ),
                            normalAttribute.getZ( j ) + normal.getZ( j )
                        );

                    }

                } else {

                    normalAttribute = geometry.attributes.normal;

                }

                morphNormals.push( normalAttribute );

            }

        }

        if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
        if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;

    }
Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets

@param {THREE.BufferGeometry} geometry
@param {Array<GLTF.Target>} targets
@param {Array<THREE.BufferAttribute>} accessors