Browse Source

Post processing

Tankernn 9 years ago
parent
commit
e81debe452

+ 27 - 0
src/main/java/eu/tankernn/gameEngine/postProcessing/ContrastChanger.java

@@ -0,0 +1,27 @@
+package eu.tankernn.gameEngine.postProcessing;
+
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL13;
+
+public class ContrastChanger {
+	private ImageRenderer renderer;
+	private ContrastShader shader;
+	
+	public ContrastChanger() {
+		shader = new ContrastShader();
+		renderer = new ImageRenderer();
+	}
+	
+	public void render(int texture) {
+		shader.start();
+		GL13.glActiveTexture(GL13.GL_TEXTURE0);
+		GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
+		renderer.renderQuad();
+		shader.stop();
+	}
+	
+	public void cleanUp() {
+		renderer.cleanUp();
+		shader.cleanUp();
+	}
+}

+ 22 - 0
src/main/java/eu/tankernn/gameEngine/postProcessing/ContrastShader.java

@@ -0,0 +1,22 @@
+package eu.tankernn.gameEngine.postProcessing;
+
+import eu.tankernn.gameEngine.shaders.ShaderProgram;
+
+public class ContrastShader extends ShaderProgram {
+	
+	private static final String VERTEX_FILE = "/eu/tankernn/gameEngine/postProcessing/contrastVertex.glsl";
+	private static final String FRAGMENT_FILE = "/eu/tankernn/gameEngine/postProcessing/contrastFragment.glsl";
+	
+	public ContrastShader() {
+		super(VERTEX_FILE, FRAGMENT_FILE);
+	}
+	
+	@Override
+	protected void getAllUniformLocations() {}
+	
+	@Override
+	protected void bindAttributes() {
+		super.bindAttribute(0, "position");
+	}
+	
+}

+ 175 - 0
src/main/java/eu/tankernn/gameEngine/postProcessing/Fbo.java

