* 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
3.0
Sha..rd 13 years ago
parent fba447dc60
commit cac820803b
  1. 57
      engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java
  2. 132
      engine/src/test/jme3test/post/TestRenderToCubemap.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()) {

@ -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();
}
}
Loading…
Cancel
Save