Save j3m

Hey guys,



Is there any way to create and save from the code a j3m file obtained by geometry.getMaterial()?



Thanks in advance,



Florin

Open the model in the SceneComposer and select “create j3m” in the material property.

1 Like

@normen, thanks for reply, that I learned from docs, the question was on generating j3m file without the SDK, from the code, similar on how its possible to export j3o files with BinaryExporter.save(node, file) method (or SaveGame.save from jme3tools.savegame.SaveGame)

No, you’d have to do it manually. Whats the point though? The way I see it you either create them before (SDK/j3m) or you just use Material objects in code. If you save a j3o it will save the material data along with it.

@fbucur , other way you should make your own xml/json material file and parse it.



i did like that:

http://code.google.com/p/rise-of-mutants/source/browse/dev/trunk/TechDemo/assets/Scripts/Scenes/level_01.json

@normen the point is to create an utility for editing 3D models, it seems that j3o export does not save the new material, just a reference to what material is used by the geometry.



@mifth that’s exactly what i tried to avoid, thanks, i’ll do it after all.



Thank you both, all thins are clear now :roll:

No, the j3o saves the material, you do something else wrong. If the material is set via a j3m then that j3m will be loaded if its available, else it falls back to the material stored in the j3o. Mifths suggestion doesn’t make much sense to me unless its generic data and not material data (e.g. you store more info about the appearance that are not related to the actual material shader).

@normen, I agree with you on the generic data part.

However, if for example I create a mesh, I create a material, assign texture maps and export it as j3o (none of those with the SDK), when I load the j3o it has no material. If I load a j3o with a material set and I replace it with a new material, same. If I load a j3o with material and edit the texture, if saved and reloaded, the material is unchanged, the new textures are not saved.

Hence the idea that j3o does not contain material data, but only material reference.

Note that the path for textures is unchanged!

I will double-check anyway if something’s wrong with my code. Thanks.

@fbucur said:
However, if for example I create a mesh, I create a material, assign texture maps and export it as j3o (none of those with the SDK), when I load the j3o it has no material. If I load a j3o with a material set and I replace it with a new material, same. If I load a j3o with material and edit the texture, if saved and reloaded, the material is unchanged, the new textures are not saved.

As I said, you do something wrong. The j3o does save the material. Most probably you get the paths wrong as they have to be absolute from the beginning. Theres a reason the SDK does things the way it does them.

The J3O stores absolute paths, e.g. according to where you loaded them in the first place. If you loaded the texture from “Textures/XYZ.png”, then that path will be stored as-is in the J3O and loaded from there when you load that model.

Hello again :slight_smile:



Circling back to this issue, I made a little tescase to prove what is the problem I encounter.

There are 3 cubes, 1st with a loaded .j3m, the material is modified and added to the 2nd cube, which is saved and loaded as cube 3.

As you can see the changes on the material are not saved! So where do I do this the wrong way?



[java]public class TestSaveMaterial extends SimpleApplication {



public static void main(String[] args) {

TestSaveMaterial app = new TestSaveMaterial();

app.start();

}



@Override

public void simpleInitApp() {

Box box1 = new Box(new Vector3f(-3f, 1f, 0f), 1f, 1f, 1f);

Geometry cube1 = new Geometry("box1", box1);

Material mat = assetManager.loadMaterial("Materials/newMaterial.j3m");

cube1.setMaterial(mat);

rootNode.attachChild(cube1);



Box box2 = new Box(new Vector3f(0f, 1f, 0f), 1f, 1f, 1f);

Geometry cube2 = new Geometry("box2", box2);

Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg");

Material mat2 = mat.clone();

mat2.setTexture("DiffuseMap", tex);

cube2.setMaterial(mat2);

rootNode.attachChild(cube2);



Node boxNode = new Node();

boxNode.attachChild(cube2.clone());

String userHome = System.getProperty("user.home");

BinaryExporter exporter = BinaryExporter.getInstance();

File file = new File(userHome + "/Models/" + "box2.j3o");

try {

exporter.save(boxNode, file);

} catch (IOException ex) {

Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Error: Failed to save model!", ex);

}



assetManager.registerLocator(userHome, FileLocator.class);

Node cube3 = (Node) assetManager.loadModel("Models/box2.j3o");

cube3.setName("loaded node");

cube3.setLocalTranslation(new Vector3f(3f, 0f, 0f));

rootNode.attachChild(cube3);



DirectionalLight sun = new DirectionalLight();

sun.setDirection(new Vector3f(1, 0, -2).normalizeLocal());

sun.setColor(ColorRGBA.White);

rootNode.addLight(sun);

}

}[/java]



Material file:

[java]Material My Material : Common/MatDefs/Light/Lighting.j3md {

MaterialParameters {

DiffuseMap : Textures/Terrain/BrickWall/BrickWall.jpg

}

AdditionalRenderState {

}

}[/java]



LE: the clone methods can be removed and you will just 2 cubes with the same effect…

@fbucur said:So where do I do this the wrong way?

You clone the material, don't do that. Just either load a new one and change that or assign the same one if its meant to be the same.

@normen, the clone methods, as I said earlier are just for the example, even if I remove the clones, the effect is the same…

Ah, do you have the j3m file in the path when you load the j3o? When a material has been assigned via j3m it will be loaded and assigned when the j3o is loaded and the j3m is available. Only if the j3m isn’t available the j3o content will be used.

Hence the need to save the j3m file… Is it possible to ignore the existing j3m when j3o is loaded? Or to put the data in j3o as priority and only if not present then go for the j3m?

No but you can create the material and its settings in code instead of from a j3m, such a material is not bound to its j3m file.

Thanks, I created an issue report here:

https://code.google.com/p/jmonkeyengine/issues/detail?id=555



If you find a fix, please post a diff patch that we can apply to the engine.

I’ve looked into it and it seems its not possible to solve this issue without user intervention. When you modify the material and want the changes to be written into the exported the J3O file, you have to force set the key to null. E.g. material.setKey(null), then export the model.

1 Like
@Momoko_Fan said:
I've looked into it and it seems its not possible to solve this issue without user intervention. When you modify the material and want the changes to be written into the exported the J3O file, you have to force set the key to null. E.g. material.setKey(null), then export the model.

As said in the issue, they are always written to the j3o file, just that the key reference makes it load that key and overwrite them.
1 Like