@@ -0,0 +1,175 @@
+
+package eu.tankernn.gameEngine.postProcessing;
+
+import java.nio.ByteBuffer;
+
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.lwjgl.opengl.GL14;
+import org.lwjgl.opengl.GL30;
+
+public class Fbo {
+
+	public static final int NONE = 0;
+	public static final int DEPTH_TEXTURE = 1;
+	public static final int DEPTH_RENDER_BUFFER = 2;
+
+	private final int width;
+	private final int height;
+
+	private int frameBuffer;
+
+	private int colourTexture;
+	private int depthTexture;
+
+	private int depthBuffer;
+	private int colourBuffer;
+
+	/**
+	 * Creates an FBO of a specified width and height, with the desired type of
+	 * depth buffer attachment.
+	 * 
+	 * @param width
+	 *            - the width of the FBO.
+	 * @param height
+	 *            - the height of the FBO.
+	 * @param depthBufferType
+	 *            - an int indicating the type of depth buffer attachment that
+	 *            this FBO should use.
+	 */
+	public Fbo(int width, int height, int depthBufferType) {
+		this.width = width;
+		this.height = height;
+		initialiseFrameBuffer(depthBufferType);
+	}
+
+	/**
+	 * Deletes the frame buffer and its attachments when the game closes.
+	 */
+	public void cleanUp() {
+		GL30.glDeleteFramebuffers(frameBuffer);
+		GL11.glDeleteTextures(colourTexture);
+		GL11.glDeleteTextures(depthTexture);
+		GL30.glDeleteRenderbuffers(depthBuffer);
+		GL30.glDeleteRenderbuffers(colourBuffer);
+	}
+
+	/**
+	 * Binds the frame buffer, setting it as the current render target. Anything
+	 * rendered after this will be rendered to this FBO, and not to the screen.
+	 */
+	public void bindFrameBuffer() {
+		GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
+		GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, frameBuffer);
+		GL11.glViewport(0, 0, width, height);
+	}
+
+	/**
+	 * Unbinds the frame buffer, setting the default frame buffer as the current
+	 * render target. Anything rendered after this will be rendered to the
+	 * screen, and not this FBO.
+	 */
+	public void unbindFrameBuffer() {
+		GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
+		GL11.glViewport(0, 0, Display.getWidth(), Display.getHeight());
+	}
+
+	/**
+	 * Binds the current FBO to be read from (not used in tutorial 43).
+	 */
+	public void bindToRead() {
+		GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
+		GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, frameBuffer);
+		GL11.glReadBuffer(GL30.GL_COLOR_ATTACHMENT0);
+	}
+
+	/**
+	 * @return The ID of the texture containing the colour buffer of the FBO.
+	 */
+	public int getColourTexture() {
+		return colourTexture;
+	}
+
+	/**
+	 * @return The texture containing the FBOs depth buffer.
+	 */
+	public int getDepthTexture() {
+		return depthTexture;
+	}
+
+	/**
+	 * Creates the FBO along with a colour buffer texture attachment, and
+	 * possibly a depth buffer.
+	 * 
+	 * @param type
+	 *            - the type of depth buffer attachment to be attached to the
+	 *            FBO.
+	 */
+	private void initialiseFrameBuffer(int type) {
+		createFrameBuffer();
+		createTextureAttachment();
+		if (type == DEPTH_RENDER_BUFFER) {
+			createDepthBufferAttachment();
+		} else if (type == DEPTH_TEXTURE) {
+			createDepthTextureAttachment();
+		}
+		unbindFrameBuffer();
+	}
+
+	/**
+	 * Creates a new frame buffer object and sets the buffer to which drawing
+	 * will occur - colour attachment 0. This is the attachment where the colour
+	 * buffer texture is.
+	 * 
+	 */
+	private void createFrameBuffer() {
+		frameBuffer = GL30.glGenFramebuffers();
+		GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBuffer);
+		GL11.glDrawBuffer(GL30.GL_COLOR_ATTACHMENT0);
+	}
+
+	/**
+	 * Creates a texture and sets it as the colour buffer attachment for this
+	 * FBO.
+	 */
+	private void createTextureAttachment() {
+		colourTexture = GL11.glGenTextures();
+		GL11.glBindTexture(GL11.GL_TEXTURE_2D, colourTexture);
+		GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE,
+				(ByteBuffer) null);
+		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
+		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
+		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
+		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
+		GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, colourTexture,
+				0);
+	}
+
+	/**
+	 * Adds a depth buffer to the FBO in the form of a texture, which can later
+	 * be sampled.
+	 */
+	private void createDepthTextureAttachment() {
+		depthTexture = GL11.glGenTextures();
+		GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTexture);
+		GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL14.GL_DEPTH_COMPONENT24, width, height, 0, GL11.GL_DEPTH_COMPONENT,
+				GL11.GL_FLOAT, (ByteBuffer) null);
+		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
+		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
+		GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, depthTexture, 0);
+	}
+
+	/**
+	 * Adds a depth buffer to the FBO in the form of a render buffer. This can't
+	 * be used for sampling in the shaders.
+	 */
+	private void createDepthBufferAttachment() {
+		depthBuffer = GL30.glGenRenderbuffers();
+		GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBuffer);
+		GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL14.GL_DEPTH_COMPONENT24, width, height);
+		GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER,
+				depthBuffer);
+	}
+
+}

+ 36 - 0
src/main/java/eu/tankernn/gameEngine/postProcessing/ImageRenderer.java

@@ -0,0 +1,36 @@
+package eu.tankernn.gameEngine.postProcessing;
+
+import org.lwjgl.opengl.GL11;
+
+public class ImageRenderer {
+
+	private Fbo fbo;
+
+	protected ImageRenderer(int width, int height) {
+		this.fbo = new Fbo(width, height, Fbo.NONE);
+	}
+
+	protected ImageRenderer() {}
+
+	protected void renderQuad() {
+		if (fbo != null) {
+			fbo.bindFrameBuffer();
+		}
+		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
+		GL11.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, 4);
+		if (fbo != null) {
+			fbo.unbindFrameBuffer();
+		}
+	}
+
+	protected int getOutputTexture() {
+		return fbo.getColourTexture();
+	}
+
+	protected void cleanUp() {
+		if (fbo != null) {
+			fbo.cleanUp();
+		}
+	}
+
+}

+ 43 - 0
src/main/java/eu/tankernn/gameEngine/postProcessing/PostProcessing.java

@@ -0,0 +1,43 @@
+package eu.tankernn.gameEngine.postProcessing;
+
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL20;
+import org.lwjgl.opengl.GL30;
+
+import eu.tankernn.gameEngine.models.RawModel;
+import eu.tankernn.gameEngine.renderEngine.Loader;
+
+public class PostProcessing {
+	
+	private static final float[] POSITIONS = {-1, 1, -1, -1, 1, 1, 1, -1};
+	private static RawModel quad;
+	private static ContrastChanger contrastChanger;
+	
+	public static void init(Loader loader) {
+		quad = loader.loadToVAO(POSITIONS, 2);
+		contrastChanger = new ContrastChanger();
+	}
+	
+	public static void doPostProcessing(int colorTexture) {
+		start();
+		contrastChanger.render(colorTexture);
+		end();
+	}
+	
+	public static void cleanUp() {
+		
+	}
+	
+	private static void start() {
+		GL30.glBindVertexArray(quad.getVaoID());
+		GL20.glEnableVertexAttribArray(0);
+		GL11.glDisable(GL11.GL_DEPTH_TEST);
+	}
+	
+	private static void end() {
+		GL11.glEnable(GL11.GL_DEPTH_TEST);
+		GL20.glDisableVertexAttribArray(0);
+		GL30.glBindVertexArray(0);
+	}
+	
+}

