OpenGL 3.2, GLSL 1.5, FBO's, and MRT

Started by pobrien, April 09, 2010, 06:09:03

Previous topic - Next topic

pobrien

Hi,

   I am trying to convert a fluid sim from C++/OpenGL/GLSL 1.2 to lwjgl so that it can run as an applet. At the time I wrote the sim, I didn't know about MRT. I know have been trying to include that in the conversion. However then I learned how much everything has changed with OpenGL 3 and 4. I was wondering first if its even worth trying to move to Opengl 3, or use the older fbo extensions and deprecated gl_fragData method? Does anyone have any code of a working fbo in opengl 3.0 using lwjgl? I haven't found a whole lot of information on it online. Oh yeah and I have version 2.3 of lwjgl if that matters. Any help is greatly appreciated!

Patrick


spasi

A fluid sim with GLSL and MRT means either Nvidia or AMD, which both have solid 3.2+ drivers (GLSL 1.5 was introduced with GL 3.2). So my advice would be to move to GL3+, preferably with the compatibility profile to make things easier. Moving from EXT_fbo to the core functionality is painless, it's more or less the same API with different entry points.

pobrien

Thanks for the replies! Matzon, I have followed that tutorial for converting my code and got it all working, but that is GL2, and the syntax has changed a bit for GL3 and thats where I'm confused. I was hoping to find the tutorial you sent, but in GL3 syntax. Thanks.

Estraven


Hi ! Hey, i've a code for this ! I use FBO in OGL 3.2 using GLSL 1.5 and doing MRT. (perfect match  ;D )

I will not provide my "Texture" class which is quite standard, so i've added a internal class at the beginning of the code, I guess you will know how to include this in your code.

I use static methods to build new FBO. you can specify the number of color buffers to use, and retrieve them as texture. You can also define the internal color and depth format.
the only thing that i did not implement is the possibility to have different color format on the multiple color buffers.

However, this code was designed with LWJGL 2.4.2.

Finally, i have to agree with Spasi, moving to Exts to OGL core is only a matter of removing EXT/ARB letters in your code ! Can't be easier !

Estraven

package org.egl.fbo;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL31.*;

import java.awt.Color;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.egl.EGL_Log;
import org.lwjgl.BufferUtils;




public class FBO {
	
	
	
	static class Texture{
		int target, texID;
		public Texture(int tgt, int id){
			target = tgt;
			texID = id;
			
		}
	}


	static public final int  COLOR_ARGB_32 = GL_RGBA32F;
	static public final int  COLOR_RGBA =  GL_RGBA;
	static public final int  COLOR_RGB =  GL_RGB;

	static public final int  DEPTH_32F = GL_DEPTH_COMPONENT32F;
	static public final int  DEPTH_32  = GL_DEPTH_COMPONENT32;
	static public final int  DEPTH_24  = GL_DEPTH_COMPONENT24;
	static public final int  DEPTH_16  = GL_DEPTH_COMPONENT16;
	static public final int  DEPTH_NORMAL     = GL_DEPTH_COMPONENT;
	
	public final static int[] attachID = new int[]{
		GL_COLOR_ATTACHMENT0,
		GL_COLOR_ATTACHMENT1,
		GL_COLOR_ATTACHMENT2,
		GL_COLOR_ATTACHMENT3,
		GL_COLOR_ATTACHMENT4,
		GL_COLOR_ATTACHMENT5,
		GL_COLOR_ATTACHMENT6,
		GL_COLOR_ATTACHMENT7,
		GL_COLOR_ATTACHMENT8,
		GL_COLOR_ATTACHMENT9,
		GL_COLOR_ATTACHMENT10,
		GL_COLOR_ATTACHMENT11,
		GL_COLOR_ATTACHMENT12,
		GL_COLOR_ATTACHMENT13,
		GL_COLOR_ATTACHMENT14,
		GL_COLOR_ATTACHMENT15,
	};

	

	boolean ClearColor,  UseDepth,  ClearDepth;
	int UseColor;

	IntBuffer DrawBufferTable ;
	
	int FBO_ID = -1;
	int[] COLOR_ID ;
	int DEPTH_ID = -1;

	int Color_format = COLOR_RGBA;
	int Depth_format = DEPTH_NORMAL;

