import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
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.Spatial;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.util.BufferUtils;
import com.jme3.util.Screenshots;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.LinkedList;
public class RenderToTexture extends Texture2D implements SceneProcessor
{
private RenderManager renderManager;
private ViewPort viewport;
private boolean enabled = true;
private transient float time;
private transient float updateTime = 1 / 30f;
private ByteBuffer cpuBuf;
private LinkedList<Spatial> offscreenScenes;
public RenderToTexture(String name, int width, int height, RenderManager renderManager)
{
this(name, width, height, Format.RGBA8, 1, new Camera(width, height), renderManager);
}
public RenderToTexture(String name, int width, int height, Format format, int sample, Camera camera, RenderManager renderManager)
{
//MemoryTracer.trace(this);
setMinFilter(Texture.MinFilter.Trilinear);
init(name, format, sample, camera, renderManager);
}
private void init(String viewPortName, Format format, int sample, Camera camera, RenderManager renderManager)
{
this.renderManager = renderManager;
final int width = camera.getWidth();
final int height = camera.getHeight();
viewport = renderManager.createPreView(viewPortName, camera);
//viewport.setClearEnabled(true);
viewport.setClearFlags(true, true, true);
viewport.setBackgroundColor(ColorRGBA.BlackNoAlpha);
// setup framebuffer's texture
Image image = new Image(format, width, height, null);
setImage(image);
FrameBuffer frameBuffer = new FrameBuffer(width, height, sample);
frameBuffer.setDepthBuffer(Format.Depth);
frameBuffer.setColorTexture(this);
viewport.setOutputFrameBuffer(frameBuffer);
}
public ViewPort getViewPort()
{
return viewport;
}
public void setScene(final Spatial... target)
{
viewport.clearScenes();
attachScene(target);
}
public void attachScene(final Spatial... target)
{
for (Spatial spatial : target)
{
viewport.attachScene(spatial);
}
}
public void attachOffscreenScene(final Spatial... target)
{
if (offscreenScenes == null)
{
offscreenScenes = new LinkedList<Spatial>();
viewport.addProcessor(this);
}
for (Spatial s : target)
{
offscreenScenes.add(s);
viewport.attachScene(s);
}
}
public boolean hasScene(final Spatial target)
{
return viewport.getScenes().contains(target);
}
public Camera getCamera()
{
return viewport.getCamera();
}
public void setBackgroundColor(ColorRGBA bg)
{
viewport.setBackgroundColor(bg);
}
public void setRefreshTime(final float time)
{
updateTime = time;
}
public void setEnabled(final boolean enable)
{
viewport.setEnabled(enable);
}
public void takeSnapshot()
{
time = updateTime;
}
public void reset()
{
viewport.clearScenes();
setEnabled(false);
}
public void dispose()
{
reset();
setEnabled(false);
}
public BufferedImage getBufferedImage(BufferedImage bufferedImage)
{
final int width = getCamera().getWidth();
final int height = getCamera().getHeight();
if (cpuBuf == null)
{
cpuBuf = BufferUtils.createByteBuffer(width * height * 4);
}
if (bufferedImage == null)
{
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
}
cpuBuf.clear();
renderManager.getRenderer().readFrameBuffer(viewport.getOutputFrameBuffer(), cpuBuf);
synchronized (bufferedImage)
{
Screenshots.convertScreenShot(cpuBuf, bufferedImage);
}
return bufferedImage;
}
public void useRenderBuffer()
{
FrameBuffer fb = getViewPort().getOutputFrameBuffer();
fb.setDepthBuffer(Format.Depth);
fb.setColorBuffer(Format.RGBA8);
}
public void initialize(RenderManager rm, ViewPort vp)
{
}
public void reshape(ViewPort vp, int w, int h)
{
}
public boolean isInitialized()
{
return false;
}
public void preFrame(float tpf)
{
for (Spatial s : offscreenScenes)
{
s.updateLogicalState(tpf);
s.updateGeometricState();
}
time += tpf;
if (time >= updateTime)
{
time = 0;
viewport.setEnabled(enabled);
}
else
{
viewport.setEnabled(false);
}
}
public void postQueue(RenderQueue rq)
{
}
public void postFrame(FrameBuffer out)
{
viewport.setEnabled(enabled);
}
public void cleanup()
{
renderManager.removePreView(viewport);
}
public void read(JmeImporter importer) throws IOException
{
}
public void write(JmeExporter exporter) throws IOException
{
}
}
Just an updated version of a helper class malova posted (actually now I post it I’m wondering if it’ll work on 3.1…)
Usage:
RenderToTexture rtt = new RenderToTexture("RTT", chosenWidth, chosenHeight, Format.ABGR8, 0, cameraNewOrSameOne, renderManager);
rtt.attachOffscreenScene(someNodeThatIsNotTheRootNodeYouStartWithNorIsItAttachedToRootNode);
Since RenderToTexture is a texture, materials can be set to use at as diffuse, or filters or anything. Just thought I’d post it since I normally make a proper mess using render to texture, and this helped me keep things clean.