Setting A Stationary Background Image In JME3

I need to be able to set the background of my Canvas to an image and no matter how I move the camera, the 3d environment will update accordingly, but unlike a skybox, but the image will stay the same position on the screen. I then need to be able to update this background image as i receive frames from a video. The images I receive from the camera are of type BufferedImage and i need to be able to convert this to something usable my JME, but my main problem is creating a background that for one, does not cover up the 3d environment, two, does not move as the camera is moved, and finally is able to be updated as i receive more imagery. Thank you for any help you can supply.

2 Likes

Since what you’re trying to do haven’t been done before, I guess I’ll have to explain it myself.



[java]Picture p = new Picture(“background”);

p.setMaterial( bgMat );

p.setWidth(settings.getWidth());

p.setHeight(settings.getHeight());

p.setPosition(0, 0);

p.updateGeometricState();



ViewPort pv = renderManager.createPreView(“background”, cam);

pv.setClearFlags(true, true, true);

pv.attachScene§;



viewPort.setClearFlags(false, true, true);[/java]



To achieve that, a picture object is created, the size of the entire screen, it is then attached to a “pre viewport” which is rendered before the primary viewport. The clear flags must be set on the primary viewport so that it does not clear color but it does clear depth. This allows the picture to appear through as the background.

Thank you, my main question was answered perfectly. I now am left with 2 problems. The first problem is using a java.awt.image.BufferedImage for my background, and my second problem is updating the background when i receive a new java.awt.image.BufferedImage. For the first problem I have seen many posts where they use TextureManager to get a texture from a buffered image, but it appears that TextureManager is not part of JME3.

1 Like

I’ve played with using a BufferedImage as a texture in JME. Here is how I do it:

[java]

BufferedImage map…

AWTLoader loader = new AWTLoader();

Image image = loader.load(map, true);

Texture texture = new Texture2D();

texture.setImage(image);

[/java]

Using AWTLoader is a little odd but it has all of the code to do it and is really convenient.

And it’s pretty simple.

THANK YOU :slight_smile: everything is working great now

1 Like

Hello,



When I try this example with a simple white background image, the white background image is always painted over my 3d scene not beyond. Any idea?



Thanks.



Regards,

Equi

Which viewport did you put it in? Sounds like it is ending up in the GUI viewport… which is not what you want.

To a previewport.



thanks.

Equi

I am back on a project using JME3 and i am again attempting the same task I did a year ago, and using the example code above to do it.

I do not have my code from back then so i am not sure what i did to get this working or if things have just changed enough in JME3 so that this no longer works, but i can not get this example code to run anymore. Now when i try to run this, if i attach the Picture to the preview viewport, i get the runtime error - "IllegalStateException: Scene graph is not properly updated for rendering. If i simple just set a background color on the preview viewport it works fine. What i am trying to do is work on an augmented reality program and i need to stream video to the background that i can overlay 3d graphics onto. Here is the simplest code to demonstrate this issue, but if there is a better way to show a stream of images onto the background in JME3 please let me know.

[java]

public class TestBGImage extends SimpleApplication

{

public static void main(String[] args)

{

TestBGImage app = new TestBGImage();

app.start();

}



@Override

public void simpleInitApp()

{

Box b = new Box(Vector3f.ZERO, 1, 1, 1);

Geometry geom = new Geometry(“Box”, b);

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

mat.setTexture(“ColorMap”, assetManager.loadTexture(“Interface/Logo/Monkey.jpg”));

geom.setMaterial(mat);

rootNode.attachChild(geom);



Picture p = new Picture(“background”);

p.setImage(assetManager, “Interface/Logo/Monkey.png”, false);



p.setWidth(settings.getWidth());

p.setHeight(settings.getHeight());

p.setPosition(0, 0);

p.updateGeometricState();



ViewPort pv = renderManager.createPreView(“background”, cam);

pv.setClearFlags(true, true, true);



pv.attachScene§;

// pv.setBackgroundColor(ColorRGBA.Red);



viewPort.setClearFlags(false, true, true);

}

}

[/java]

2 Likes

moving p.updateGeometricState(); to the end of simpleInit works (Just something i tried)

1 Like

Thanks, that worked.

1 Like

I think that’s because the ViewPort isn’t being properly managed. That’s probably ok in this case but yeah, it has to be updated after being attached to the viewport.



Normally, each frame you’d call updateLogicalState() and updateGeometricState() on the root nodes in a ViewPort. In this case, it’s probably ok but you should be aware that regular JME Controls won’t work properly on the Picture because of this.

hi!



i tried that snippet in my existing code and it’s now working. no matter what kind of imagetype (png, jpg, …) i try, all i get is a black background although i’m setting the background of the primary viewport to gray. further more if an objects is moved somehow, it gets redrawn at the new position but is not deleted at the old one. i put the code at the end of the simpleInitApp method of my class which extends the SimpleApplication. am i forgetting something?



thx, kopi

Noob here, When i tried this I am getting
java.lang.IllegalStateException: Scene graph is not properly updated for rendering.
State was changed after rootNode.updateGeometricState() call.
Make sure you do not modify the scene from another thread!
Problem spatial name: background
at com.jme3.scene.Spatial.checkCulling(Spatial.java:260)
at com.jme3.renderer.RenderManager.renderSubScene(RenderManager.java:647)
at com.jme3.renderer.RenderManager.renderScene(RenderManager.java:640)
at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:974)
at com.jme3.renderer.RenderManager.render(RenderManager.java:1023)
at mygame.MyGame.update(SkyRoads.java:254)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:744)

You have to manage your viewport and call the appropriate update methods. There are about 100 threads on here about it. Search for ViewportAppState maybe or just search for the error you got.

I was trying to do something and i found what you need.

If the fragment shader, if you do :

float x = gl_FragCoord.x / the_with_of_the_viewport;
float y = gl_FragCoord.y / the_height_of_the_viewport;

gl_FragColor = texture2D(your_texture, vec2(x, y));

You’ll be good.
gl_FragCoord is the pixel position on the window. If you divide it by the with/height of the window, it will be in [0, 1]
So it will display your image it you use that as texture coordinates.

I am using this previewport technique to draw a background and it was working fine. until I tried to make one of the objects in the scene (regular viewport) transparent. I am using the Unshaded material with the ColorRGBA.BlackNoAlpha color. I also added this to the Bucket.Transparent bucket. When I render this, the object is black instead of transparent.

My guess is that being transparent is just displaying the background of the viewport which is black and that is then covering the previewport.

How can I have transparent objects not cover the previewport?

Thanks

i think maybe you forgot aboud Additional Render state. Transparent bucket + render state required.

geom.getMaterial().getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);

Also, if you want transparent over render over render, you need set Clear flags to false for color(so it will have previous render color)

viewPort.setClearFlags(false, true, false);

first param was color (if you clear it, it will override, so leave color as false as i remember)

1 Like

Forgot to mention. For preViewport I am setting flags as true, true, true. for regular viewport I am setting flags as false, true, true. so should I set to false the stencil as well?

I will also give the render state a try. Thanks!

Edit: I tried the BlendMode and it worked! I didn’t have to change the stencil. Again, thanks a lot!

2 Likes