From cac820803bdcc8819d3ba09b7a5ee71d5b799d52 Mon Sep 17 00:00:00 2001 From: "Sha..rd" Date: Sat, 12 May 2012 18:38:31 +0000 Subject: [PATCH] * Better checking for MRT in renderer (first against max color attachments then against draw buffers) * Now uses only OpenGL2 draw buffers instead of relying on GL_ARB_draw_buffers existing * copyFrameBuffer() was non-functional when used against the main framebuffer because the width/height were set to zero erroneously, now it uses the current viewport parameters. * Added TestRenderToCubemap to demonstrate render to cubemap functionality, it also uses MRT to render to all the cube sides git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9378 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../jme3/renderer/lwjgl/LwjglRenderer.java | 57 ++++++-- .../jme3test/post/TestRenderToCubemap.java | 132 ++++++++++++++++++ 2 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 engine/src/test/jme3test/post/TestRenderToCubemap.java diff --git a/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java b/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java index 939fc158d..6d19a70d7 100644 --- a/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java +++ b/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java @@ -355,12 +355,19 @@ public class LwjglRenderer implements Renderer { logger.log(Level.FINER, "Texture Multisample Depth Samples: {0}", maxDepthTexSamples); } - if (ctxCaps.GL_ARB_draw_buffers) { + glGetInteger(GL_MAX_DRAW_BUFFERS, intBuf16); + maxMRTFBOAttachs = intBuf16.get(0); + if (maxMRTFBOAttachs > 1) { caps.add(Caps.FrameBufferMRT); - glGetInteger(ARBDrawBuffers.GL_MAX_DRAW_BUFFERS_ARB, intBuf16); - maxMRTFBOAttachs = intBuf16.get(0); logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); } + +// if (ctxCaps.GL_ARB_draw_buffers) { +// caps.add(Caps.FrameBufferMRT); +// glGetInteger(ARBDrawBuffers.GL_MAX_DRAW_BUFFERS_ARB, intBuf16); +// maxMRTFBOAttachs = intBuf16.get(0); +// logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); + //} } if (ctxCaps.GL_ARB_multisample) { @@ -1175,11 +1182,26 @@ public class LwjglRenderer implements Renderer { public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { if (GLContext.getCapabilities().GL_EXT_framebuffer_blit) { + int srcX = 0; + int srcY = 0; int srcW = 0; int srcH = 0; + + int dstX = 0; + int dstY = 0; int dstW = 0; int dstH = 0; + int prevFBO = context.boundFBO; + + if (mainFbOverride != null) { + if (src == null) { + src = mainFbOverride; + } + if (dst == null) { + dst = mainFbOverride; + } + } if (src != null && src.isUpdateNeeded()) { updateFrameBuffer(src); @@ -1191,8 +1213,10 @@ public class LwjglRenderer implements Renderer { if (src == null) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); -// srcW = viewWidth; -// srcH = viewHeight; + srcX = vpX; + srcY = vpY; + srcW = vpW; + srcH = vpH; } else { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, src.getId()); srcW = src.getWidth(); @@ -1200,20 +1224,22 @@ public class LwjglRenderer implements Renderer { } if (dst == null) { glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); -// dstW = viewWidth; -// dstH = viewHeight; + dstX = vpX; + dstY = vpY; + dstW = vpW - 1; + dstH = vpH - 1; } else { glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dst.getId()); - dstW = dst.getWidth(); - dstH = dst.getHeight(); + dstW = dst.getWidth() - 1; + dstH = dst.getHeight() - 1; } int mask = GL_COLOR_BUFFER_BIT; if (copyDepth) { mask |= GL_DEPTH_BUFFER_BIT; } glBlitFramebufferEXT(0, 0, srcW, srcH, - 0, 0, dstW, dstH, mask, - GL_NEAREST); + 0, 0, dstW, dstH, mask, + GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prevFBO); @@ -1563,11 +1589,16 @@ public class LwjglRenderer implements Renderer { context.boundReadBuf = -2; } } else { + if (fb.getNumColorBuffers() > maxFBOAttachs) { + throw new RendererException("Framebuffer has more color " + + "attachments than are supported" + + " by the video hardware!"); + } if (fb.isMultiTarget()) { if (fb.getNumColorBuffers() > maxMRTFBOAttachs) { throw new RendererException("Framebuffer has more" - + " targets than are supported" - + " on the system!"); + + " multi targets than are supported" + + " by the video hardware!"); } if (context.boundDrawBuf != 100 + fb.getNumColorBuffers()) { diff --git a/engine/src/test/jme3test/post/TestRenderToCubemap.java b/engine/src/test/jme3test/post/TestRenderToCubemap.java new file mode 100644 index 000000000..5eced134e --- /dev/null +++ b/engine/src/test/jme3test/post/TestRenderToCubemap.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.TextureCubeMap; +import com.jme3.util.SkyFactory; + +/** + * Renders a rotating box to a cubemap texture, then applies the cubemap + * texture as a sky. + */ +public class TestRenderToCubemap extends SimpleApplication { + + private Geometry offBox; + private float angle = 0; + private ViewPort offView; + + public static void main(String[] args){ + TestRenderToCubemap app = new TestRenderToCubemap(); + app.start(); + } + + public Texture setupOffscreenView(){ + Camera offCamera = new Camera(512, 512); + + offView = renderManager.createPreView("Offscreen View", offCamera); + offView.setClearFlags(true, true, true); + offView.setBackgroundColor(ColorRGBA.DarkGray); + + // create offscreen framebuffer + FrameBuffer offBuffer = new FrameBuffer(512, 512, 1); + + //setup framebuffer's cam + offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f); + offCamera.setLocation(new Vector3f(0f, 0f, -5f)); + offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y); + + //setup framebuffer's texture + TextureCubeMap offTex = new TextureCubeMap(512, 512, Format.RGBA8); + offTex.setMinFilter(Texture.MinFilter.Trilinear); + offTex.setMagFilter(Texture.MagFilter.Bilinear); + + //setup framebuffer to use texture + offBuffer.setDepthBuffer(Format.Depth); + offBuffer.setMultiTarget(true); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeX); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveX); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeY); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveY); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeZ); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveZ); + + //set viewport to render to offscreen framebuffer + offView.setOutputFrameBuffer(offBuffer); + + // setup framebuffer's scene + Box boxMesh = new Box(Vector3f.ZERO, 1,1,1); + Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m"); + offBox = new Geometry("box", boxMesh); + offBox.setMaterial(material); + + // attach the scene to the viewport to be rendered + offView.attachScene(offBox); + + return offTex; + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(3, 3, 3)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + + Texture offTex = setupOffscreenView(); + rootNode.attachChild(SkyFactory.createSky(assetManager, offTex, false)); + } + + @Override + public void simpleUpdate(float tpf){ + Quaternion q = new Quaternion(); + + angle += tpf; + angle %= FastMath.TWO_PI; + q.fromAngles(angle, 0, angle); + + offBox.setLocalRotation(q); + offBox.updateLogicalState(tpf); + offBox.updateGeometricState(); + } +} \ No newline at end of file