Unexpected texture offset


#1

Hello,

I’m trying to load a texture from a java.awt.Image, and then apply it on a surface (let’s start simple : a flat rectangle).
I made a simple example so that you get my problem :

  1. here is a link to an example image of the java.awt.Image I would like to put on a texture (a white backgound with 3 black rectangles in 3 corners) :
    Image

  2. Here is the code (actually some others objects are generated, I am focusing on the one that doesn’t work) :
    // Geometry, Material
    Vector3f[] pos = new Vector3f[4];
    pos[0] = new Vector3f(0, 0, 0);
    pos[1] = new Vector3f(10, 0, 0);
    pos[2] = new Vector3f(10, 10, 0);
    pos[3] = new Vector3f(0, 10, 0);

    Vector2f[] texCoord = new Vector2f[4];
    texCoord[0] = new Vector2f(0, 0);
    texCoord[1] = new Vector2f(1, 0);
    texCoord[2] = new Vector2f(1, 1);
    texCoord[3] = new Vector2f(0, 1);

    int[] faces = new int[] {
    0, 2, 1,
    0, 3, 2
    };

    Mesh mesh = new Mesh();
    mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
    mesh.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));
    mesh.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(faces));
    mesh.updateBound();

    Geometry geo = new Geometry(“BgTest”, mesh);
    Material mat = new Material(
    getAssetManager(),
    “Common/MatDefs/Misc/Unshaded.j3md”);
    geo.setMaterial(mat);
    parentNode.attachChild(geo);

    // [For this example] Loading the image from the file I described above
    BufferedImage bi = ImageIO.read(new File(“PathToFile\BG.jpg”));
    // Applying the image as a Texture to the object
    Image image = new AWTLoader().load(bi, false);
    Texture texture = new Texture2D(image);
    mat.setTexture(“ColorMap”, texture);

  3. And here is the result :
    JME

It looks like there is an “weird offset” when the texture reads the image data, but as far as I looked, I couldn’t find out why…
I tried with other images (varying type (grayscale image, color image), dimensions…), and it rarely works (the applied texture looks like the original JPG file), and most often doesn’t work (the offset is present, and varies : the angle of the blocks aren’t always the same).

After having spent one day on the matter, I decided to ask you all : do you have any idea why I have that kind of “offset” ?
Thanks a lot !

Jeremy.


#2

Does it work if you load BG.jpg the regular way as a texture asset?


#3

Same image, loaded with the AssetManager :
texture = this.getAssetManager().loadTexture(“BG.jpg”);

… gives :

It isn’t the same result as my first image, because I have the flip option of AWTLoader to false, in my first example.
I then tried to run my first code again with the flip option to true, and it produces exactly the same result :
// [For this example] Loading the image from the file I described above
BufferedImage bi = ImageIO.read(new File(“PathToFile\BG.jpg”));
// Applying the image as a Texture to the object
Image image = new AWTLoader().load(bi, true);

ImageIO does not seem to be the cause of my issue…


#4

Then it’s probably that your texture coordinates are messed up. Try with a regular JME Quad instead of your hand-rolled code.


#5

I’ve tried many texture coordinate changes, but none has solved the issue.

Here is a picture of the result with a Quad mesh, but I’m afraid there is no change :frowning:


(actually, I hadn’t much hope since my code in the first post is inspired from the Quad class file)

Here is the code :

Mesh mesh = new Quad(100, 50);

Geometry geo = new Geometry(“BgTest”, mesh);
Material mat = new Material(
   getAssetManager(),
   “Common/MatDefs/Misc/Unshaded.j3md”);
geo.setMaterial(mat);
parentNode.attachChild(geo);

// [For this example] Loading the image from the file I described above
BufferedImage bi = ImageIO.read(new File(“PathToFile\BG.jpg”));
// Applying the image as a Texture to the object
Image image = new AWTLoader().load(bi, false);
Texture texture = new Texture2D(image);
mat.setTexture(“ColorMap”, texture);

Any new idea ? Thanks !


#6

Use a Quad and load the image as a regular texture.

When that doesn’t work try a different image.


#7

Even with the regular texture loading, the result is the same (except the flipping) :


… with this code :

Mesh mesh = new Quad(100, 50);

Geometry geo = new Geometry(“BgTest”, mesh);
Material mat = new Material(
   getAssetManager(),
   “Common/MatDefs/Misc/Unshaded.j3md”);
geo.setMaterial(mat);
parentNode.attachChild(geo);

// [For this example] Loading the image from the file I described above
Texture texture = this.getAssetManager().loadTexture("BG.jpg")
mat.setTexture(“ColorMap”, texture);

I’m afraid I can’t change the image I’m trying to display : I’m getting the AWT Image as is (actually the image isn’t read from disk, but directly generated in Java).
My goal is then to put it on a surface in JMonkeyEngine. It turns out I have the same problem with an image loaded from disk, hence the questions above.

I’m pretty sure that I could understand my initial problem (pure Java) by solving this new one (image from file).

Do you have another idea ? Thanks.

Jeremy.


#8

The JPG seems to be messed up in a way that even Java doesn’t like. Trying a different image would prove that.

If you are trying to go from raw image data to JME then don’t do it through a messed up JPG. Write that code and we can help debug that.

If you have to use a file… maybe try a different format like PNG.


#9

OK I’ll explain the full story then. I’m connecting images loaded in ImageJ (ImageJ) to a 3D view in JMonkeyEngine.

