public void readSkins() throws IOException {
        if (skins == null) {
            // no skins, no bone animation.
            return;
        }
        List<JsonArray> allJoints = new ArrayList<>();
        for (int index = 0; index < skins.size(); index++) {
            JsonObject skin = skins.get(index).getAsJsonObject();

            // Note that the "skeleton" index is intentionally ignored.
            // It's not mandatory and exporters tend to mix up how it should be used
            // because the specs are not clear.
            // Anyway we have other means to detect both armature structures and root bones.

            JsonArray jsonJoints = skin.getAsJsonArray("joints");
            assertNotNull(jsonJoints, "No joints defined for skin");
            int idx = allJoints.indexOf(jsonJoints);
            if (idx >= 0) {
                // skin already exists let's just set it in the cache
                SkinData sd = fetchFromCache("skins", idx, SkinData.class);
                addToCache("skins", index, sd, nodes.size());
                continue;
            } else {
                allJoints.add(jsonJoints);
            }

            // These inverse bind matrices, once inverted again,
            // will give us the real bind pose of the bones (in model space),
            // since the skeleton is not guaranteed to be exported in bind pose.
            Integer matricesIndex = getAsInteger(skin, "inverseBindMatrices");
            Matrix4f[] inverseBindMatrices = null;
            if (matricesIndex != null) {
                inverseBindMatrices = readAccessorData(matricesIndex, matrix4fArrayPopulator);
            } else {
                inverseBindMatrices = new Matrix4f[jsonJoints.size()];
                for (int i = 0; i < inverseBindMatrices.length; i++) {
                    inverseBindMatrices[i] = new Matrix4f();
                }
            }

            Joint[] joints = new Joint[jsonJoints.size()];
            for (int i = 0; i < jsonJoints.size(); i++) {
                int boneIndex = jsonJoints.get(i).getAsInt();
                Matrix4f inverseModelBindMatrix = inverseBindMatrices[i];
                joints[i] = readNodeAsBone(boneIndex, i, index, inverseModelBindMatrix);
            }

            for (int i = 0; i < jsonJoints.size(); i++) {
                findChildren(jsonJoints.get(i).getAsInt());
            }

            Armature armature = new Armature(joints);
            armature = customContentManager.readExtensionAndExtras("skin", skin, armature);
            SkinData skinData = new SkinData();
            skinData.joints = joints;
            skinData.skinningControl = new SkinningControl(armature);
            skinData.animComposer = new AnimComposer();
            addToCache("skins", index, skinData, nodes.size());
            skinnedSpatials.put(skinData, new ArrayList<Spatial>());

            armature.update();
            armature.saveInitialPose();
        }
    }
GLTF 2.0 loader
Created by Nehon on 07/08/2017.
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java