3131 */
3232package com .jme3 .scene .plugins .gltf ;
3333
34+ import static com .jme3 .scene .plugins .gltf .GltfMaterialData .*;
3435import static com .jme3 .scene .plugins .gltf .GltfUtils .assertNotNull ;
3536import static com .jme3 .scene .plugins .gltf .GltfUtils .findCommonAncestor ;
3637import static com .jme3 .scene .plugins .gltf .GltfUtils .getAdapterForMaterial ;
8283import com .jme3 .asset .AssetLoader ;
8384import com .jme3 .asset .TextureKey ;
8485import com .jme3 .material .Material ;
85- import com .jme3 .material .RenderState ;
86+ import com .jme3 .material .RenderState . BlendMode ;
8687import com .jme3 .math .ColorRGBA ;
8788import com .jme3 .math .FastMath ;
8889import com .jme3 .math .Matrix4f ;
109110import com .jme3 .util .BufferInputStream ;
110111import com .jme3 .util .BufferUtils ;
111112import com .jme3 .util .IntMap ;
113+ import com .jme3 .util .SafeArrayList ;
112114import com .jme3 .util .mikktspace .MikktspaceTangentGenerator ;
113115
114116/**
@@ -143,13 +145,20 @@ public class GltfLoader implements AssetLoader {
143145 private final Vector3fArrayPopulator vector3fArrayPopulator = new Vector3fArrayPopulator ();
144146 private final QuaternionArrayPopulator quaternionArrayPopulator = new QuaternionArrayPopulator ();
145147 private final Matrix4fArrayPopulator matrix4fArrayPopulator = new Matrix4fArrayPopulator ();
146- private final Map <String , MaterialAdapter > defaultMaterialAdapters = new HashMap <>();
148+ @ Deprecated private final Map <String , MaterialAdapter > defaultMaterialAdapters = new HashMap <>();
147149 private final CustomContentManager customContentManager = new CustomContentManager ();
148150 private boolean useNormalsFlag = false ;
149151
150152 Map <SkinData , List <Spatial >> skinnedSpatials = new HashMap <>();
151153 private final IntMap <SkinBuffers > skinBuffers = new IntMap <>();
152154
155+ private static SafeArrayList <GltfMaterialFactory > materialFactoryList = new SafeArrayList <>(GltfMaterialFactory .class );
156+
157+ static {
158+ materialFactoryList .add (new UnshadedMaterialFactory ());
159+ materialFactoryList .add (new PBRLightingMaterialFactory ());
160+ }
161+
153162 public GltfLoader () {
154163 defaultMaterialAdapters .put ("pbrMetallicRoughness" , new PBRMetalRoughMaterialAdapter ());
155164 }
@@ -523,12 +532,17 @@ public Geometry[] readMeshPrimitives(int meshIndex) throws IOException {
523532
524533 Integer materialIndex = getAsInteger (meshObject , "material" );
525534 if (materialIndex == null ) {
526- geom .setMaterial (defaultMat );
535+ // Create a new default material
536+ Material material = defaultMat .clone ();
537+ material .setBoolean ("UseVertexColor" , useVertexColors );
538+ geom .setMaterial (material );
539+
527540 } else {
528541 useNormalsFlag = false ;
529- geom .setMaterial (readMaterial (materialIndex ));
530- if (geom .getMaterial ().getAdditionalRenderState ()
531- .getBlendMode () == RenderState .BlendMode .Alpha ) {
542+ Material material = readMaterial (materialIndex , useVertexColors );
543+ geom .setMaterial (material );
544+ BlendMode blendMode = material .getAdditionalRenderState ().getBlendMode ();
545+ if (blendMode == BlendMode .Alpha || blendMode == BlendMode .AlphaAdditive ) {
532546 // Alpha blending is enabled for this material. Let's place the geom in the
533547 // transparent bucket.
534548 geom .setQueueBucket (RenderQueue .Bucket .Transparent );
@@ -540,10 +554,6 @@ public Geometry[] readMeshPrimitives(int meshIndex) throws IOException {
540554 }
541555 }
542556
543- if (useVertexColors ) {
544- geom .getMaterial ().setBoolean ("UseVertexColor" , useVertexColors );
545- }
546-
547557 geom .setName (name + "_" + index );
548558
549559 geom .updateModelBound ();
@@ -802,7 +812,75 @@ protected ByteBuffer getBytes(int bufferIndex, String uri, Integer bufferLength)
802812 return data ;
803813 }
804814
805- public Material readMaterial (int materialIndex ) throws IOException {
815+ public Material readMaterial (int materialIndex , boolean usesVertexColors ) throws IOException {
816+ // Fallback to the old material adapter system, if the legacy flag is set.
817+ if (GltfUtils .isMaterialAdaptersEnabled (info )) {
818+ return readMaterialUsingMaterialAdapters (materialIndex , usesVertexColors );
819+ }
820+
821+ assertNotNull (materials , "There is no material defined yet a mesh references one" );
822+ JsonObject materialJson = materials .get (materialIndex ).getAsJsonObject ();
823+
824+ GltfMaterialData gltfMaterialData = readStandardMaterialParameters (materialJson );
825+ gltfMaterialData .setHasVertexColors (usesVertexColors );
826+ gltfMaterialData = customContentManager .readExtensionAndExtras ("material" , materialJson , gltfMaterialData );
827+ return createMaterial (gltfMaterialData , materialIndex );
828+ }
829+
830+ protected GltfMaterialData readStandardMaterialParameters (JsonObject materialJson ) throws IOException {
831+ GltfMaterialData gltfMaterialData = new GltfMaterialData ();
832+ gltfMaterialData .setGltfParam (MATERIAL_NAME_PARAM , getAsString (materialJson , "name" ));
833+
834+ JsonObject pbrMetallicRoughnessJson = materialJson .getAsJsonObject ("pbrMetallicRoughness" );
835+ if (pbrMetallicRoughnessJson != null ) {
836+ gltfMaterialData .setGltfParam (BASE_COLOR_PARAM , getAsColor (pbrMetallicRoughnessJson , "baseColorFactor" ));
837+ gltfMaterialData .setGltfParam (BASE_COLOR_TEXTURE_PARAM , getAsTexture2D (pbrMetallicRoughnessJson , "baseColorTexture" ));
838+ gltfMaterialData .setGltfParam (METALLIC_FACTOR_PARAM , getAsFloat (pbrMetallicRoughnessJson , "metallicFactor" ));
839+ gltfMaterialData .setGltfParam (ROUGHNESS_FACTOR_PARAM , getAsFloat (pbrMetallicRoughnessJson , "roughnessFactor" ));
840+ gltfMaterialData .setGltfParam (METALLIC_ROUGHNESS_TEXTURE_PARAM , getAsTexture2D (pbrMetallicRoughnessJson , "metallicRoughnessTexture" ));
841+ }
842+
843+ JsonObject normalTextureJson = materialJson .getAsJsonObject ("normalTexture" );
844+ if (normalTextureJson != null ) {
845+ gltfMaterialData .setGltfParam (NORMAL_TEXTURE_PARAM , readTexture (normalTextureJson ));
846+ gltfMaterialData .setGltfParam (NORMAL_SCALE_PARAM , getAsFloat (normalTextureJson , "scale" ));
847+ useNormalsFlag = true ;
848+ }
849+
850+ JsonObject occlusionTextureJson = materialJson .getAsJsonObject ("occlusionTexture" );
851+ if (occlusionTextureJson != null ) {
852+ gltfMaterialData .setGltfParam (OCCLUSION_TEXTURE_PARAM , readTexture (occlusionTextureJson ));
853+ gltfMaterialData .setGltfParam (OCCLUSION_TEXTURE_STRENGTH_PARAM , getAsFloat (occlusionTextureJson , "strength" ));
854+ }
855+
856+ gltfMaterialData .setGltfParam (EMISSIVE_TEXTURE_PARAM , getAsTexture2D (materialJson , "emissiveTexture" ));
857+ gltfMaterialData .setGltfParam (EMISSIVE_COLOR_PARAM , getAsColor (materialJson , "emissiveFactor" ));
858+
859+ String alphaMode = getAsString (materialJson , "alphaMode" );
860+ gltfMaterialData .setGltfParam (ALPHA_MODE_PARAM , alphaMode );
861+ if ("MASK" .equals (alphaMode )) {
862+ gltfMaterialData .setGltfParam (ALPHA_CUTOFF_PARAM , getAsFloat (materialJson , "alphaCutoff" ));
863+ }
864+
865+ gltfMaterialData .setGltfParam (DOUBLE_SIDED_PARAM , getAsBoolean (materialJson , "doubleSided" ));
866+
867+ return gltfMaterialData ;
868+ }
869+
870+ protected Material createMaterial (GltfMaterialData gltfMaterialData , int materialIndex ) {
871+ for (GltfMaterialFactory gltfMaterialFactory : materialFactoryList ) {
872+ if (gltfMaterialFactory .accepts (info .getKey (), gltfMaterialData )) {
873+ return gltfMaterialFactory .createMaterial (info .getManager (), info .getKey (), gltfMaterialData );
874+ }
875+ }
876+
877+ logger .log (Level .WARNING , "Couldn't find any matching GltfMaterialFactory for material " + materialIndex );
878+ useNormalsFlag = false ;
879+ return defaultMat ;
880+ }
881+
882+ @ Deprecated
883+ protected Material readMaterialUsingMaterialAdapters (int materialIndex , boolean usesVertexColors ) throws IOException {
806884 assertNotNull (materials , "There is no material defined yet a mesh references one" );
807885
808886 JsonObject matData = materials .get (materialIndex ).getAsJsonObject ();
@@ -875,6 +953,8 @@ public Material readMaterial(int materialIndex) throws IOException {
875953
876954 adapter .setParam ("emissiveTexture" , readTexture (matData .getAsJsonObject ("emissiveTexture" )));
877955
956+ adapter .setParam ("usesVertexColors" , usesVertexColors );
957+
878958 return adapter .getMaterial ();
879959 }
880960
@@ -922,6 +1002,10 @@ public void readCameras() throws IOException {
9221002 }
9231003 }
9241004
1005+ protected Texture2D getAsTexture2D (JsonObject jsonObject , String textureName ) throws IOException {
1006+ return readTexture (jsonObject .getAsJsonObject (textureName ));
1007+ }
1008+
9251009 public Texture2D readTexture (JsonObject texture ) throws IOException {
9261010 return readTexture (texture , false );
9271011 }
@@ -1715,4 +1799,44 @@ public static void registerDefaultExtrasLoader(Class<? extends ExtrasLoader> loa
17151799 public static void unregisterDefaultExtrasLoader () {
17161800 CustomContentManager .defaultExtraLoaderClass = UserDataLoader .class ;
17171801 }
1802+
1803+ /**
1804+ * Registers a new material factory and places it before all existing factories.<br/>
1805+ * The ordering of these factories defines their priority. When a new material needs to be created,
1806+ * the loader searches for the first material factory that accepts the given material data.
1807+ *
1808+ * @param materialFactory The {@link GltfMaterialFactory} to register.
1809+ */
1810+ public static void registerMaterialFactoryFirst (GltfMaterialFactory materialFactory ) {
1811+ unregisterMaterialFactory (materialFactory .getClass ());
1812+ materialFactoryList .add (0 , materialFactory );
1813+ }
1814+
1815+ /**
1816+ * Registers a new material factory and places it behind all existing factories.<br/>
1817+ * The ordering of these factories defines their priority. When a new material needs to be created,
1818+ * the loader searches for the first material factory that accepts the given material data.
1819+ *
1820+ * @param materialFactory The {@link GltfMaterialFactory} to register.
1821+ */
1822+ public static void registerMaterialFactoryLast (GltfMaterialFactory materialFactory ) {
1823+ unregisterMaterialFactory (materialFactory .getClass ());
1824+ materialFactoryList .add (materialFactory );
1825+ }
1826+
1827+ /**
1828+ * Unregisters a material factory by its class.
1829+ *
1830+ * @param materialFactoryClass The class of the {@link GltfMaterialFactory} to unregister.
1831+ */
1832+ public static void unregisterMaterialFactory (Class <? extends GltfMaterialFactory > materialFactoryClass ) {
1833+ materialFactoryList .removeIf (materialFactoryClass ::isInstance );
1834+ }
1835+
1836+ /**
1837+ * Unregisters all material factories.
1838+ */
1839+ public static void unregisterAllMaterialFactories () {
1840+ materialFactoryList .clear ();
1841+ }
17181842}
0 commit comments