	int TargetW=512, TargetH=512;

	Color Background = Color.black;

	Texture colorTexture[];
	
	Texture depthTexture;
	
	
	public static boolean checkGLErrors(String message){
		int error ;
		if ((error=glGetError()) != GL_NO_ERROR){
			if (message != null) {
				switch (error) {
				case GL_INVALID_ENUM : EGL_Log.Log("GL_INVALID_ENUM: " + message); break;

				case GL_INVALID_OPERATION : EGL_Log.Log("GL_INVALID_OPERATION: " + message); break;

				case GL_INVALID_VALUE : EGL_Log.Log("GL_INVALID_VALUE: " + message); break;

				case GL_OUT_OF_MEMORY : EGL_Log.Log("GL_OUT_OF_MEMORY: " + message); break;

				default : EGL_Log.Log("GL_UNKNOWN_ERROR: " + message); break;
				}
			}
		}
		else
			return false;
		return true;
	}
	
	
	public static FBO newFBO(String name, int width, int height, int color_format, boolean useColor, boolean clearColor, boolean useDepth, boolean clearDepth) {
		return new FBO(width, height,color_format,DEPTH_32, useColor?1:0, clearColor, useDepth, clearDepth);
	}
	public static FBO newFBO( int width, int height, int color_format, int depth_format, boolean useColor, boolean clearColor, boolean useDepth, boolean clearDepth) {
		return new FBO(width, height,color_format,depth_format, useColor?1:0, clearColor, useDepth, clearDepth);
	}
	public static FBO newFBO( int width, int height, int color_format, int useColor, boolean clearColor, boolean useDepth, boolean clearDepth) {
		return new FBO(width, height,color_format,DEPTH_32, useColor, clearColor, useDepth, clearDepth);
	}
	public static FBO newFBO( int width, int height, int color_format, int depth_format, int useColor, boolean clearColor, boolean useDepth, boolean clearDepth) {
		return new FBO(width, height, color_format, depth_format, useColor, clearColor, useDepth, clearDepth);
	}

	private FBO(int width, int height, int useColor, boolean clearColor, boolean useDepth, boolean clearDepth) {
		
		this.UseColor = useColor + (!useDepth || useColor==0?1:0);
		this.UseDepth = useDepth;
		this.ClearColor = clearColor;
		this.ClearDepth = clearDepth;
		this.TargetW = width;
		this.TargetH = height;
		this.setBackground(Color.black);
		this.init();
	}


	private FBO(int width, int height, int color_format, int depth_format, int useColor, boolean clearColor, boolean useDepth, boolean clearDepth) {
		this.UseColor = useColor + (!useDepth || useColor==0?1:0);
		this.UseDepth = useDepth;
		this.ClearColor = clearColor;
		this.Color_format = color_format;
		this.Depth_format = depth_format;
		this.ClearDepth = clearDepth;
		this.TargetW = width;
		this.TargetH = height;
		this.setBackground(Color.black);
		
		this.init();
	}


	public void bindAndClear(){



		//checkGLErrors(null);



			bind();

			if (ClearColor)
			{
				glClearColor(this.cR,this.cG,this.cB, 1);
				glClear(GL_COLOR_BUFFER_BIT);
			}

			if (ClearDepth)
			{
				glClearColor(0,0,0,0);
				glClear(GL_DEPTH_BUFFER_BIT);
			}


		//	checkGLErrors("ERROR in FBO binding");
	}

	public void bind(){

		
		glBindFramebuffer(	GL_FRAMEBUFFER , this.FBO_ID);
		
		for(int i=0;i<UseColor;i++)
				glFramebufferTexture2D( GL_FRAMEBUFFER, attachID[i] , GL_TEXTURE_RECTANGLE, this.COLOR_ID[i], 0 );
		
		if (UseDepth)
				glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_TEXTURE_RECTANGLE, this.DEPTH_ID, 0 );
		
