Added support for loading "extras" from gltf files. Added some documentation
This commit is contained in:
parent
5e79ae3c36
commit
7166906908
@ -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…
x
Reference in New Issue
Block a user