import com.jogamp.newt.opengl.GLWindow; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.event.WindowUpdateEvent; import com.jogamp.opengl.util.glsl.ShaderCode; import com.jogamp.opengl.util.glsl.ShaderProgram; import com.jogamp.opengl.*; import com.jogamp.opengl.FBObject.*; import javax.media.opengl.*; import java.nio.FloatBuffer; public class FBOTest3 implements GLEventListener, WindowListener{ private final float[] canvasVertices = { -1f, -1f, 0.0f, -1f, 1f, 0.0f, 1f, -1f, 0.0f, 1f, 1f, 0.0f, }; private final float[] canvasTexCoords = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, }; private final float[] quadVertices = { -0.5f, -0.5f, 0.0f, -0.5f, 0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 0.0f, }; private final float[] offsetQuadVertices = { -1f, -1f, 0.0f, -1f, 0f, 0.0f, 0f, -1f, 0.0f, 0f, 0f, 0.0f, }; //OpenGL Data private GLProfile glProfile; private GLCapabilities glCapabilities; private GLWindow gameWindow; //Canvas data private ShaderProgram canvasShader; private int canvasVAO; private int canvasTexture; private int canvasColourFramebuffer; //Object data private int vaoCentre; private int vaoOffset; private FBObject source; private FBObject target; private GL3ES3 gl; private void initFBO() { gl = GLContext.getCurrentGL().getGL3ES3(); source = new FBObject(); // Create FrameBuffer source.reset(gl, 320, 320); // int width, height - size of FBO, can be resized with the same call // With MSAA: // fbo.reset(gl, width, height, sampleNum, true); // int width, height, sampleNum - size/sampleNum of FBO, can be resized with the same call source.attachTexture2D(gl, 0, true); // Create GL_TEXTURE_2D texture which can be used as sampler2D at the shader code // Created texture will be bound to FBO's GL_COLOR_ATTACHMENT0 (see the second parameter 0) source.attachRenderbuffer(gl, Attachment.Type.DEPTH, 32); // Create depth buffer (if required) source.unbind(gl); // See Note-3 for use with MSAA. Unbind FrameBuffer (You will probably want to make bind() - render - unbind() loop later on) } private void renderToFBO() { source.bind(gl); // Render scene as usual gl.glClearColor(0, 0, 1, 1); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glBindVertexArray(vaoCentre); gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, quadVertices.length); gl.glBindVertexArray(vaoOffset); gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, offsetQuadVertices.length); source.unbind(gl); // See Note-3 for use with MSAA } public void renderFBOToScreen() { final TextureAttachment tex0 = (TextureAttachment) source.getColorbuffer(0); gl.glActiveTexture(GL2.GL_TEXTURE0); gl.glEnable(GL2.GL_TEXTURE_2D); // Should not call this for CORE profiles, i.e. ES2, GL3, .. gl.glBindTexture(GL2.GL_TEXTURE_2D, tex0.getName()); // See Notes 1, 2. Binding source FBO's TextureAttachment as GL_TEXTURE_2D // Here you can just render a fullscreen quad to show FBO content, or do something more exciting //Draw the colour buffer to the screen gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); gl.glClearColor(1f, 0f, 0f, 1f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glBindVertexArray(canvasVAO); canvasShader.useProgram(gl, true); int textureSamplerIndex = gl.glGetUniformLocation(canvasShader.program(), "textureUnit"); gl.glUniform1f(textureSamplerIndex, 0); gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, canvasVertices.length/3); } public final void init(GLAutoDrawable glad) { GL2 gl = glad.getGL().getGL2(); //Load shaders canvasShader = loadShader(gl, "Canvas.vsh", "Canvas.fsh"); //Generate framebuffers int[] framebuffers = new int[1]; gl.glGenFramebuffers(2, framebuffers, 0); canvasColourFramebuffer = framebuffers[0]; //Generate textures int[] textures = new int[1]; gl.glGenTextures(1, textures, 0); canvasTexture = textures[0]; gl.glBindTexture(GL.GL_TEXTURE_2D, canvasTexture); //Generate VAOs int[] vaos = new int[3]; gl.glGenVertexArrays(3, vaos, 0); vaoCentre = vaos[0]; vaoOffset = vaos[1]; canvasVAO = vaos[2]; //Generate buffers int[] buffers = new int[4]; gl.glGenBuffers(4, buffers, 0); int vertBuffer = buffers[0]; int offsetVertBuffer = buffers[1]; int canvasVertBuffer = buffers[2]; int canvasTexCoordBuffer = buffers[3]; //Initialize VAOs gl.glBindVertexArray(vaoCentre); gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertBuffer); gl.glBufferData(GL.GL_ARRAY_BUFFER, quadVertices.length*(Float.SIZE/8), FloatBuffer.wrap(quadVertices), GL.GL_STATIC_DRAW); gl.glEnableVertexAttribArray(0); gl.glVertexAttribPointer(0, 3, GL.GL_FLOAT, false, 0, 0); gl.glBindVertexArray(vaoOffset); gl.glBindBuffer(GL.GL_ARRAY_BUFFER, offsetVertBuffer); gl.glBufferData(GL.GL_ARRAY_BUFFER, offsetQuadVertices.length*(Float.SIZE/8), FloatBuffer.wrap(offsetQuadVertices), GL.GL_STATIC_DRAW); gl.glEnableVertexAttribArray(0); gl.glVertexAttribPointer(0, 3, GL.GL_FLOAT, false, 0, 0); //Canvas VAO canvasShader.useProgram(gl, true); gl.glBindVertexArray(canvasVAO); gl.glBindBuffer(GL.GL_ARRAY_BUFFER, canvasVertBuffer); gl.glBufferData(GL.GL_ARRAY_BUFFER, canvasVertices.length*(Float.SIZE/8), FloatBuffer.wrap(canvasVertices), GL.GL_STATIC_DRAW); int positionLoc = gl.glGetAttribLocation(canvasShader.program(), "position"); gl.glEnableVertexAttribArray(positionLoc); gl.glVertexAttribPointer(positionLoc, 3, GL.GL_FLOAT, false, 0, 0); gl.glBindBuffer(GL.GL_ARRAY_BUFFER, canvasTexCoordBuffer); gl.glBufferData(GL.GL_ARRAY_BUFFER, canvasTexCoords.length*(Float.SIZE/8), FloatBuffer.wrap(canvasTexCoords), GL.GL_STATIC_DRAW); int texCoordLoc = gl.glGetAttribLocation(canvasShader.program(), "texCoord"); gl.glEnableVertexAttribArray(texCoordLoc); gl.glVertexAttribPointer(texCoordLoc, 2, GL.GL_FLOAT, false, 0, 0); canvasShader.useProgram(gl, false); //Setup the canvas gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, canvasColourFramebuffer); gl.glBindTexture(GL.GL_TEXTURE_2D, canvasTexture); gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, 320, 320, 0, GL.GL_RGB, GL.GL_FLOAT, null); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, canvasTexture, 0); gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); initFBO(); } public final void display(GLAutoDrawable glad) { renderToFBO(); renderFBOToScreen(); } public FBOTest3() { //Initialize the OpenGL profile that the game will use glProfile = GLProfile.getDefault(); glCapabilities = new GLCapabilities(glProfile); //Create the game window gameWindow = GLWindow.create(glCapabilities); gameWindow.setSize(320, 320); gameWindow.setVisible(true); gameWindow.setTitle("JOGL Test"); gameWindow.addWindowListener(this); gameWindow.addGLEventListener(this); } public final void start() { while(true) { gameWindow.display(); } } public static void main(String[] args) { FBOTest3 fbot = new FBOTest3(); fbot.start(); } private ShaderProgram loadShader(GL2 gl, String vertexShader, String fragmentShader) { ShaderCode vertShader = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, getClass(), new String[]{"/shaders/"+vertexShader},false); vertShader.compile(gl); ShaderCode fragShader = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, getClass(), new String[]{"/shaders/"+fragmentShader},false); fragShader.compile(gl); ShaderProgram newShader = new ShaderProgram(); newShader.init(gl); newShader.add(vertShader); newShader.add(fragShader); newShader.link(gl, System.out); vertShader.destroy(gl); fragShader.destroy(gl); return newShader; } //GLEvent listener methods public void reshape(GLAutoDrawable glad, int x, int y, int width, int height) { } public void dispose(GLAutoDrawable glad) { } //Window listener methods public void windowDestroyNotify(WindowEvent we) { //The window and profile get cleaned up automatically in this case anyways System.exit(0); } public void windowDestroyed(WindowEvent we){} public void windowGainedFocus(WindowEvent we){} public void windowLostFocus(WindowEvent we){} public void windowMoved(WindowEvent we){} public void windowResized(WindowEvent we){} public void windowRepaint(WindowUpdateEvent wue){} }