// This code example is created for educational purpose // by Thorsten Thormaehlen (contact: www.thormae.de). // It is distributed without any warranty. import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.nio.ByteBuffer; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.opengl.glu.GLU; import javax.swing.JFrame; import com.jogamp.opengl.util.FPSAnimator; class Renderer { private GLU glu = new GLU(); public float t = 0.0f; public int mode = 1; private int[] fboID = {0}; private int[] depthID = {0}; private int fboTexSize = 512; private int width = 0; private int height = 0; //private int[] vertBufID = new int[1]; public void init(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL graphics context gl.glEnable(GL2.GL_DEPTH_TEST); // create a frame buffer object gl.glGenFramebuffers(1, fboID, 0); // bind the frame buffer gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, fboID[0]); // Generate render texture // this is not used (but some drivers require it) int[] texID = {0}; gl.glGenTextures (1, texID, 0); gl.glBindTexture(GL2.GL_TEXTURE_2D, texID[0]); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE); int level = 0; ByteBuffer fakeColorBuffer = ByteBuffer.allocateDirect(fboTexSize * fboTexSize * 4); gl.glTexImage2D(GL2.GL_TEXTURE_2D, level, GL2.GL_RGBA, fboTexSize, fboTexSize, 0, GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, fakeColorBuffer); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE); // Attach the texture to the fbo gl.glFramebufferTexture2D(GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0, GL2.GL_TEXTURE_2D, texID[0], level); if(!checkFramebufferStatus(d)) System.exit(1); // Generate depth render texture gl.glGenTextures (1, depthID, 0); gl.glBindTexture(GL2.GL_TEXTURE_2D, depthID[0]); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE); ByteBuffer fakeDepthBuffer = ByteBuffer.allocateDirect(fboTexSize * fboTexSize); gl.glTexImage2D(GL2.GL_TEXTURE_2D, level, GL2.GL_DEPTH_COMPONENT, fboTexSize, fboTexSize, 0, GL2.GL_DEPTH_COMPONENT, GL2.GL_UNSIGNED_BYTE, fakeDepthBuffer); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE); // Attach the texture to the fbo gl.glFramebufferTexture2D(GL2.GL_FRAMEBUFFER, GL2.GL_DEPTH_ATTACHMENT, GL2.GL_TEXTURE_2D, depthID[0], level); if(!checkFramebufferStatus(d)) System.exit(1); // unbind texture gl.glBindTexture(GL2.GL_TEXTURE_2D, 0); //unbind fbo gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0); } public void resize(GLAutoDrawable d, int w, int h) { width = w; height = h; changeViewport(d, w, h); } private void changeViewport(GLAutoDrawable d, int w, int h) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context gl.glViewport(0, 0, w, h); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective (30.0, (float)w/(float)h, 7.0, 12.0); } private void changeViewportOrtho(GLAutoDrawable d, int w, int h) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context float aspect = (float)w/(float)h; gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); gl.glOrtho(-1.0*aspect, 1.0*aspect, -1.0, 1.0, -1.0, 1.0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); } public void display(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context if(mode > 0) { // bind the fbo gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, fboID[0]); changeViewport(d, fboTexSize, fboTexSize); }else{ changeViewport(d, width, height); } gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // render to attached fbo drawScene(d); if(mode == 1) { // unbind frame buffer gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0); changeViewportOrtho(d, width, height); // using first render pass result as texture gl.glEnable(GL2.GL_TEXTURE_2D); gl.glBindTexture(GL2.GL_TEXTURE_2D, depthID[0]); //draw quad with depth texture gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL2.GL_POLYGON); gl.glTexCoord2f(0.00f,0.00f); gl.glVertex3f(-1.0f,-1.0f, 0.0f); gl.glTexCoord2f(1.00f,0.00f); gl.glVertex3f( 1.0f,-1.0f, 0.0f); gl.glTexCoord2f(1.00f,1.00f); gl.glVertex3f( 1.0f, 1.0f, 0.0f); gl.glTexCoord2f(0.00f,1.00f); gl.glVertex3f(-1.0f, 1.0f, 0.0f); gl.glEnd(); gl.glDisable(GL2.GL_TEXTURE_2D); } gl.glFlush(); } // returns a valid textureID on success, otherwise 0 private void drawScene(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); // set camera glu.gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); // draw scene gl.glRotatef(t, 0.0f, 0.0f, 1.0f); drawTexturedCube(d); } private boolean checkFramebufferStatus(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context int status = gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER); switch(status) { case GL2.GL_FRAMEBUFFER_COMPLETE: return true; case GL2.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: throw new RuntimeException("Framebuffer incomplete, incomplete attachment"); case GL2.GL_FRAMEBUFFER_UNSUPPORTED: throw new RuntimeException("Unsupported framebuffer format"); case GL2.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: throw new RuntimeException("Framebuffer incomplete, missing attachment"); case GL2.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: throw new RuntimeException("Framebuffer incomplete, missing draw buffer"); case GL2.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: throw new RuntimeException("Framebuffer incomplete, missing read buffer"); } return false; } private void drawTexturedCube(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL2.GL_POLYGON); gl.glTexCoord2f(0.00f,0.00f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glTexCoord2f(1.00f,0.00f); gl.glVertex3f(-1.0f,-1.0f, 1.0f); gl.glTexCoord2f(1.00f,1.00f); gl.glVertex3f( 1.0f,-1.0f, 1.0f); gl.glTexCoord2f(0.00f,1.00f); gl.glVertex3f( 1.0f, 1.0f, 1.0f); gl.glEnd(); gl.glColor3f(1.0f,1.0f,0.0f); gl.glBegin(GL2.GL_POLYGON); gl.glTexCoord2f(0.00f,0.00f); gl.glVertex3f(-1.0f, 1.0f,-1.0f); gl.glTexCoord2f(1.00f,0.00f); gl.glVertex3f(-1.0f,-1.0f,-1.0f); gl.glTexCoord2f(1.00f,1.00f); gl.glVertex3f(-1.0f,-1.0f, 1.0f); gl.glTexCoord2f(0.00f,1.00f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glEnd(); gl.glColor3f(0.0f,0.0f,1.0f); gl.glBegin(GL2.GL_POLYGON); gl.glTexCoord2f(0.00f,0.00f); gl.glVertex3f( 1.0f, 1.0f, 1.0f); gl.glTexCoord2f(1.00f,0.00f); gl.glVertex3f( 1.0f,-1.0f, 1.0f); gl.glTexCoord2f(1.00f,1.00f); gl.glVertex3f( 1.0f,-1.0f,-1.0f); gl.glTexCoord2f(0.00f,1.00f); gl.glVertex3f( 1.0f, 1.0f,-1.0f); gl.glEnd(); gl.glColor3f(1.0f,0.0f,1.0f); gl.glBegin(GL2.GL_POLYGON); gl.glTexCoord2f(0.00f,0.00f); gl.glVertex3f(-1.0f, 1.0f,-1.0f); gl.glTexCoord2f(1.00f,0.00f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glTexCoord2f(1.00f,1.00f); gl.glVertex3f( 1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.00f,1.00f); gl.glVertex3f( 1.0f, 1.0f,-1.0f); gl.glEnd(); gl.glColor3f(0.0f,1.0f,1.0f); gl.glBegin(GL2.GL_POLYGON); gl.glTexCoord2f(0.00f,0.00f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.00f,0.00f); gl.glVertex3f(-1.0f, -1.0f,-1.0f); gl.glTexCoord2f(1.00f,1.00f); gl.glVertex3f( 1.0f, -1.0f,-1.0f); gl.glTexCoord2f(0.00f,1.00f); gl.glVertex3f( 1.0f, -1.0f, 1.0f); gl.glEnd(); gl.glColor3f(0.0f,1.0f,0.0f); gl.glBegin(GL2.GL_POLYGON); gl.glTexCoord2f(0.00f,0.00f); gl.glVertex3f( 1.0f, 1.0f,-1.0f); gl.glTexCoord2f(1.00f,0.00f); gl.glVertex3f( 1.0f,-1.0f,-1.0f); gl.glTexCoord2f(1.00f,1.00f); gl.glVertex3f(-1.0f,-1.0f,-1.0f); gl.glTexCoord2f(0.00f,1.00f); gl.glVertex3f(-1.0f, 1.0f,-1.0f); gl.glEnd(); } } class MyGui extends JFrame implements GLEventListener { private Renderer renderer; public void createGUI() { setTitle("Press 1 to toggle between first/second render pass"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GLProfile glp = GLProfile.getDefault(); GLCapabilities caps = new GLCapabilities(glp); GLCanvas canvas = new GLCanvas(caps); setSize(320, 320); getContentPane().add(canvas); final FPSAnimator ani = new FPSAnimator(canvas, 60, true); canvas.addGLEventListener(this); setVisible(true); renderer = new Renderer(); canvas.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent event) { boolean redraw = false; String modeStr = ""; switch(event.getKeyCode()) { case '1': if(renderer.mode == 1) { renderer.mode = 0; modeStr = "first render pass result"; } else { renderer.mode = 1; modeStr = "second render pass result"; } redraw = true; break; } if(redraw) { // done automatically setTitle(modeStr); } } }); ani.start(); } @Override public void init(GLAutoDrawable d) { renderer.init(d); } @Override public void reshape(GLAutoDrawable d, int x, int y, int width, int height) { renderer.resize(d, width, height); } @Override public void display(GLAutoDrawable d) { float offset = 1.0f; renderer.t += offset; renderer.display(d); } @Override public void dispose(GLAutoDrawable d) { } } public class FboDepth { public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { MyGui myGUI = new MyGui(); myGUI.createGUI(); } }); } }