Shadow mapping approach

Started by take2316, March 20, 2013, 01:53:49 AM

Previous topic - Next topic

take2316

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!)


// 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?

take2316

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?

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;
}
}

EgonOlsen

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?

take2316

Wow... I had interpreted this documentation incorrectly or just read it too fast:

QuoteWhile 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:

chair.setShader(shader);
chair.setRenderHook(new CustomShader(vertexSphereShader, fragmentSphereShader, chair.getShader()));


and have CustomShader just set the uniform values in the beforeRendering() method:

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?)

EgonOlsen

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.

take2316

So if I'm implementing shadow mapping, then that would be a shared shader, right? That is, if I did
world.setGlobalShader(shadowShader);
and wanted to pass in a uniform, would I need to implement IRenderHook?

EgonOlsen

Quote from: take2316 on March 20, 2013, 04:28:24 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.