Best way to save TextureArray?

I’m trying to extract the embedded materials from my terrains to save them for editing purposes, but I am getting this error when I try to save a material that has a TextureArray. It consistently works fine for any terrain material that does not have texture array matParams, so I am assuming that is the cause.

Here is the error that happens when calling j3mExporter.save(terrainMaterial, savePath); to save a material with a texture array:

java.lang.NullPointerException
	at com.jme3.material.plugin.export.material.J3MOutputCapsule.formatMatParamTexture(J3MOutputCapsule.java:160)
	at com.jme3.material.plugin.export.material.J3MOutputCapsule.format(J3MOutputCapsule.java:86)
	at com.jme3.material.plugin.export.material.J3MOutputCapsule.writeStringSavableMap(J3MOutputCapsule.java:79)
	at com.jme3.material.Material.write(Material.java:1049)
	at com.jme3.material.plugin.export.material.J3MExporter.save(J3MExporter.java:56)
	at com.jme3.material.plugin.export.material.J3MExporter.save(J3MExporter.java:65)
	at SceneTools.TerrainTool.preSave(TerrainTool.java:753)
	at Core.SceneState.preSave(SceneState.java:1248)
	at Core.SceneState.saveTile(SceneState.java:720)
	at Core.SceneInputState$1.onAction(SceneInputState.java:400)
	at com.jme3.input.InputManager.invokeActions(InputManager.java:171)
	at com.jme3.input.InputManager.onKeyEventQueued(InputManager.java:471)
	at com.jme3.input.InputManager.processQueue(InputManager.java:865)
	at com.jme3.input.InputManager.update(InputManager.java:917)
	at com.jme3.app.LegacyApplication.update(LegacyApplication.java:724)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:246)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:153)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:193)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:234)
	at java.base/java.lang.Thread.run(Thread.java:834)

I tried to find the J3MExporter class on github to take a look at the line of code throwing the error, but couldn’t find it in the materials package I expected it to be based in its package declaration.

Any help is greatly appreciated :slightly_smiling_face:

1 Like

For future reference:
image

Then:
image

Third result:

Edit: and then you can “Hey! The lines don’t match up.” and then you can ask yourself which version of JME you use, etc… which is what we’d then have to do.

2 Likes

It looks like the null error is due to the material’s TextureArrays having a null AssetKey when the material is being saved.

This line specifically:

Is it possible to save an entire Texture Array in some other format like DDS (i think?) that supports multiple image layers? I tried saving as standard PNG just to try it, but did not expect it to work since all png/jpg saving methods with JME I’ve seen save a single image, wheras the TextureArray contains a list of images that need saved to a single asset key.

Or is it just better to recreate the TextureArray at run time and avoid saving/loading any TextureArrays? This is what I’m currently doing, and going this route I could just bypass the null error in my original post by saving a blank string as the asset key for any TextureParams that are actually Texture Arrays.

1 Like

Sorry for bumping my own thread, but I’m curious if anyone has any input on the best way to go forward with ‘saving’ a material with a texture array

I have 3 ideas so far:

  1. Avoid saving the texture array, and set a blank texture key in the material and just recreate it on launch by my own means

  2. Make a PR to J3MExporter to append all of the texture keys within the TextureArray into a single concatenated string, and have the J3MExporter load and recreate the TextureArray using these texture keys

  3. Make a PR that tries to save the texture array in an image format that supports multipe image layers.

Number 3 sounds easiest but I have no clue how to properly save/load formats other than single image png/jpg types so I’m leaning towards number 2. But number 2 would also recreate a new texture array for every material, even if the texture arrays are identical.

I would like to hear some input from others before I attempt to add code to a class within the core engine.

1 Like

Since TextureArray implements Savable, it ought to be possible to write a TextureArray with a null key to a J3O file using binaryExporter.save(textureArray, file) .

Without compression, this might be inefficient use of storage. But it ought to work.

1 Like

Sounds good, when I get a chance I will submit a PR saving the texture array to j3o.

It’s looking like I will want to make a PR to the J3MExporter class I linked, and also to the read method of the Material class.

Specifically, I will add an if statement at this line to check if the MatParamTexture is of VarType TextureArray, and if so I will make it then read / write the mat param for the texture array as a normal j3o file instead.

I think this is well beyond scope for the moment, but this could be a good candidate for optimization down the line by saving in KTX format.

1 Like