[SOLVED] Offscreen buffer renderer

I don’t expect to much, but I’m hoping someone could come up with a theory on what might be happening.

I have 2 off screen buffers, one for GUI and another for 3D renderer. I then take the 2d image and attach a geometry to the guiNode, so it will be displayed.

It works fine to a point. Inside simpleupdate, I update both buffers and it displays the screen correctly.

    public void simpleUpdate(float tpf) 
    {
    	//We need to make sure the game Node gets updated, since it is not
    	//tied to guiNode or rootNode.  We have to call it manually.
//    	offView.setClearFlags(true, true, true);

    	List<Spatial> scenes = offView.getScenes();
        for (Spatial scene : scenes) {
            scene.updateLogicalState(tpf);
            scene.updateGeometricState();
        }

    	
    }

Where I have the issue is when I go back to main menu. I detach 3d Geometry from guiNode. the gui Texture is always attached. When I click on play again, at start of the game the 3d Texture is re-attached to guiNode. Using the old buffer and geometry. It is only created once at start and I try to use it over and over again. The 3d Geometry texture is the ALWAYS the last frame of the first time played.

I’ve stepped through code, and it is still processing guiBuffer and 3dBuffer and their scenes. The gui texture gets updated and displayed correctly. But the 3d texture will remain the last frame from the first time. It never gets updated.

Does any one have any ideas where to look at to see why the texture is not being updated after the scene is processed.

I thought (not tried) to kill the buffer and re-create it every time the game starts and when the game quits, instead of just detach to release it.

Thanks for any help.

What’s the goal here? What are you actually trying to accomplish with this technique?

If i understand it correctly, you have two offscreen framebuffers that render on two textures: the GUI and the GAME.
You show one or the other to the player by attaching their texture to a material on a spatial attached to the SimpleApplication.guiNode (eg. a quad or picture).

But the GAME target is never updated after the first swap.

I suppose you are using two viewports as well? Or do you render them manually?
Maybe you should post this code because the setup that you have described should work.

I would like to post code, but my code is huge. Not possible to pull it out of the project.
I would have to write a simple application to be able to post it.


In the picture above. That is showing two offscreen buffer renders. I attach 2 spatial (texture) geometries to SimpleApplication.guiNode.

The gui one is on top, the 3d is below. From the picture, you can see the play area, that is the 3d scene rendered to a texture and that texture is assigned to a “Box” (geometry) and attached to guiNode.

The gui screen is attach as startup and stays attach at all time. The 3d texture is only attached when the player clicks on start, and when the game is over it is detached.

Inside Main.cpp (which is the SimpleApplication).

	public void simpleUpdate(float tpf)
	{
    	for (FrameBufferItem frameBuffer : offViewBuffers)
    	{
    		if (frameBuffer.isEnabled())
    			frameBuffer.simpleUpdate(tpf);
    	}
		renderTo3DFrameBuffer.simpleUpdate(tpf);
		renderToGUIFrameBuffer.simpleUpdate(tpf);

Ignore the first part where it talks about offViewBuffers. That is completely something different. That is for Gui area that need scroll bars with clipping. So is can display text that is clipped on left/right or top/down and have scroll bars. Since JME does not have the ability to easy define an area and clip it like OpenGL offers, due to structure.

The renderT03dFrameBufrfer and renderToGuiFrameBuffer, do what I’m talking about.

    public void simpleUpdate(float tpf) 
    {
    	//We need to make sure the game Node gets updated, since it is not
    	//tied to guiNode or rootNode.  We have to call it manually.

    	List<Spatial> scenes = offView.getScenes();
        for (Spatial scene : scenes) {
            scene.updateLogicalState(tpf);
            scene.updateGeometricState();
        }

    	
    }

Inside those classes (same class), they handle rendering the scene to the texture.

When the player plays for the first time, everything works. Say play dies and goes back to main menu and then clicks play again. Then the 3d texture is never updated and the texture remains unchange from the last frame from the first game. No matter how many times the player quits and tries playing again. Has to shutdown the game and relaunch it.

The definition of the off screen buffer is as follows:

	public Texture setupOffscreenViewPort(RenderManager renderManager, Camera camera, Texture texture)
	{
		offCamera = camera.clone();
		float aspect = (float) offCamera.getWidth() / offCamera.getHeight();
		// setup framebuffer's cam
		offCamera.resize(width, height, true);
		offCamera.setFrustumPerspective(60, aspect, 1, 1000);

		offView = renderManager.createPreView(name + " 3D Offscreen View", offCamera);
		if (texture != null)
			offView.setClearFlags(false, true, true);
		else
			offView.setClearFlags(true, true, true);
		offView.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f));
		// create offscreen framebuffer
		FrameBuffer offBuffer = new FrameBuffer(width, height, 1);

		// setup framebuffer's texture
		Texture2D offTex = new Texture2D(width, height, Format.RGBA8);
		offTex.setMinFilter(Texture.MinFilter.Trilinear);
		offTex.setMagFilter(Texture.MagFilter.Bilinear);

		if (texture != null)
		{
			offTex.setImage(texture.getImage());
		}

		// setup framebuffer to use texture
		offBuffer.setDepthBuffer(Format.Depth);
		FrameBufferTextureTarget buffTar = FrameBufferTarget.newTarget((Texture) offTex);
//	      FrameBufferTextureTarget buffTar =  FrameBufferTarget.newTarget(background);
//	      Texture texture = buffTar.getTexture();
		if (texture != null)
			texture.getImage().setFormat(Format.RGBA8);
		offBuffer.addColorTarget(buffTar);

		// set viewport to render to offscreen framebuffer
		offView.setOutputFrameBuffer(offBuffer);

//	      fbNode.setQueueBucket(Bucket.Gui);

		// attach the scene to the viewport to be rendered
		foregroundNode.setCullHint(CullHint.Never);

		offView.attachScene(foregroundNode);

		return offTex;
	}

	public void simpleUpdate(float tpf)
	{
		// We need to make sure the game Node gets updated, since it is not
		// tied to guiNode or rootNode. We have to call it manually.
//    	offView.setClearFlags(true, true, true);

		List<Spatial> scenes = offView.getScenes();
		for (Spatial scene : scenes)
		{
			scene.updateLogicalState(tpf);
			scene.updateGeometricState();
		}

	}

It is basically taken from the example from JME.

I got it. The game grabbed the camera and set it to be the player camera. I made a reference to the camera but during quit, it killed the player camera. When I restarted the game, it tried to use the old player camera but it became invalid.

So when the game starts again, I recreated the new camera and assigned it to the buffer and player camera and it worked.

3 Likes

I’m glad you’ve resolved it. I think you should also look into how the texture is used in setupOffscreenViewPort , i am not sure why you are setting the image like so and changing the format without altering the image data buffer to match it might have unexpected results.
Eg. if your image is RGB you are setting it to RGBA without adding the extra channel to the data buffer that will still contain the image encoded as RGB.

You should probably recreate the texture to match the framebuffer on setupOffscreenViewPort and return it to your code. The image can be initialized with a null data buffer if it is used only on the gpu, so you won’t have a big overhead.