+ 15 - 0
src/main/java/eu/tankernn/gameEngine/postProcessing/contrastFragment.glsl

@@ -0,0 +1,15 @@
+#version 140
+
+in vec2 textureCoords;
+
+out vec4 out_Colour;
+
+uniform sampler2D colourTexture;
+
+const float contrast = 0.3;
+
+void main(void){
+	
+	out_Colour = texture(colourTexture, textureCoords);
+	out_Colour.rgb = (out_Colour.rgb - 0.5) * (1.0 + contrast) + 0.5;
+}

+ 12 - 0
src/main/java/eu/tankernn/gameEngine/postProcessing/contrastVertex.glsl

@@ -0,0 +1,12 @@
+#version 140
+
+in vec2 position;
+
+out vec2 textureCoords;
+
+void main(void){
+
+	gl_Position = vec4(position, 0.0, 1.0);
+	textureCoords = position * 0.5 + 0.5;
+	
+}

+ 22 - 1
src/main/java/eu/tankernn/gameEngine/tester/MainLoop.java

@@ -28,6 +28,8 @@ import eu.tankernn.gameEngine.objLoader.OBJFileLoader;
 import eu.tankernn.gameEngine.particles.ParticleMaster;
 import eu.tankernn.gameEngine.particles.ParticleSystem;
 import eu.tankernn.gameEngine.particles.ParticleTexture;
+import eu.tankernn.gameEngine.postProcessing.Fbo;
+import eu.tankernn.gameEngine.postProcessing.PostProcessing;
 import eu.tankernn.gameEngine.renderEngine.DisplayManager;
 import eu.tankernn.gameEngine.renderEngine.Loader;
 import eu.tankernn.gameEngine.renderEngine.MasterRenderer;
@@ -47,7 +49,12 @@ public class MainLoop {
 	private static final int SEED = 1235;
 	
 	public static void main(String[] args) {
-		System.setProperty("org.lwjgl.librarypath", new File("natives").getAbsolutePath());
+		File nativeDir = new File("natives");
+		if (nativeDir.exists()) {
+			System.setProperty("org.lwjgl.librarypath", nativeDir.getAbsolutePath());
+		}
+		
+			
 		List<Entity> entities = new ArrayList<Entity>();
 		List<Entity> normalMapEntities = new ArrayList<Entity>();
 		TerrainPack terrainPack = new TerrainPack();
@@ -147,6 +154,10 @@ public class MainLoop {
 		ParticleTexture particleTexture = new ParticleTexture(loader.loadTexture("particles/cosmic"), 4, true);
 		ParticleSystem ps = new ParticleSystem(particleTexture, 50, 10, 0.3f, 4);
 		
+		Fbo fbo = new Fbo(Display.getWidth(), Display.getHeight(), Fbo.DEPTH_RENDER_BUFFER);
+		
+		PostProcessing.init(loader);
+		
 		while (!Display.isCloseRequested()) {
 			barrel.increaseRotation(0, 1, 0);
 			player.move(terrainPack);
@@ -181,15 +192,25 @@ public class MainLoop {
 			Scene scene = new Scene(entities, normalMapEntities, terrainPack, lights, camera);
 			
 			waterMaster.renderBuffers(renderer, scene);
+			
+			fbo.bindFrameBuffer();
+			
 			renderer.renderScene(scene, new Vector4f(0, 1, 0, Float.MAX_VALUE));
 			waterMaster.renderWater(camera, lights);
 			ParticleMaster.renderParticles(camera);
+			
+			fbo.unbindFrameBuffer();
+			
+			PostProcessing.doPostProcessing(fbo.getColourTexture());
+			
 			guiRenderer.render(guis);
 			TextMaster.render();
 			
 			DisplayManager.updateDisplay();
 		}
 		
+		PostProcessing.cleanUp();
+		fbo.cleanUp();
 		ParticleMaster.cleanUp();
 		TextMaster.cleanUp();
 		waterMaster.cleanUp();