![JAR search and dependency download from the Maven repository](/logo.png)
org.oscim.renderer.light.ShadowFrameBuffer Maven / Gradle / Ivy
Show all versions of vtm Show documentation
/*
* Copyright 2019 Gustl22
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see .
*/
package org.oscim.renderer.light;
import org.oscim.backend.GL;
import org.oscim.backend.GLAdapter;
import org.oscim.renderer.GLState;
import org.oscim.renderer.GLUtils;
import static org.oscim.backend.GLAdapter.gl;
import static org.oscim.backend.GLAdapter.gl30;
/**
* The frame buffer for the shadow pass. This class sets up the depth texture
* which can be rendered to during the shadow render pass, producing a shadow
* map.
*
* See ThinMatrix on Youtube: https://youtu.be/o6zDfDkOFIc
*/
public class ShadowFrameBuffer {
private final int WIDTH;
private final int HEIGHT;
private int defaultWidth;
private int defaultHeight;
private int defaultFrameBuffer;
private int defaultTexture;
private int fbo;
private int shadowMap;
/**
* Initialises the frame buffer and shadow map of a certain size.
*
* @param width - the width of the shadow map in pixels.
* @param height - the height of the shadow map in pixels.
*/
protected ShadowFrameBuffer(int width, int height) {
this.WIDTH = width;
this.HEIGHT = height;
updateViewportDimensions();
fbo = createFrameBuffer();
shadowMap = createDepthBufferAttachment(width, height);
unbindFrameBuffer();
}
/**
* Deletes the frame buffer and shadow map texture when the game closes.
*/
protected void cleanUp() {
GLUtils.glDeleteFrameBuffers(1, new int[]{fbo});
GLUtils.glDeleteTextures(1, new int[]{shadowMap});
}
/**
* Unbinds the frame buffer, setting the default frame buffer as the current
* render target.
*/
protected void unbindFrameBuffer() {
GLState.bindFramebuffer(defaultFrameBuffer);
GLState.viewport(defaultWidth, defaultHeight);
}
/**
* @return The ID of the shadow map texture.
*/
protected int getShadowMap() {
return shadowMap;
}
/**
* Binds the frame buffer as the current render target.
*/
public void bindFrameBuffer() {
updateViewportDimensions();
GLState.bindTex2D(defaultTexture);
defaultFrameBuffer = GLState.getFramebuffer();
GLState.bindFramebuffer(fbo);
GLState.viewport(WIDTH, HEIGHT);
}
/**
* Creates a frame buffer and binds it so that attachments can be added to
* it. The draw buffer is set to none, indicating that there's no colour
* buffer to be rendered to.
*
* @return The newly created frame buffer's ID.
*/
private static int createFrameBuffer() {
int frameBuffer = GLUtils.glGenFrameBuffers(1)[0];
GLState.bindFramebuffer(frameBuffer);
if (GLAdapter.isGL30()) {
GLUtils.glDrawBuffers(1, new int[]{GL.NONE});
gl30.readBuffer(GL.NONE);
}
return frameBuffer;
}
/**
* Creates a depth buffer texture attachment.
*
* @param width - the width of the texture.
* @param height - the height of the texture.
* @return The ID of the depth texture.
*/
private int createDepthBufferAttachment(int width, int height) {
defaultTexture = GLState.getTexture();
int[] texture = GLUtils.glGenTextures(1);
GLState.bindTex2D(texture[0]);
if (GLAdapter.isGL30()) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl30.DEPTH_COMPONENT16,
width, height, 0, gl30.DEPTH_COMPONENT,
gl.UNSIGNED_SHORT, null);
} else {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
width, height, 0, gl.RGBA,
gl.UNSIGNED_BYTE, null);
}
// Alternatively set to 32 bit float texture
// gl.texImage2D(gl.TEXTURE_2D, 0, gl30.DEPTH_COMPONENT32F, width, height, 0,
// gl.DEPTH_COMPONENT, gl.FLOAT, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);
if (GLAdapter.isGL30()) {
gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.TEXTURE_2D, texture[0], 0);
} else {
gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, texture[0], 0);
}
return texture[0];
}
private void updateViewportDimensions() {
defaultWidth = GLState.getViewportWidth();
defaultHeight = GLState.getViewportHeight();
}
}