-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Adding full support for custom materials to GltfLoader #2725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 9 commits
ef06795
317a56a
c164633
fef2d6e
11eded3
ae12167
53b75ca
13ad8ba
58410b6
2921b83
d005d0b
7909f1b
b245ada
ccec70a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,7 @@ | |
| */ | ||
| package com.jme3.scene.plugins.gltf; | ||
|
|
||
| import static com.jme3.scene.plugins.gltf.GltfMaterialData.*; | ||
| import static com.jme3.scene.plugins.gltf.GltfUtils.assertNotNull; | ||
| import static com.jme3.scene.plugins.gltf.GltfUtils.findCommonAncestor; | ||
| import static com.jme3.scene.plugins.gltf.GltfUtils.getAdapterForMaterial; | ||
|
|
@@ -83,6 +84,7 @@ | |
| import com.jme3.asset.TextureKey; | ||
| import com.jme3.material.Material; | ||
| import com.jme3.material.RenderState; | ||
| import com.jme3.material.RenderState.BlendMode; | ||
| import com.jme3.math.ColorRGBA; | ||
| import com.jme3.math.FastMath; | ||
| import com.jme3.math.Matrix4f; | ||
|
|
@@ -109,6 +111,7 @@ | |
| import com.jme3.util.BufferInputStream; | ||
| import com.jme3.util.BufferUtils; | ||
| import com.jme3.util.IntMap; | ||
| import com.jme3.util.SafeArrayList; | ||
| import com.jme3.util.mikktspace.MikktspaceTangentGenerator; | ||
|
|
||
| /** | ||
|
|
@@ -143,13 +146,20 @@ public class GltfLoader implements AssetLoader { | |
| private final Vector3fArrayPopulator vector3fArrayPopulator = new Vector3fArrayPopulator(); | ||
| private final QuaternionArrayPopulator quaternionArrayPopulator = new QuaternionArrayPopulator(); | ||
| private final Matrix4fArrayPopulator matrix4fArrayPopulator = new Matrix4fArrayPopulator(); | ||
| private final Map<String, MaterialAdapter> defaultMaterialAdapters = new HashMap<>(); | ||
| @Deprecated private final Map<String, MaterialAdapter> defaultMaterialAdapters = new HashMap<>(); | ||
| private final CustomContentManager customContentManager = new CustomContentManager(); | ||
| private boolean useNormalsFlag = false; | ||
|
|
||
| Map<SkinData, List<Spatial>> skinnedSpatials = new HashMap<>(); | ||
| private final IntMap<SkinBuffers> skinBuffers = new IntMap<>(); | ||
|
|
||
| private static SafeArrayList<GltfMaterialFactory> materialFactoryList = new SafeArrayList<>(GltfMaterialFactory.class); | ||
|
|
||
| static { | ||
| materialFactoryList.add(new UnshadedMaterialFactory()); | ||
| materialFactoryList.add(new PBRLightingMaterialFactory()); | ||
| } | ||
|
|
||
| public GltfLoader() { | ||
| defaultMaterialAdapters.put("pbrMetallicRoughness", new PBRMetalRoughMaterialAdapter()); | ||
| } | ||
|
|
@@ -526,9 +536,10 @@ public Geometry[] readMeshPrimitives(int meshIndex) throws IOException { | |
| geom.setMaterial(defaultMat); | ||
| } else { | ||
| useNormalsFlag = false; | ||
| geom.setMaterial(readMaterial(materialIndex)); | ||
| if (geom.getMaterial().getAdditionalRenderState() | ||
| .getBlendMode() == RenderState.BlendMode.Alpha) { | ||
| Material material = readMaterial(materialIndex, useVertexColors); | ||
| geom.setMaterial(material); | ||
| BlendMode blendMode = material.getAdditionalRenderState().getBlendMode(); | ||
| if (blendMode == BlendMode.Alpha || blendMode == BlendMode.AlphaAdditive) { | ||
| // Alpha blending is enabled for this material. Let's place the geom in the | ||
| // transparent bucket. | ||
| geom.setQueueBucket(RenderQueue.Bucket.Transparent); | ||
|
|
@@ -540,10 +551,6 @@ public Geometry[] readMeshPrimitives(int meshIndex) throws IOException { | |
| } | ||
| } | ||
|
|
||
| if (useVertexColors) { | ||
| geom.getMaterial().setBoolean("UseVertexColor", useVertexColors); | ||
| } | ||
|
|
||
| geom.setName(name + "_" + index); | ||
|
|
||
| geom.updateModelBound(); | ||
|
|
@@ -802,7 +809,75 @@ protected ByteBuffer getBytes(int bufferIndex, String uri, Integer bufferLength) | |
| return data; | ||
| } | ||
|
|
||
| public Material readMaterial(int materialIndex) throws IOException { | ||
| public Material readMaterial(int materialIndex, boolean usesVertexColors) throws IOException { | ||
| // Fallback to the old material adapter system, if the legacy flag is set. | ||
| if (GltfUtils.isMaterialAdaptersEnabled(info)) { | ||
| return readMaterialUsingMaterialAdapters(materialIndex); | ||
| } | ||
|
Comment on lines
+815
to
+819
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The vertex coloring flag is now also set correctly in the legacy system. |
||
|
|
||
| assertNotNull(materials, "There is no material defined yet a mesh references one"); | ||
| JsonObject materialJson = materials.get(materialIndex).getAsJsonObject(); | ||
|
|
||
| GltfMaterialData gltfMaterialData = readStandardMaterialParameters(materialJson); | ||
| gltfMaterialData.setHasVertexColors(usesVertexColors); | ||
| gltfMaterialData = customContentManager.readExtensionAndExtras("material", materialJson, gltfMaterialData); | ||
| return createMaterial(gltfMaterialData, materialIndex); | ||
|
Comment on lines
+815
to
+827
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added many new tests for various material parameter combinations to the GltfLoaderTest. |
||
| } | ||
|
|
||
| protected GltfMaterialData readStandardMaterialParameters(JsonObject materialJson) throws IOException { | ||
| GltfMaterialData gltfMaterialData = new GltfMaterialData(); | ||
| gltfMaterialData.setGltfParam(MATERIAL_NAME_PARAM, getAsString(materialJson, "name")); | ||
|
|
||
| JsonObject pbrMetallicRoughnessJson = materialJson.getAsJsonObject("pbrMetallicRoughness"); | ||
| if (pbrMetallicRoughnessJson != null) { | ||
| gltfMaterialData.setGltfParam(BASE_COLOR_PARAM, getAsColor(pbrMetallicRoughnessJson, "baseColorFactor")); | ||
| gltfMaterialData.setGltfParam(BASE_COLOR_TEXTURE_PARAM, getAsTexture2D(pbrMetallicRoughnessJson, "baseColorTexture")); | ||
| gltfMaterialData.setGltfParam(METALLIC_FACTOR_PARAM, getAsFloat(pbrMetallicRoughnessJson, "metallicFactor")); | ||
| gltfMaterialData.setGltfParam(ROUGHNESS_FACTOR_PARAM, getAsFloat(pbrMetallicRoughnessJson, "roughnessFactor")); | ||
| gltfMaterialData.setGltfParam(METALLIC_ROUGHNESS_TEXTURE_PARAM, getAsTexture2D(pbrMetallicRoughnessJson, "metallicRoughnessTexture")); | ||
| } | ||
|
|
||
| JsonObject normalTextureJson = materialJson.getAsJsonObject("normalTexture"); | ||
| if (normalTextureJson != null) { | ||
| gltfMaterialData.setGltfParam(NORMAL_TEXTURE_PARAM, readTexture(normalTextureJson)); | ||
| gltfMaterialData.setGltfParam(NORMAL_SCALE_PARAM, getAsFloat(normalTextureJson, "scale")); | ||
| useNormalsFlag = true; | ||
| } | ||
|
|
||
| JsonObject occlusionTextureJson = materialJson.getAsJsonObject("occlusionTexture"); | ||
| if (occlusionTextureJson != null) { | ||
| gltfMaterialData.setGltfParam(OCCLUSION_TEXTURE_PARAM, readTexture(occlusionTextureJson)); | ||
| gltfMaterialData.setGltfParam(OCCLUSION_TEXTURE_STRENGTH_PARAM, getAsFloat(occlusionTextureJson, "strength")); | ||
| } | ||
|
|
||
| gltfMaterialData.setGltfParam(EMISSIV_TEXTURE_PARAM, getAsTexture2D(materialJson, "emissiveTexture")); | ||
| gltfMaterialData.setGltfParam(EMISSIV_COLOR_PARAM, getAsColor(materialJson, "emissiveFactor")); | ||
|
|
||
| String alphaMode = getAsString(materialJson, "alphaMode"); | ||
| gltfMaterialData.setGltfParam(ALPHA_MODE_PARAM, alphaMode); | ||
| if ("MASK".equals(alphaMode)) { | ||
| gltfMaterialData.setGltfParam(ALPHA_CUTOFF_PARAM, getAsFloat(materialJson, "alphaCutoff")); | ||
| } | ||
|
|
||
| gltfMaterialData.setGltfParam(DOUBLE_SIDED_PARAM, getAsBoolean(materialJson, "doubleSided")); | ||
|
|
||
| return gltfMaterialData; | ||
| } | ||
|
|
||
| protected Material createMaterial(GltfMaterialData gltfMaterialData, int materialIndex) { | ||
| for (GltfMaterialFactory gltfMaterialFactory : materialFactoryList) { | ||
| if (gltfMaterialFactory.accepts(info.getKey(), gltfMaterialData)) { | ||
| return gltfMaterialFactory.createMaterial(info.getManager(), info.getKey(), gltfMaterialData); | ||
| } | ||
| } | ||
|
|
||
| logger.log(Level.WARNING, "Couldn't find any matching GltfMaterialFactory for material " + materialIndex); | ||
| useNormalsFlag = false; | ||
| return defaultMat; | ||
| } | ||
|
|
||
| @Deprecated | ||
| protected Material readMaterialUsingMaterialAdapters(int materialIndex) throws IOException { | ||
| assertNotNull(materials, "There is no material defined yet a mesh references one"); | ||
|
|
||
| JsonObject matData = materials.get(materialIndex).getAsJsonObject(); | ||
|
|
@@ -922,6 +997,10 @@ public void readCameras() throws IOException { | |
| } | ||
| } | ||
|
|
||
| protected Texture2D getAsTexture2D(JsonObject jsonObject, String textureName) throws IOException { | ||
| return readTexture(jsonObject.getAsJsonObject(textureName)); | ||
| } | ||
|
|
||
| public Texture2D readTexture(JsonObject texture) throws IOException { | ||
| return readTexture(texture, false); | ||
| } | ||
|
|
@@ -1715,4 +1794,44 @@ public static void registerDefaultExtrasLoader(Class<? extends ExtrasLoader> loa | |
| public static void unregisterDefaultExtrasLoader() { | ||
| CustomContentManager.defaultExtraLoaderClass = UserDataLoader.class; | ||
| } | ||
|
|
||
| /** | ||
| * Registers a new material factory and places it before all existing factories.<br/> | ||
| * The ordering of these factories defines their priority. When a new material needs to be created, | ||
| * the loader searches for the first material factory that accepts the given material data. | ||
| * | ||
| * @param materialFactory The {@link GltfMaterialFactory} to register. | ||
| */ | ||
| public static void registerMaterialFactoryFirst(GltfMaterialFactory materialFactory) { | ||
| unregisterMaterialFactory(materialFactory.getClass()); | ||
| materialFactoryList.add(0, materialFactory); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indentation has been fixed. |
||
| } | ||
|
|
||
| /** | ||
| * Registers a new material factory and places it behind all existing factories.<br/> | ||
| * The ordering of these factories defines their priority. When a new material needs to be created, | ||
| * the loader searches for the first material factory that accepts the given material data. | ||
| * | ||
| * @param materialFactory The {@link GltfMaterialFactory} to register. | ||
| */ | ||
| public static void registerMaterialFactoryLast(GltfMaterialFactory materialFactory) { | ||
| unregisterMaterialFactory(materialFactory.getClass()); | ||
| materialFactoryList.add(materialFactory); | ||
| } | ||
|
|
||
| /** | ||
| * Unregisters a material factory by its class. | ||
| * | ||
| * @param materialFactoryClass The class of the {@link GltfMaterialFactory} to unregister. | ||
| */ | ||
| public static void unregisterMaterialFactory(Class<? extends GltfMaterialFactory> materialFactoryClass) { | ||
| materialFactoryList.removeIf(materialFactoryClass::isInstance); | ||
| } | ||
|
|
||
| /** | ||
| * Unregisters all material factories. | ||
| */ | ||
| public static void unregisterAllMaterialFactories() { | ||
| materialFactoryList.clear(); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The vertex coloring flag is now also set correctly for the default material.