Browse Source

Added support for loading "extras" from gltf files. Added some documentation

Nehon 8 năm trước cách đây
mục cha
commit
7166906908

+ 31 - 2
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/CustomContentManager.java

@@ -56,7 +56,13 @@ public class CustomContentManager {
         }
     }
 
-    public <T> T readExtension(JsonElement el, T input) throws AssetLoadException {
+    public <T> T readExtensionAndExtras(String name, JsonElement el, T input) throws AssetLoadException {
+        T output = readExtension(name, el, input);
+        output = readExtras(name, el, output);
+        return output;
+    }
+
+    private <T> T readExtension(String name, JsonElement el, T input) throws AssetLoadException {
         JsonElement extensions = el.getAsJsonObject().getAsJsonObject("extensions");
         if (extensions == null) {
             return input;
@@ -77,7 +83,7 @@ public class CustomContentManager {
             }
 
             try {
-                return (T) loader.handleExtension(gltfLoader, el, ext.getValue(), input);
+                return (T) loader.handleExtension(gltfLoader, name, el, ext.getValue(), input);
             } catch (ClassCastException e) {
                 throw new AssetLoadException("Extension loader " + loader.getClass().getName() + " for extension " + ext.getKey() + " is incompatible with type " + input.getClass(), e);
             }
@@ -86,4 +92,27 @@ public class CustomContentManager {
         return input;
     }
 
+    private <T> T readExtras(String name, JsonElement el, T input) throws AssetLoadException {
+        if (key == null) {
+            return input;
+        }
+        ExtrasLoader loader;
+        loader = key.getExtrasLoader();
+        if (loader == null) {
+            return input;
+        }
+        JsonElement extras = el.getAsJsonObject().getAsJsonObject("extras");
+        if (extras == null) {
+            return input;
+        }
+
+        try {
+            return (T) loader.handleExtras(gltfLoader, name, el, extras, input);
+        } catch (ClassCastException e) {
+            throw new AssetLoadException("Extra loader " + loader.getClass().getName() + " for " + name + " is incompatible with type " + input.getClass(), e);
+        }
+
+    }
+
+
 }

+ 13 - 1
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/ExtensionLoader.java

@@ -3,10 +3,22 @@ package com.jme3.scene.plugins.gltf;
 import com.google.gson.JsonElement;
 
 /**
+ * Base Interface for extension loading implementation.
+ *
  * Created by Nehon on 20/08/2017.
  */
 public interface ExtensionLoader {
 
-    Object handleExtension(GltfLoader loader, JsonElement parent, JsonElement extension, Object input);
+    /**
+     * Implement this methods to handle a gltf extension reading
+     *
+     * @param loader     the GltfLoader with all the data structure.
+     * @param parentName the name of the element being read
+     * @param parent     the element being read
+     * @param extension  the content of the extension found in the element being read
+     * @param input      an object containing already loaded data from the element, this is most probably a JME object
+     * @return An object of the same type as input, containing the data from the input object and the eventual additional data read from the extension
+     */
+    Object handleExtension(GltfLoader loader, String parentName, JsonElement parent, JsonElement extension, Object input);
 
 }

+ 25 - 0
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/ExtrasLoader.java

@@ -0,0 +1,25 @@
+package com.jme3.scene.plugins.gltf;
+
+import com.google.gson.JsonElement;
+
+/**
+ * Base Interface for extra loading implementation.
+ * Created by Nehon on 30/08/2017.
+ */
+public interface ExtrasLoader {
+
+    /**
+     * Implement this methods to handle gltf extra reading
+     * Note that this method will be invoked every time an "extras" element will be found in the gltf file.
+     * You can check the parentName to know where the "extras" element has been found.
+     *
+     * @param loader     the GltfLoader with all the data structure.
+     * @param parentName the name of the element being read
+     * @param parent     the element being read
+     * @param extras     the content of the extras found in the element being read
+     * @param input      an object containing already loaded data from the element, this is most probably a JME object
+     * @return An object of the same type as input, containing the data from the input object and the eventual additional data read from the extras
+     */
+    Object handleExtras(GltfLoader loader, String parentName, JsonElement parent, JsonElement extras, Object input);
+
+}

+ 27 - 18
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java

@@ -121,7 +121,7 @@ public class GltfLoader implements AssetLoader {
 
             readScenes(defaultScene, rootNode);
 
-            rootNode = customContentManager.readExtension(docRoot, rootNode);
+            rootNode = customContentManager.readExtensionAndExtras("root", docRoot, rootNode);
 
             setupControls();
 
@@ -163,7 +163,7 @@ public class GltfLoader implements AssetLoader {
 
             sceneNode.setName(getAsString(scene.getAsJsonObject(), "name"));
             JsonArray sceneNodes = scene.getAsJsonObject().getAsJsonArray("nodes");
-            sceneNode = customContentManager.readExtension(scene, sceneNode);
+            sceneNode = customContentManager.readExtensionAndExtras("scene", scene, sceneNode);
             rootNode.attachChild(sceneNode);
             for (JsonElement node : sceneNodes) {
                 readChild(sceneNode, node);
@@ -248,7 +248,7 @@ public class GltfLoader implements AssetLoader {
             spatial.setName(getAsString(nodeData.getAsJsonObject(), "name"));
         }
 
-        spatial = customContentManager.readExtension(nodeData, spatial);
+        spatial = customContentManager.readExtensionAndExtras("node", nodeData, spatial);
 
         addToCache("nodes", nodeIndex, spatial, nodes.size());
         return spatial;
@@ -384,7 +384,7 @@ public class GltfLoader implements AssetLoader {
                 mesh.generateBindPose();
             }
 
-            mesh = customContentManager.readExtension(meshObject, mesh);
+            mesh = customContentManager.readExtensionAndExtras("primitive", meshObject, mesh);
 
             Geometry geom = new Geometry(null, mesh);
 
@@ -415,7 +415,7 @@ public class GltfLoader implements AssetLoader {
             //TODO targets(morph anim...)
         }
 
-        geomArray = customContentManager.readExtension(meshData, geomArray);
+        geomArray = customContentManager.readExtensionAndExtras("mesh", meshData, geomArray);
 
         addToCache("meshes", meshIndex, geomArray, meshes.size());
         return geomArray;
@@ -454,7 +454,7 @@ public class GltfLoader implements AssetLoader {
         //TODO extras?
 
         R data = populator.populate(bufferViewIndex, componentType, type, count, byteOffset, normalized);
-        data = customContentManager.readExtension(accessor, data);
+        data = customContentManager.readExtensionAndExtras("accessor", accessor, data);
         return data;
     }
 
@@ -474,7 +474,7 @@ public class GltfLoader implements AssetLoader {
 
         byte[] data = readData(bufferIndex);
 
-        data = customContentManager.readExtension(bufferView, data);
+        data = customContentManager.readExtensionAndExtras("bufferView", bufferView, data);
 
         populateBuffer(store, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents, format);
 
@@ -515,7 +515,7 @@ public class GltfLoader implements AssetLoader {
             throw new AssetLoadException("Binary gltf is not supported yet");
         }
 
-        data = customContentManager.readExtension(buffer, data);
+        data = customContentManager.readExtensionAndExtras("buffer", buffer, data);
 
         addToCache("buffers", bufferIndex, data, buffers.size());
         return data;
@@ -539,7 +539,7 @@ public class GltfLoader implements AssetLoader {
             adapter.init(info.getManager());
         }
 
-        adapter = customContentManager.readExtension(matData, adapter);
+        adapter = customContentManager.readExtensionAndExtras("material", matData, adapter);
 
         if (adapter == null) {
             logger.log(Level.WARNING, "Couldn't find any matching material definition for material " + materialIndex);
@@ -599,7 +599,7 @@ public class GltfLoader implements AssetLoader {
                 Float zfar = getAsFloat(camData, "zfar", znear * 1000f);
 
                 cam.setFrustumPerspective(yfov * FastMath.RAD_TO_DEG, aspectRatio, znear, zfar);
-                cam = customContentManager.readExtension(camData, cam);
+                cam = customContentManager.readExtensionAndExtras("camera.perspective", camData, cam);
 
             } else {
                 Float xmag = getAsFloat(camData, "xmag");
@@ -609,14 +609,14 @@ public class GltfLoader implements AssetLoader {
                 Float znear = getAsFloat(camData, "znear");
                 assertNotNull(znear, "No znear for orthographic camere");
                 Float zfar = getAsFloat(camData, "zfar", znear * 1000f);
-                assertNotNull(zfar, "No zfar for orthographic camere");
+                assertNotNull(zfar, "No zfar for orthographic camera");
 
                 cam.setParallelProjection(true);
                 cam.setFrustum(znear, zfar, -xmag, xmag, ymag, -ymag);
 
-                cam = customContentManager.readExtension(camData, cam);
+                cam = customContentManager.readExtensionAndExtras("camera.orthographic", camData, cam);
             }
-
+            cam = customContentManager.readExtensionAndExtras("camera", camObj, cam);
             addToCache("cameras", i, cam, cameras.size());
         }
     }
@@ -639,9 +639,9 @@ public class GltfLoader implements AssetLoader {
         Integer samplerIndex = getAsInteger(textureData, "sampler");
 
         Texture2D texture2d = readImage(sourceIndex, flip);
-        readSampler(samplerIndex, texture2d);
+        texture2d = readSampler(samplerIndex, texture2d);
 
-        texture2d = customContentManager.readExtension(texture, texture2d);
+        texture2d = customContentManager.readExtensionAndExtras("texture", texture, texture2d);
 
         return texture2d;
     }
@@ -673,7 +673,7 @@ public class GltfLoader implements AssetLoader {
             result = (Texture2D) tex;
         }
 
-        result = customContentManager.readExtension(image, result);
+        result = customContentManager.readExtensionAndExtras("image", image, result);
 
         return result;
 
@@ -728,6 +728,8 @@ public class GltfLoader implements AssetLoader {
                 logger.log(Level.WARNING, "JME only supports linear interpolation for animations");
             }
 
+            animData = customContentManager.readExtensionAndExtras("animation.sampler", sampler, animData);
+
             float[] times = fetchFromCache("accessors", timeIndex, float[].class);
             if (times == null) {
                 times = readAccessorData(timeIndex, floatArrayPopulator);
@@ -757,6 +759,7 @@ public class GltfLoader implements AssetLoader {
                 Quaternion[] rotations = readAccessorData(dataIndex, quaternionArrayPopulator);
                 animData.rotations = rotations;
             }
+            animatedNodes[targetNode] = customContentManager.readExtensionAndExtras("channel", channel, animData);
         }
 
         if (name == null) {
@@ -802,7 +805,7 @@ public class GltfLoader implements AssetLoader {
             }
         }
 
-        anim = customContentManager.readExtension(animation, anim);
+        anim = customContentManager.readExtensionAndExtras("animations", animation, anim);
 
         if (skinIndex != -1) {
             //we have a bone animation.
@@ -841,7 +844,7 @@ public class GltfLoader implements AssetLoader {
         }
     }
 
-    public void readSampler(int samplerIndex, Texture2D texture) {
+    public Texture2D readSampler(int samplerIndex, Texture2D texture) {
         if (samplers == null) {
             throw new AssetLoadException("No samplers defined");
         }
@@ -859,6 +862,10 @@ public class GltfLoader implements AssetLoader {
         }
         texture.setWrap(Texture.WrapAxis.S, wrapS);
         texture.setWrap(Texture.WrapAxis.T, wrapT);
+
+        texture = customContentManager.readExtensionAndExtras("texture.sampler", sampler, texture);
+
+        return texture;
     }
 
     public void readSkins() throws IOException {
@@ -917,6 +924,8 @@ public class GltfLoader implements AssetLoader {
                 skeleton.updateWorldVectors();
             }
 
+            skeleton = customContentManager.readExtensionAndExtras("skin", skin, skeleton);
+
             SkinData skinData = new SkinData();
             skinData.skeletonControl = new SkeletonControl(skeleton);
             addToCache("skins", index, skinData, nodes.size());

+ 37 - 0
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfModelKey.java

@@ -6,12 +6,23 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
+ * An optional key to use when loading a glTF file
+ * It allows to specify custom data loader replacing the default ones.
+ *
+ * MaterialAdapters: Allows to map glTF standard material model to a non stock material.
+ * ExtensionLoaders: Allows to provide or override a loader for a given gltf extension.
+ * ExtrasLoader: Allows to load any extras, application specific data of the gltf file.
+ *
+ * For more information, please see glTF 2.0 specifications
+ * https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md
+ *
  * Created by Nehon on 08/08/2017.
  */
 public class GltfModelKey extends ModelKey {
 
     private Map<String, MaterialAdapter> materialAdapters = new HashMap<>();
     private static Map<String, ExtensionLoader> extensionLoaders = new HashMap<>();
+    private ExtrasLoader extrasLoader;
     private boolean keepSkeletonPose = false;
 
     public GltfModelKey(String name) {
@@ -21,10 +32,25 @@ public class GltfModelKey extends ModelKey {
     public GltfModelKey() {
     }
 
+    /**
+     * Registers a MaterialAdapter for the given materialName.
+     * The materialName must be "pbrMetallicRoughness" or any name from KHR_materials glTF Extension (for example "pbrSpecularGlossiness" for "KHR_materials_pbrSpecularGlossiness" extension)
+     *
+     * @param gltfMaterialName the name of the gltf material
+     * @param adapter          the material adapter
+     */
     public void registerMaterialAdapter(String gltfMaterialName, MaterialAdapter adapter) {
         materialAdapters.put(gltfMaterialName, adapter);
     }
 
+    /**
+     * Registers and extension loader for th given extension name.
+     * For more information on extension please see glTF 2.0 extensions registry
+     * https://github.com/KhronosGroup/glTF/blob/master/extensions/README.md
+     *
+     * @param extensionName the name of the extension
+     * @param loader        the Extension loader
+     */
     public void registerExtensionLoader(String extensionName, ExtensionLoader loader) {
         extensionLoaders.put(extensionName, loader);
     }
@@ -45,5 +71,16 @@ public class GltfModelKey extends ModelKey {
         this.keepSkeletonPose = keepSkeletonPose;
     }
 
+    public ExtrasLoader getExtrasLoader() {
+        return extrasLoader;
+    }
 
+    /**
+     * Sets the ExtrasLoader for reading any extra information from the gltf file.
+     *
+     * @param extrasLoader
+     */
+    public void setExtrasLoader(ExtrasLoader extrasLoader) {
+        this.extrasLoader = extrasLoader;
+    }
 }

+ 20 - 8
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/PBRSpecGlossExtensionLoader.java

@@ -1,6 +1,7 @@
 package com.jme3.scene.plugins.gltf;
 
 import com.google.gson.JsonElement;
+import com.jme3.asset.AssetKey;
 
 import static com.jme3.scene.plugins.gltf.GltfUtils.getAsColor;
 import static com.jme3.scene.plugins.gltf.GltfUtils.getAsFloat;
@@ -14,15 +15,26 @@ public class PBRSpecGlossExtensionLoader implements ExtensionLoader {
     private PBRSpecGlossMaterialAdapter materialAdapter = new PBRSpecGlossMaterialAdapter();
 
     @Override
-    public Object handleExtension(GltfLoader loader, JsonElement parent, JsonElement extension, Object input) {
-        materialAdapter.init(loader.getInfo().getManager());
+    public Object handleExtension(GltfLoader loader, String parentName, JsonElement parent, JsonElement extension, Object input) {
+        MaterialAdapter adapter = materialAdapter;
+        AssetKey key = loader.getInfo().getKey();
+        //check for a custom adapter for spec/gloss pipeline
+        if (key instanceof GltfModelKey) {
+            GltfModelKey gltfKey = (GltfModelKey) key;
+            MaterialAdapter ma = gltfKey.getAdapterForMaterial("pbrSpecularGlossiness");
+            if (ma != null) {
+                adapter = ma;
+            }
+        }
 
-        materialAdapter.setParam("diffuseFactor", getAsColor(extension.getAsJsonObject(), "diffuseFactor"));
-        materialAdapter.setParam("specularFactor", getAsColor(extension.getAsJsonObject(), "specularFactor"));
-        materialAdapter.setParam("glossinessFactor", getAsFloat(extension.getAsJsonObject(), "glossinessFactor"));
-        materialAdapter.setParam("diffuseTexture", loader.readTexture(extension.getAsJsonObject().getAsJsonObject("diffuseTexture")));
-        materialAdapter.setParam("specularGlossinessTexture", loader.readTexture(extension.getAsJsonObject().getAsJsonObject("specularGlossinessTexture")));
+        adapter.init(loader.getInfo().getManager());
 
-        return materialAdapter;
+        adapter.setParam("diffuseFactor", getAsColor(extension.getAsJsonObject(), "diffuseFactor"));
+        adapter.setParam("specularFactor", getAsColor(extension.getAsJsonObject(), "specularFactor"));
+        adapter.setParam("glossinessFactor", getAsFloat(extension.getAsJsonObject(), "glossinessFactor"));
+        adapter.setParam("diffuseTexture", loader.readTexture(extension.getAsJsonObject().getAsJsonObject("diffuseTexture")));
+        adapter.setParam("specularGlossinessTexture", loader.readTexture(extension.getAsJsonObject().getAsJsonObject("specularGlossinessTexture")));
+
+        return adapter;
     }
 }