I'm trying to adapt the shadow-mapping process given on this microbasic guide into my game, it's made with LibGDX. I've run into a blocking point with the creation of the shadow buffer via rendering to a texture.
When I just use my normal shader, the game looks fine:
When I render using my depth shader, it renders as I expect it should:
But when I try to render to a FrameBuffer with the depth shader, and then normally with the normal shader, all geometry rendered with that normal shader appears black:
Debug geometry, which is rendered with Libgdx's default shaders, actually renders fine though. I'd appreciate suggestions as to what could be causing this, since I've spent a few hours searching through the code I could find and I couldn't find anything that I obviously wasn't doing or was doing wrong.
I'll post the relevant code, which is written in Scala.
In the render function:
val provider: RenderableProvider = (the provider for all geometry)
lightBuffer.begin()
Gdx.gl.glClearColor(0, 0, 0, 1)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT)
lightBatch.begin(lightCam)
lightBatch.render(provider)
lightBatch.end()
lightBuffer.end()
Gdx.gl.glClearColor(0.5089f, 0.6941f, 1f, 1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT)
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D)
modelBatch.begin(cam)
modelBatch.render(provider, environment)
modelBatch.end()
In the initialization logic:
private var modelBatch: ModelBatch = _
private var lightCam: PerspectiveCamera = _
private var lightBuffer: FrameBuffer = _
private var lightBatch: ModelBatch = _
private var depthShader: DepthShader = _
private var sceneShader: TestShader = _
private var environment: Environment = _
...
modelBatch = new ModelBatch(new BaseShaderProvider {
shaders.add(sceneShader)
override def createShader(renderable: Renderable): Shader =
new DefaultShader(renderable, new DefaultShader.Config())
})
environment = new Environment
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1))
environment.add(new DirectionalLight().set(1, 1, 1, 0, -1, 0))
lightCam = new PerspectiveCamera(120f, 1024, 1024)
lightCam.near = 0.1f
lightCam.far = 100f
lightCam.position.set(0, 10, 0)
lightCam.lookAt(1, 10, 1)
lightCam.update()
lightBuffer = new FrameBuffer(Format.RGBA8888, 1024, 1024, true)
depthShader = new DepthShader()
depthShader.init()
lightBatch = new ModelBatch(new ShaderProvider {
override def getShader(renderable: Renderable): Shader =
depthShader
override def dispose(): Unit =
depthShader.dispose()
})
The Scala shader classes:
class DepthShader extends Shader {
var program: ShaderProgram = _
var cam: Camera = _
var context: RenderContext = _
var u_projViewTrans: Int = _
var u_worldTrans: Int = _
var u_cameraFar: Int = _
var u_lightPosition: Int = _
override def canRender(instance: Renderable): Boolean = true
override def init(): Unit = {
val vert = Gdx.files.internal("shaders/depth_v.glsl").readString()
val frag = Gdx.files.internal("shaders/depth_f.glsl").readString()
program = new ShaderProgram(vert, frag)
if (!(program isCompiled))
throw new GdxRuntimeException(program.getLog)
u_projViewTrans = program.getUniformLocation("u_projViewTrans")
u_worldTrans = program.getUniformLocation("u_worldTrans")
u_cameraFar = program.getUniformLocation("u_cameraFar")
u_lightPosition = program.getUniformLocation("u_lightPosition")
}
override def compareTo(other: Shader): Int = 0
override def begin(camera: Camera, context: RenderContext): Unit = {
this.cam = camera
this.context = context
program.begin()
program.setUniformMatrix(u_projViewTrans, camera.combined)
program.setUniformf(u_cameraFar, camera.far)
program.setUniform3fv(u_lightPosition, Array(camera.position.x, camera.position.y, camera.position.z), 0, 3)
context.setDepthTest(GL20.GL_LEQUAL)
context.setCullFace(GL20.GL_BACK)
}
override def render(renderable: Renderable): Unit = {
program.setUniformMatrix(u_worldTrans, renderable.worldTransform)
renderable.meshPart.render(program)
}
override def end(): Unit = {
program.end()
}
override def dispose(): Unit = {
program.dispose()
}
}
class TestShader(sheet: Texture) extends Shader {
var program: ShaderProgram = _
var cam: Camera = _
var context: RenderContext = _
var u_projViewTrans: Int = _
var u_worldTrans: Int = _
override def canRender(instance: Renderable): Boolean = {
instance.meshPart.primitiveType == GL20.GL_TRIANGLES
}
override def init(): Unit = {
val vert = Gdx.files.internal("shaders/test_v.glsl").readString()
val frag = Gdx.files.internal("shaders/test_f.glsl").readString()
program = new ShaderProgram(vert, frag)
if (!(program isCompiled))
throw new GdxRuntimeException(program.getLog)
u_projViewTrans = program.getUniformLocation("u_projViewTrans")
u_worldTrans = program.getUniformLocation("u_worldTrans")
}
override def compareTo(other: Shader): Int = 0
override def begin(camera: Camera, context: RenderContext): Unit = {
this.cam = camera
this.context = context
program.begin()
program.setUniformMatrix(u_projViewTrans, camera.combined)
sheet.bind()
program.setUniformi("u_texture", 0)
context.setDepthTest(GL20.GL_LEQUAL)
context.setCullFace(GL20.GL_BACK)
}
override def render(renderable: Renderable): Unit = {
program.setUniformMatrix(u_worldTrans, renderable.worldTransform)
renderable.meshPart.render(program)
}
override def end(): Unit = {
program.end()
}
override def dispose(): Unit = {
program.dispose()
}
}
The GLSL shaders:
#version 120
attribute vec3 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_worldTrans;
uniform mat4 u_projViewTrans;
varying vec2 v_texCoord0;
varying vec4 v_color;
// scene vertex shader
void main() {
v_texCoord0 = a_texCoord0;
v_color = a_color;
gl_Position = u_projViewTrans * u_worldTrans * vec4(a_position, 1.0);
}
#version 120
varying vec2 v_texCoord0;
varying vec4 v_color;
uniform sampler2D u_texture;
// scene fragment shader
void main() {
gl_FragColor = texture2D(u_texture, v_texCoord0);
//gl_FragColor = v_color;
}
#version 120
attribute vec3 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_worldTrans;
uniform mat4 u_projViewTrans;
varying vec4 v_position;
// depth vertex shader
void main() {
v_position = u_worldTrans * vec4(a_position, 1.0);
gl_Position = u_projViewTrans * v_position;
}
#version 120
uniform float u_cameraFar;
uniform vec3 u_lightPosition;
varying vec4 v_position;
// depth fragment shader
void main() {
gl_FragColor = vec4(length(v_position.xyz - u_lightPosition) / u_cameraFar);
}
Thank you for your time.