Texture (originating from Buffered image) loses mips when saved to j3o

Problem

I’ve been trying to build my geometries (including textures) at build time (as a gradle task) and then saving them as j3os to use at run time. I also do some image manipulation so I start with BufferedImages which I then turn into Textures (rather than the more normal loading them using the asset loader, in which case this problem does not occur).

Steps to reproduce

If I do the following:

  1. Load a buffered image from disk

    BufferedImage textureAsImage = ImageIO.read(new File("src/main/resources/textures/square.png"));
    
  2. Convert it to a texture

     AWTLoader loader=new AWTLoader();
     Texture texture = new Texture2D(loader.load(textureAsImage, false));
    
  3. Set a magfilter that implies mips

     texture.setMinFilter(Texture.MinFilter.Trilinear);
    

Then if I use that geometry immediately it looks great

image

But if instead I save it as a j3o and reload it later it looks aliased

image

Getting out the debugger I can see that after the image is reloaded from the j3o it thinks it doesn’t need to generate mips

But before it went in it did

So I think this may be a j3o serialisation problem?

Complete example

First run with loadFromDisk = false (which will save to j3o) then run with loadFromDisk = true

public class J3oTest extends SimpleApplication {

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

    boolean loadFromDisk = false;

    @Override
    public void simpleInitApp() {
        if (loadFromDisk){
            loadBoxFromDisk();
        } else {
            createNewBox();
        }
    }

    void loadBoxFromDisk(){
        Spatial geom = assetManager.loadModel("Models/cube.j3o");
        rootNode.attachChild(geom);
    }

    void createNewBox(){
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

        BufferedImage textureAsImage;
        try{
            textureAsImage = ImageIO.read(new File("src/main/resources/textures/square.png"));
        } catch(IOException e){
            throw new RuntimeException(e);
        }
        AWTLoader loader=new AWTLoader();
        Texture texture = new Texture2D(loader.load(textureAsImage, false));
        texture.setMinFilter(Texture.MinFilter.Trilinear);
        mat.setTexture("ColorMap", texture);
        geom.setMaterial(mat);

        BinaryExporter exporter = BinaryExporter.getInstance();
        try{
            exporter.save(geom, new File("src/main/resources/Models/cube.j3o"));
        } catch(IOException e){
            throw new RuntimeException(e);
        }

        rootNode.attachChild(geom);
    }

}

Next steps

I’m going to have more of a dig but wanted to see if anyone knew if this was a known issue or I’m doing something wrong

1 Like

Hmm, a dig has produced interesting results. The write method of Image looks like:

@Override
public void write(JmeExporter e) throws IOException {
    OutputCapsule capsule = e.getCapsule(this);
    capsule.write(format, "format", Format.RGBA8);
    capsule.write(width, "width", 0);
    capsule.write(height, "height", 0);
    capsule.write(depth, "depth", 0);
    capsule.write(mipMapSizes, "mipMapSizes", null);
    capsule.write(multiSamples, "multiSamples", 1);
    capsule.writeByteBufferArrayList(data, "data", null);
    capsule.write(colorSpace, "colorSpace", null);
}

I.e. it never writes mipsWereGenerated and needGeneratedMips. I’d be right in saying that’s an omission? I’ll try that locally tomorrow and see if that fixes it. Anyone know if there is a good reason not to serialise those

Edit; and by tomorrow I mean right now. Adding mipsWereGenerated and needGeneratedMips to the read and write does fix this. I really will leave it now and wait to see if anyone answers the “is there is a good reason not to serialise those” question. If not I’ll add this in as a bugfix

?

4 Likes

@oxplay2 Ah you’re right. It was the [Building from source] bit of [Building from source and changing the j3o serialisation] that solved this. Thanks! Looks like this will get sorted out with JME 3.7

3 Likes