Hi,
I’m currently working on an application using interactive genetic algorithms to evolve 3d objects.
Maybe you want to have a look at a video I’ve done before:
http://www.youtube.com/watch?v=7v5BAiXcUrs
The application shows “rooms” as textures on sliding panels. These are using offscreen rendering. When a panel is destroyed, the offscreen processor is also removed and viewport and framebuffer gets destroyed. This used to work fine some months ago (with jme svn rev. 6207), but now I often get a renderer crash on Renderer.deleteFrameBuffer(). The Exception is:
SCHWERWIEGEND: Problem FBO:
FrameBuffer[format=1024x1024x1, drawBuf=0]
Depth => BufferTarget[format=Depth]
Color(0) => TextureTarget[format=RGBA8]
04.07.2011 11:32:40 com.jme3.app.Application handleError
SCHWERWIEGEND: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.IllegalStateException: Framebuffer is missing required attachment.
at com.jme3.renderer.lwjgl.LwjglRenderer.checkFrameBufferError(LwjglRenderer.java:1269)
at com.jme3.renderer.lwjgl.LwjglRenderer.setFrameBuffer(LwjglRenderer.java:1523)
at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:1103)
at com.jme3.renderer.RenderManager.render(RenderManager.java:1159)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:264)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:144)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:218)
at java.lang.Thread.run(Thread.java:662)
I’m using the following code for my offscreen processor, adapted from jme’s TestRenderToMemory:
[java]import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture2D;
public class OffscreenProcessor implements SceneProcessor {
private int renderWidth = 512;
private int renderHeight = 512;
private FrameBuffer offscreenBuffer;
private Camera offscreenCam;
private final Node offscreenScene;
private ViewPort offscreenView;
private final AssetManager assetManager;
private RenderManager rm;
private final AppSettings settings;
private ColorRGBA backgroundColor = ColorRGBA.White;
// the texture to render to
private Texture2D texture;
// the material that will be created
private final Material material;
// the key to apply the texture to the material
private final String textureKey;
/**
- Creates a new offscreen texture processor with a SimpleTextured material.
*
-
@param assetManager
-
The AssetManager<br />
-
@param settings
-
The application settings<br />
-
@param scene
-
The scene that will be rendered<br />
-
@param material
-
The material to apply the texture to<br />
-
@param textureKey
-
The texture key used to apply the texture<br />
*/
public OffscreenProcessor(final AssetManager assetManager,
final AppSettings settings, final Node scene, final Material material,
final String textureKey) {
this.assetManager = assetManager;
this.settings = settings;
this.offscreenScene = scene;
this.material = material;
this.textureKey = textureKey;
init();
}
/**
- Pre-initializes the processor.
*/
private void init() {
// update the state of the offscreen scene
offscreenScene.updateGeometricState();
texture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
offscreenCam = new Camera(renderWidth, renderHeight);
}
/**
- Sets the size of the offscreen texture.
*
-
@param width
-
With of the texture<br />
-
@param height
-
Height of the texture<br />
*/
public void setTextureSize(final int width, final int height) {
this.renderWidth = width;
this.renderHeight = height;
init();
}
@Override
public void initialize(final RenderManager rm, final ViewPort vp) {
this.rm = rm;
// create a pre-view. a view that is rendered before the main view
offscreenView = rm.createPreView("Offscreen View", offscreenCam);
offscreenCam.setFrustum(vp.getCamera().getFrustumNear(), vp.getCamera()
.getFrustumFar(), vp.getCamera().getFrustumLeft(), vp.getCamera()
.getFrustumRight(), vp.getCamera().getFrustumTop(), vp.getCamera()
.getFrustumBottom());
offscreenView.setClearFlags(true, true, true);
offscreenView.setBackgroundColor(backgroundColor);
// create offscreen framebuffer
offscreenBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
// setup framebuffer to use texture
offscreenBuffer.setDepthBuffer(Format.Depth);
offscreenBuffer.setColorTexture(texture);
// set viewport to render to offscreen framebuffer
offscreenView.setOutputFrameBuffer(offscreenBuffer);
// attach the scene to the viewport to be rendered
offscreenView.attachScene(offscreenScene);
// apply the texture
material.setTexture(textureKey, texture);
// EffectsFactory.addShadowProcessor(assetManager, settings, offscreenView,
// new Vector3f(7, 2, 3));
// EffectsFactory.addLightScatteringProcessor(assetManager, settings,
// offscreenView, new Vector3f(2, .1f, 2));
// EffectsFactory.addSSAOProcessor(assetManager, settings, offscreenView);
}
@Override
public void reshape(final ViewPort vp, final int w, final int h) {
}
@Override
public boolean isInitialized() {
return rm != null;
}
@Override
public void preFrame(final float tpf) {
}
@Override
public void postQueue(final RenderQueue rq) {
}
@Override
public void postFrame(final FrameBuffer out) {
}
@Override
public void cleanup() {
offscreenBuffer.clearColorTargets();
cleanup();
offscreenView.clearScenes();
offscreenView.setOutputFrameBuffer(null);
rm.clearQueue(offscreenView);
rm.removePreView(offscreenView);
// TODO this often causes a renderer crash
rm.getRenderer().deleteFrameBuffer(offscreenBuffer);
rm.getRenderer().deleteImage(texture.getImage());
while (offscreenView.getProcessors().size() > 0) {
final SceneProcessor proc = offscreenView.getProcessors().get(0);
offscreenView.removeProcessor(proc);
}
}
/**
- Getter for the camera.
*
-
@return The camera of the offscreen scene
*/
public Camera getCamera() {
return offscreenCam;
}
/**
- Getter for the material to render to.
*
-
@return The material on which is rendered
*/
public Material getMaterial() {
return material;
}
/**
- Getter for the offscreen scene.
*
-
@return The scene being rendered off screen
*/
public Node getScene() {
return offscreenScene;
}
/**
- Getter for the background color of the scene.
*
-
@return The color of the background
*/
public ColorRGBA getBackgroundColor() {
return backgroundColor;
}
/**
- Setter for the background color of the scene.
*
-
@param backgroundColor
-
The color of the background<br />
*/
public void setBackgroundColor(final ColorRGBA backgroundColor) {
this.backgroundColor = backgroundColor;
if (isInitialized()) {
offscreenView.setBackgroundColor(backgroundColor);
}
}
}[/java]
The ViewPort.removeProcessor() method is called from the update() method.I already tried to change the order in the cleanup() method, but it did’nt help. When I remove the Renderer.deleteFrameBuffer() call, the error disappears but I need to clean up the frame buffers. A also tried to invoke the framebuffer cleanup later using Application.enqueue, but nothing changed.
Can someone give me a hint to solve this error?