In ImageJ, every 3D image is an ImagePlus, which itself is made of several ImageProcessor, containing the 2D slices of the image. I’m working with a specific type of ImageProcessor called ShortProcessor, containing a 16-bit unsigned 2D image.

This ImageProcessor class has a getBufferedImage method, that returns the image as a BufferedImage. That is the real way I’m getting the BufferedImage.

If I write the BufferedImage to disk, and then open it with ImageJ, or any image viewer (like the Windows one), it works fine, I see my picture as it should be.

However, transferring the BufferedImage to JMonkeyEngine produces the kind of weird images I showed above, with the “offset impression”.
The actual code is :

Mesh mesh = new Quad(100, 50);

Geometry geo = new Geometry(“BgTest”, mesh);
Material mat = new Material(
   getAssetManager(),
   “Common/MatDefs/Misc/Unshaded.j3md”);
geo.setMaterial(mat);
parentNode.attachChild(geo);

// Getting the current displayed ImageProcessor in IJ
BufferedImage bi = IJ.getImage().getProcessor().getBufferedImage();
// Applying the image as a Texture to the object
Image image = new AWTLoader().load(bi, false);
Texture texture = new Texture2D(image);
mat.setTexture(“ColorMap”, texture);

In my first post, I didn’t want to bother you with the ImageJ part, I used ImageIO.write(bi, "jpg", new File("BG.jpg")); to write my ImageJ processor down to disk and then loaded it from disk.

Does it help you ? Thanks.


#10

i dont remember now, but there was some topic about some issue in bufferedImage and solved by setting some param of image. not sure if related anyway.


#11

Does it work if you change it to a different format as I already suggested?
ImageIO.write(bi, "png", new File("BG.png"));


#12

I’m spent a lot of time looking for answers on this forum, but didn’t find the post you’re talking about. Any clue to find it again ?

Just tried (link to the png file) : no change at all, I’m afraid, in both ways :

ImageIO.write(bi, "png", new File("BG.png")); // Then transfered to Texture
// OR 
Texture texture = this.getAssetManager().loadTexture("BG.png");

I’m going to try rewriting the whole BufferedImage from the ImageJ pixel values (inspired by here). I’ll let you know if I get anything good.

I’m still open to any new idea :slight_smile:


#13

Hi all,

I’ve got something new, that shifts the problem from a texture problem to another topic, I think…

Some context to start : I’m integrating JMonkeyEngine to an existing frame in Swing. I used the “Swing integration” tutorial. In all my previous posts, I was thinking I was doing something wrong with the way I was using textures.
After discussing with you, I understood it might be something else. So I decided to create the simpliest possible code, and created a SimpleApplication displaying a Quad with my example texture… And it worked fine !

I then added the Swing integration, and it went back wrong.

Here is the whole code I tested (and the texture file here); put the inSwing boolean to false, and the texture will be displayed all right; put it to true, and it fails :

import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeCanvasContext;
import com.jme3.texture.Texture;

public class TestTexture extends SimpleApplication {
    public static void main(String[] args) {
    	/*
    	 * JMonkeyEngine as an independant program if false, or integrated 
    	 * to a Swing frame if true
    	 */
    	boolean inSwing = true;

    	
    	TestTexture app = new TestTexture();
    	if (inSwing) {
        	AppSettings settings = new AppSettings(true);
        	settings.setWidth(640);
        	settings.setHeight(480);

        	app.setSettings(settings);
        	app.createCanvas();
        	JmeCanvasContext ctx = (JmeCanvasContext) app.getContext();
        	ctx.setSystemListener(app);
        	Dimension dim = new Dimension(640, 480);
        	ctx.getCanvas().setPreferredSize(dim);

        	JFrame window = new JFrame("Texture");
        	window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        	JPanel panel = new JPanel(new FlowLayout());
        	panel.add(ctx.getCanvas());
        	window.add(panel);
        	window.pack();
        	window.setVisible(true);

        	app.startCanvas();
    	} else {
            app.start();
    	}
    }

    @Override
    public void simpleInitApp() {
    	/*
    	 * Just a quad with the texture applied on it
    	 */
        Quad q = new Quad(5, 10);
        Geometry geom = new Geometry("Plane", q);
        Material mat = new Material(this.assetManager,
          "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.White);

		Texture texture = this.getAssetManager().loadTexture("BG.png");
		mat.setTexture("ColorMap", texture);

        geom.setMaterial(mat);
        this.rootNode.attachChild(geom);
    }
}

Have you already seen something like this ? I tried some searches with “JMonkeyEngine swing texture”, but haven’t found anything useful yet.


#14

There are some unexplained issues with the Swing canvas in JME. For instance:

https://github.com/jMonkeyEngine/jmonkeyengine/issues/428

Perhaps someone should dig a little deeper…


#15

Does one of you know any “trick” to make it work ? An option to turn on or off that would put it back to work ?


#16

I’ve tried some things, mostly by turning on and off the options in AppSettings, or by changing the Renderer, but nothing has worked so far… :tired_face:

If any of you has got something, I’m definitely interested !


#17

Have you found a solution to your issue?


#18

Hi all,

I’ve found another way but it is far from the perfect solution regarding what I wanted to do : I’m just using JMonkeyEngine in its standard way, with an external frame, and no integration in my Swing canvas.

I’m still interested in solutions or ideas you might have. :slight_smile: