Custom mesh shapes not loading in SceneComposer

Hi there,

I’m actually playing around with custom mesh shapes.
While creating them now works fine for me, saving them in a j3o file seems to cause problems.

I wrote some code in which I create a custom mesh and add it to the root node.
Then I save the root node in a j3o file.
When I try to load this file in the SceneComposer i get a NullPointerException: Box has null mesh.
Can this behaviour be changed?

Here is my code:

Main.java:
[java]package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import java.io.File;
import java.io.IOException;

/**

  • test

  • @author brother.byto
    */
    public class Main extends SimpleApplication {

    public static void main(String[] args) {
    Main app = new Main();
    app.start();
    }

    @Override
    public void simpleInitApp() {
    //Box b = new Box(Vector3f.ZERO, 1, 1, 1);

     BigPoint a = new BigPoint(new Vector3f(0,1,0), new Vector3f(0,0,10));
     BigPoint b = new BigPoint(new Vector3f(0,0,5), new Vector3f(0,0,0));
     
     TileMesh mesh = new TileMesh(a,b,3);
     Geometry geom = new Geometry("Box", mesh);
    
     Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
     mat.setColor("Color", ColorRGBA.Blue);
     geom.setMaterial(mat);
    
     rootNode.attachChild(geom);
     
     BinaryExporter exporter = BinaryExporter.getInstance();
     File file = new File("./assets/Models/test.j3o");
     try {
         exporter.save(rootNode, file);
     } catch (IOException e) {
         System.err.println("Error: " + e.getMessage());
     }
    

    }

    @Override
    public void simpleUpdate(float tpf) {
    //TODO: add update code
    }

    @Override
    public void simpleRender(RenderManager rm) {
    //TODO: add render code
    }
    }
    [/java]

TileMesh.java:
[java]package mygame;

import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;

/**
*

  • @author brother.byto
    */
    public class TileMesh extends Mesh {

    Vector3f [] vertices = new Vector3f[8];
    Vector2f[] texCoord = new Vector2f[8];
    int [] indexes = { 2,1,0, 1,2,3, 0,4,1, 4,5,1, 3,5,1, 3,7,5,
    0,4,2, 2,4,6, 2,3,7, 2,7,6, 4,5,6, 5,7,6};

    public TileMesh(BigPoint start, BigPoint end, float width){

     Vector3f base = new Vector3f(width/2f,0,0);
     
     Quaternion quat1 = new Quaternion();
     Quaternion quat2 = new Quaternion();
     
     float[] angles1 = new float[]{start.rot.x / 180 * FastMath.PI,
         start.rot.y / 180 * FastMath.PI,start.rot.z / 180 * FastMath.PI};
     float[] angles2 = new float[]{end.rot.x / 180 * FastMath.PI,
         end.rot.y / 180 * FastMath.PI,end.rot.z / 180 * FastMath.PI};
     
     quat1.fromAngles(angles1);
     quat2.fromAngles(angles2);
     
     Vector3f mod1 = quat1.mult(base);
     Vector3f mod2 = quat2.mult(base);
     
     vertices[0] = (start.pos).subtract(mod1);
     vertices[1] = (start.pos).add(mod1);
     vertices[2] = (end.pos).subtract(mod2);
     vertices[3] = (end.pos).add(mod2);
     vertices[4] = ((start.pos).subtract(mod1)).subtract(new Vector3f(0,1,0));
     vertices[5] = ((start.pos).add(mod1)).subtract(new Vector3f(0,1,0));
     vertices[6] = ((end.pos).subtract(mod2)).subtract(new Vector3f(0,1,0));
     vertices[7] = ((end.pos).add(mod2)).subtract(new Vector3f(0,1,0));
     
     texCoord[0] = new Vector2f(0,0);
     texCoord[1] = new Vector2f(1,0);
     texCoord[2] = new Vector2f(0,1);
     texCoord[3] = new Vector2f(1,1);
     texCoord[4] = new Vector2f(0,0);
     texCoord[5] = new Vector2f(1,0);
     texCoord[6] = new Vector2f(0,1);
     texCoord[7] = new Vector2f(1,1);
     
     this.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
     this.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));
     this.setBuffer(Type.Index,    3, BufferUtils.createIntBuffer(indexes));
     this.updateBound();
    

    }

}
[/java]

BigPoint.java:
[java]package mygame;

import com.jme3.math.Vector3f;

/**
*

  • @author brother.byto
    */
    public class BigPoint {

    public Vector3f pos;
    public Vector3f rot;

    public BigPoint(){
    this.pos = new Vector3f();
    this.rot = new Vector3f();
    }

    public BigPoint(Vector3f pos, Vector3f rot){
    this.pos = pos;
    this.rot = rot;
    }

}
[/java]

Problem solved,

adding an empty standard Constructor to the TileMesh class seems to do the trick.

Thanks anyways

1 Like

You should also implement read/write methods and recreate the mesh based on the info given when it was created with the other constructor.

1 Like

Hi Normen,

Thanks for the hint.
I found that read/write methods are “specified” in Savable, but i didn’t quite get how they should work.
I suppose, that the write method should recreate the mesh as you mentioned.
Can you give me an example on how these methods could look like?
It would really help me understand these things.
Thank you.

Hey,

I now implemented the read/write methods similar to those in the AbstractBox class.
I don’t know if I did it the right way, but everything still works as before.