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

fix-456
Nehon 8 years ago committed by Rémy Bouquet
parent 5e79ae3c36
commit 7166906908
  1. 33
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/CustomContentManager.java
  2. 14
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/ExtensionLoader.java
  3. 25
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/ExtrasLoader.java
  4. 45
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java
  5. 37
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfModelKey.java
  6. 28
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/PBRSpecGlossExtensionLoader.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);
}
}
}

@ -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);
}

@ -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);
}

@ -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());

@ -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;
}
}

@ -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;
}
}

Loading…
Cancel
Save