0
\$\begingroup\$

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:

enter image description here

When I render using my depth shader, it renders as I expect it should:

enter image description here

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:

enter image description here

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.

\$\endgroup\$
0
\$\begingroup\$

The problem was that I was using multiple shader providers, and references to the shaders were cached into the renderables. Instead of extending BaseShaderProvider, I just directly implemented ShaderProvider to only cache models if they should be rendered with the LibGDX default shader. (If you do this, remember that the shader provider is responsible for initializing shaders).

\$\endgroup\$
1
  • \$\begingroup\$ stuff like this is why gdx is a mess \$\endgroup\$ – Khlorghaal Dec 10 '18 at 0:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.