		if (UseColor>=1)
			glDrawBuffers(DrawBufferTable);
		else
			glDrawBuffer(attachID[0]);
		

	}


	static IntBuffer bf1 = BufferUtils.createIntBuffer(1);
	
	/* FBO INITIALISATION */
	
	public void init(){


		if (this.FBO_ID <0){
			bf1.rewind();
			glGenFramebuffers(bf1);
			this.FBO_ID = bf1.get();
			//System.out.println("FBO generated id : " + this.FBO_ID);
		}


		// COLOR
		COLOR_ID = new int[UseColor];
		colorTexture = new Texture[UseColor];
		
		if (UseColor>=1){
			
			DrawBufferTable = BufferUtils.createIntBuffer(UseColor);
			
			for(int i=0;i<UseColor;i++)
					DrawBufferTable.put(attachID[i]);
			DrawBufferTable.rewind();
		}
		
		for(int i=0;i<UseColor;i++){

			bf1.rewind();
			glGenTextures(bf1);
			this.COLOR_ID[i] = bf1.get();
			//System.out.println("FBO Color generated id : " + this.COLOR_ID[i]);



				glBindTexture(GL_TEXTURE_RECTANGLE, this.COLOR_ID[i]);
				glTexImage2D(  GL_TEXTURE_RECTANGLE, 0, Color_format , this.TargetW, this.TargetH, 0, GL_RGBA, GL_FLOAT, (FloatBuffer) null );
				//System.out.println("FBO Color id : " + this.COLOR_ID[i] + " was succefully defined as a rectangular (GL31) texture");
				this.colorTexture[i] = new Texture(GL_TEXTURE_RECTANGLE,this.COLOR_ID[i]);
			
			
		}



		// DEPTH
		if (this.DEPTH_ID <0 && this.UseDepth){

			bf1.rewind();
			glGenTextures(bf1);
			this.DEPTH_ID = bf1.get();
			//System.out.println("FBO depth generated id : " + this.DEPTH_ID);

				glBindTexture(GL_TEXTURE_RECTANGLE,  this.DEPTH_ID );
				glTexImage2D(  GL_TEXTURE_RECTANGLE, 0, Depth_format ,this.TargetW, this.TargetH, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, (IntBuffer) null  );
				//System.out.println("FBO depth id : " + this.DEPTH_ID + " was succefully defined as a rectangular (GL31) texture");
				this.depthTexture = new Texture(GL_TEXTURE_RECTANGLE,this.DEPTH_ID);
			

			
		}

			glBindFramebuffer(	GL_FRAMEBUFFER , this.FBO_ID);
			checkGLErrors("Early FBO binding...");

		// BINDING
		for(int i=0;i<UseColor;i++){
				glFramebufferTexture2D( GL_FRAMEBUFFER, attachID[i] , GL_TEXTURE_RECTANGLE, this.COLOR_ID[i], 0 );

		}


		if(glCheckFramebufferStatus(GL_FRAMEBUFFER)==GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
			System.err.println("Error while Binding FBO color texture");
		else
			if(glCheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE)
				System.err.println("Error while creating FBO");


		if (this.DEPTH_ID <0 && this.UseDepth){
			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_TEXTURE_RECTANGLE, this.DEPTH_ID, 0 );
			if(glCheckFramebufferStatus(GL_FRAMEBUFFER)==GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT){

				System.err.println("Error while Binding FBO depth texture");
			}
		}

		if (ClearColor){
			glClearColor(this.cR,this.cG,this.cB, 1);
			glClear(GL_COLOR_BUFFER_BIT);
		}


		if (ClearDepth)
		{
			glClearColor(0,0,0,0);
			glClear(GL_DEPTH_BUFFER_BIT);
		}


		glBindFramebuffer(	GL_FRAMEBUFFER , 0);

	}

	float cR,cG,cB;


	public Color getBackground() {
		return this.Background;
	}

	public void setBackground(Color c) {
		if (c!= null){
			this.Background = c;
			this.cR = this.getBackground().getRed()/255.0f;
			this.cG = this.getBackground().getGreen()/255.0f;
			this.cB = this.getBackground().getBlue()/255.0f;
		}
	}




	public Texture getColorTexture(){
		return getColorTexture(0);
	}

	public Texture getColorTexture(int i){
		if (i>=this.colorTexture.length){
			//System.out.println("NULL COLOR TEXTURE !!");
			return null;
		}
		return this.colorTexture[i];
	}


	
	public Texture getDepthTexture(){
		if (this.depthTexture == null){
			//System.out.println("NULL DEPTH TEXTURE !!");
			return null;
		}
		return this.depthTexture;
	}


}