Author Topic: Shadow mapping approach  (Read 3661 times)

Offline take2316

  • byte
  • *
  • Posts: 12
    • View Profile
Shadow mapping approach
« on: March 20, 2013, 01:53:49 am »
I'm trying to implement simple shadow mapping for jPCT-AE. I saw some of the recent forum posts about how shadows will soon be implemented?... but I just wanted to know if my approach is correct. (I'm trying to implement this for a school project that's due in a little over 48 hours!)

Code: [Select]
// Framebuffer fb
// Camera lightCam represents the light's view
// Texture shadowMap
// GLSLShader depthShader

// render shadow map
fb.setRenderTarget(shadowMap);
world.setCameraTo(lightCam);
world.setGlobalShader(depthShader); // doesn't override the shader for objects that called setShader!
world.renderScene(fb);
world.draw(fb);
fb.removeRenderTarget();
world.setGlobalShader(null); // is this how you remove the global shader?
world.setCameraTo(cam); // set back to regular camera
...
// regular render pass
world.renderScene(fb);
world.draw(fb);
fb.display();

Then I'll have to pass in the light's model view projection matrix to the regular shadow mapping shader. Since GLSLShader does not support passing in your own uniforms, I'll have to create an implementation of IRenderHook... right? Or is there a way to pass in the model-view-projection matrix for the light source(s) via GLSLShader without implementing IRenderHook?

Offline take2316

  • byte
  • *
  • Posts: 12
    • View Profile
Re: Shadow mapping approach
« Reply #1 on: March 20, 2013, 06:42:24 am »
Here's my initial implementation of IRenderHook. It seems to execute with no errors, but the shaders are not getting executed... If I use GLSLShader with the same shader sources, it executes fine. Any ideas on what might be going wrong?
Code: [Select]
package com.arproject;
import java.util.ArrayList;
import com.threed.jpct.*;
import android.opengl.*;

public class CustomShader implements IRenderHook {

private int prg=0;
private int fragShade = 0, vertShade = 0;
private boolean init=false;

private String mVertexSource, mFragmentSource;

public CustomShader(String vertexSource, String fragmentSource) {
Logger.log("Created Custom Shader!", Logger.MESSAGE);
mVertexSource = vertexSource;
mFragmentSource = fragmentSource;
init();
}

@Override
public void afterRendering(int arg0) {
// TODO Auto-generated method stub
GLES20.glUseProgram(0);
}

@Override
public void beforeRendering(int arg0) {
// TODO Auto-generated method stub
if (!init) {
init();
}
GLES20.glUseProgram(prg);
}

@Override
public void onDispose() {
// TODO Auto-generated method stub
GLES20.glDeleteShader(vertShade);
GLES20.glDeleteShader(fragShade);
GLES20.glDeleteProgram(prg);
init = false;
}

@Override
public boolean repeatRendering() {
// TODO Auto-generated method stub
return false;
}

@Override
public void setCurrentObject3D(Object3D arg0) {
// TODO Auto-generated method stub

}

@Override
public void setCurrentShader(GLSLShader arg0) {
// TODO Auto-generated method stub

}

@Override
public void setTransparency(float arg0) {
// TODO Auto-generated method stub

}

private void init() {
prg = GLES20.glCreateProgram();
fragShade = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if(fragShade == 0)
{
Logger.log("Failed to create fragShade in CustomShader!", Logger.MESSAGE);
Logger.log("Info: " + GLES20.glGetShaderInfoLog(prg), Logger.ERROR);
return;
}
GLES20.glShaderSource(fragShade, mFragmentSource);

vertShade = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
if(vertShade == 0)
{
Logger.log("Failed to create vertShade in CustomShader!", Logger.MESSAGE);
Logger.log("Info: " + GLES20.glGetShaderInfoLog(prg), Logger.ERROR);
return;
}
GLES20.glShaderSource(vertShade, mVertexSource);

int[] status = new int[1];
GLES20.glCompileShader(vertShade);
GLES20.glGetShaderiv(vertShade, GLES20.GL_COMPILE_STATUS, status, 0);
if(status[0] == 0) {
Logger.log("Vertex shader failed to compile in CustomShader!", Logger.MESSAGE);
Logger.log("Info: " + GLES20.glGetShaderInfoLog(prg), Logger.ERROR);
return;
}
GLES20.glCompileShader(fragShade);
GLES20.glGetShaderiv(fragShade, GLES20.GL_COMPILE_STATUS, status, 0);
if(status[0] == 0) {
Logger.log("Fragment shader failed to compile in CustomShader!", Logger.MESSAGE);
Logger.log("Info: " + GLES20.glGetShaderInfoLog(prg), Logger.ERROR);
return;
}

GLES20.glAttachShader(prg, vertShade);
GLES20.glAttachShader(prg, fragShade);

GLES20.glLinkProgram(prg);
GLES20.glGetProgramiv(prg, GLES20.GL_LINK_STATUS, status, 0);
if(status[0] == 0) {
Logger.log("Failed to link program in CustomShader!", Logger.MESSAGE);
Logger.log("Info: " + GLES20.glGetShaderInfoLog(prg), Logger.ERROR);
return;
}

Logger.log("Shader compiled and linked in CustomShader!", Logger.MESSAGE);
Logger.log("Info: " + GLES20.glGetShaderInfoLog(prg), Logger.MESSAGE);

init=true;
}
}

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Shadow mapping approach
« Reply #2 on: March 20, 2013, 08:22:41 am »
The IRenderHook way of doing shaders is a) outdated and b) only valid for desktop jPCT. It doesn't work that way in jPCT-AE. Why are you actually using it instead of GLSLShader?

Offline take2316

  • byte
  • *
  • Posts: 12
    • View Profile
Re: Shadow mapping approach
« Reply #3 on: March 20, 2013, 08:46:45 am »
Wow... I had interpreted this documentation incorrectly or just read it too fast:

Quote
While this class is similar to the one in desktop jPCT, it works a little different. Especially, it's not an implementation of IRenderHook, so if you want to set uniforms per Object3D on a shared shader, you have to write an additional IRenderHook to do so. However, it's ensured that IRenderHook's beforeRendering()-method will be called before the shader will be initialized, so you can safely set your uniforms there.

I'm supposed to do something like:
Code: [Select]
chair.setShader(shader);
chair.setRenderHook(new CustomShader(vertexSphereShader, fragmentSphereShader, chair.getShader()));

and have CustomShader just set the uniform values in the beforeRendering() method:
Code: [Select]
mShader.setUniform("mixValue", mixValue);
and of course, I have to pass in the shader to the CustomShader...

UPDATE: all this is wrong! I can just call setUniform without having to use IRenderHook... Is this because it's not a "shared shader" (what is a shared shader anyway?)

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Shadow mapping approach
« Reply #4 on: March 20, 2013, 09:49:37 am »
A shared shader is a shader that is used by multiple objects. I might be needed to set a uniform's value per object in some cases. For this, and only this, application, the IRenderHook is needed in addition. Most uniform can be set in the shader directly.

Offline take2316

  • byte
  • *
  • Posts: 12
    • View Profile
Re: Shadow mapping approach
« Reply #5 on: March 20, 2013, 04:28:24 pm »
So if I'm implementing shadow mapping, then that would be a shared shader, right? That is, if I did
Code: [Select]
world.setGlobalShader(shadowShader);and wanted to pass in a uniform, would I need to implement IRenderHook?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Shadow mapping approach
« Reply #6 on: March 20, 2013, 08:21:49 pm »
and wanted to pass in a uniform, would I need to implement IRenderHook?
No. You just have to do that if you want to set a different uniform value for each object.