Author Topic: Shadow Maker Shader  (Read 4841 times)

Offline sushobhit

  • long
  • ***
  • Posts: 109
  • future is now
    • View Profile
    • ANDROID APPS
Shadow Maker Shader
« on: May 29, 2014, 08:09:55 am »
Hi ,

I want to implement a shader for a Plane object which shows shadows of all the objects placed on it.
I know about blob shadows but that wont solve the pourpose that i am trying to achieve.

I have a rough sketch in my mind which is something like this : The shader of the plane would be a perpixel light shader
and it illuminates all of the plane falling under light. Now if an object falls in between the position of the light and the position of the object(plane) i.e the vertex if simply does gl_FragColor = shadowcolor * texturecolor; and if there is no object between light & plane it simply does gl_FragColor = textureColor;

All is going fine till now , I am able to get gl_FragColor = textureColor ; but how do i find out if there is an object between light and the plane.... plz help !!!

Do I have to set a uniform for each individual object if yes which matrix I have to pass that contains positions of all vertex of the object.

Very desparate to get this one working cause this is the last thing i have left to learn regarding game programming.....


Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Shadow Maker Shader
« Reply #1 on: May 29, 2014, 08:51:56 am »
That's done by a process called shadow mapping. You have to render the scene from the light source into a depth map (which is in fact a normal texture with the depth encoded into its rgba values, search the forum for Thomas' example of this), then project the depth map onto the scene into a second texture layer and compare the distance of the fragment to the light with the value in the texture.
jPCT-AE has everything you need to do this except for a build-in implementation itself (still on my todo list).
You might want to try to contact Thomas. and ask him about it too. I think that he had a more or less complete implementation of it running.

Offline sushobhit

  • long
  • ***
  • Posts: 109
  • future is now
    • View Profile
    • ANDROID APPS
Re: Shadow Maker Shader
« Reply #2 on: May 29, 2014, 01:00:20 pm »
If I got you right you mean render the every frame onto a depth map (is it something like the height map) a greyscale image of the texture. And then using this depthmap I blend it into second texture of the plane object.

Is there no way to find if a object is being interfering between light and plane object in glsl ??

Offline sushobhit

  • long
  • ***
  • Posts: 109
  • future is now
    • View Profile
    • ANDROID APPS
Re: Shadow Maker Shader
« Reply #3 on: May 29, 2014, 01:37:16 pm »
and how do i get the depth map ????

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Shadow Maker Shader
« Reply #4 on: May 29, 2014, 03:09:16 pm »
Well, that IS the way to check if something is blocking the light. Sadly, there's no magic glsl command that does it... :(
To get the depth map, you have to render the scene into a texture with a shader that writes the depth instead of the color. As said, you'll need some encode/decode method to store the depth in the texture's rgba values. You can find these somewhere in one of Thomas.'s posts.

Offline Thomas.

  • double
  • *****
  • Posts: 833
    • View Profile
Re: Shadow Maker Shader
« Reply #5 on: May 29, 2014, 03:35:47 pm »
Here is very good tutorial. You will know how it works and what you need. And here is Android implementation witch is almost same what i am using in my project.
« Last Edit: May 29, 2014, 03:39:40 pm by Thomas. »

Offline sushobhit

  • long
  • ***
  • Posts: 109
  • future is now
    • View Profile
    • ANDROID APPS
Re: Shadow Maker Shader
« Reply #6 on: May 30, 2014, 12:06:00 pm »
Thank 's A pow(Ton,100) Thomas & Egon

I googled for around 2 days but it didnt point to this stuff. It's really very useful.

Now I am stuck @ here (as it's pure GL) and i am using JPCT as the renderer.

I have the VS & FS for creating the Depth texture :
Code: [Select]
// Vertex shader to generate the Depth Map
// Used for shadow mapping - generates depth map from the light's viewpoint

// model-view projection matrix
uniform mat4 uMVPMatrix;

// position of the vertices
attribute vec4 aPosition;

varying vec4 position;

void main() {

position = uMVPMatrix * aPosition;
gl_Position = uMVPMatrix * aPosition;
}

Code: [Select]
// Pixel shader to generate the Depth Map
// Used for shadow mapping - generates depth map from the light's viewpoint
precision highp float;

varying vec4 position;

// taken from Fabien Sangalard's DEngine
vec4 pack (float depth)
{
const vec4 bitSh = vec4(256.0 * 256.0 * 256.0,
256.0 * 256.0,
256.0,
1.0);
const vec4 bitMsk = vec4(0,
1.0 / 256.0,
1.0 / 256.0,
1.0 / 256.0);
vec4 comp = fract(depth * bitSh);
comp -= comp.xxyz * bitMsk;
return comp;
}

void main() {
// the depth
float normalizedDistance  = position.z / position.w;
normalizedDistance = (normalizedDistance + 1.0) / 2.0;

// bias
normalizedDistance += 0.0005;

// pack value into 32-bit RGBA texture
gl_FragColor = pack(normalizedDistance);  // I am stuck here

}

And then I have the Phong shader that takes Input Texture from the above shader to create shadows.

Code: [Select]
// Vertex shader Phong Shading - Per-pixel lighting

uniform mat4 uMVPMatrix;
uniform mat4 normalMatrix;

// the shadow projection matrix
uniform mat4 shadowProjMatrix;

// eye pos
uniform vec3 eyePos;

// position and normal of the vertices
attribute vec4 aPosition;
attribute vec3 aNormal;

// texture variables
uniform float hasTexture;
varying float tex;
attribute vec2 textureCoord;
varying vec2 tCoord;

// lighting
uniform vec4 lightPos;
uniform vec4 lightColor;

// material
uniform vec4 matAmbient;
uniform vec4 matDiffuse;
uniform vec4 matSpecular;
uniform float matShininess;

// to pass on
varying vec3 vNormal;
varying vec3 EyespaceNormal;
varying vec4 shadowCoord;

varying vec3 lightDir, eyeVec;

void main() {
// pass on texture variables
tex = hasTexture;
tCoord = textureCoord;

// normal
EyespaceNormal = vec3(normalMatrix * vec4(aNormal, 1.0));

// the vertex position
vec4 position = uMVPMatrix * aPosition;

// light dir
lightDir = lightPos.xyz - position.xyz;
eyeVec = -position.xyz;

// shadow coordinates
mat4 bias2 = mat4(0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.0, 0.5,
0.0, 0.0, 0.0, 1.0);

mat4 bias = mat4(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.0, 0.5,
0.5, 0.5, 0.5, 1.0);
mat4 shadowProjMatrix2 = bias * shadowProjMatrix;
shadowCoord = shadowProjMatrix * aPosition;

gl_Position = position;//uMVPMatrix * aPosition;
}

Code: [Select]
// Frag shader Phong Shading - Per-pixel lighting

precision highp float;

// texture variables
uniform sampler2D shadowTexture; // depth texture
uniform sampler2D texture1; // color texture


varying float tex;
varying vec2 tCoord;

varying vec3 vNormal;
varying vec3 EyespaceNormal;

// light
uniform vec4 lightPos;
uniform vec4 lightColor;

// shadow projection matrix
uniform mat4 shadowProjMatrix;

// material
uniform vec4 matAmbient;
uniform vec4 matDiffuse;
uniform vec4 matSpecular;
uniform float matShininess;

// eye pos
uniform vec3 eyePos;

// from vertex s
varying vec3 lightDir, eyeVec;

// shadow coordinates
varying vec4 shadowCoord;


float getShadowFactor(vec4 lightZ)
{
vec4 packedZValue = texture2D(shadowTexture, lightZ.st);

// unpack
const vec4 bitShifts = vec4(1.0 / (256.0 * 256.0 * 256.0),
1.0 / (256.0 * 256.0),
1.0 / 256.0,
1);
float shadow = dot(packedZValue , bitShifts);

return float(shadow > lightZ.z);
}

void main() {
// Just to show them being used
//vec4 a = lightPos;
    vec4 b = lightColor;
    vec4 c = matAmbient;
    vec4 d = matDiffuse;
    vec4 e = matSpecular;
    vec3 g = eyePos;
    float f = matShininess;

vec3 N = normalize(EyespaceNormal);
    vec3 E = normalize(eyeVec);
   
    vec3 L = normalize(lightDir);
   
    // Reflect the vector. Use this or reflect(incidentV, N);
    vec3 reflectV = reflect(-L, N);
   
    // Get lighting terms
    vec4 ambientTerm;
    if (tex >= 1.0) {
    ambientTerm = texture2D(texture1, tCoord);
    }
    else
        ambientTerm = matAmbient * lightColor;
   
    vec4 diffuseTerm = matDiffuse * max(dot(N, L), 0.0);
    vec4 specularTerm = matSpecular * pow(max(dot(reflectV, E), 0.0), matShininess);
   
   
    // Shadow
    float sValue = 1.0;
    float sValue2 = 1.0;
    if (shadowCoord.w > 0.0) {
    vec4 lightZ = shadowCoord / shadowCoord.w;
lightZ = (lightZ + 1.0) /2.0;

sValue = getShadowFactor(lightZ);

// scale the value from 0.5-1.0 to get a "softer" shadow for ambient
float newMin = 0.5;
float v1 = (1.0)/(1.0 - newMin);
float v2 = sValue/v1;
sValue2 = sValue + newMin;//v2 + newMin;
}
   
    gl_FragColor =  ( ambientTerm * sValue2 + (diffuseTerm + specularTerm) * sValue) ;
}

Issues I am facing :
1. How do I pass the Depth Texture to the Phong shader so that it processes the shadow.
2. Which shader should be set for which object. (I have a Plane , a Cube , a Sphere and a Cone. The cone , the sphere , and the cube lies on the plane.)
3. Do I have to use world.setglobalshader(shader)

Offline sushobhit

  • long
  • ***
  • Posts: 109
  • future is now
    • View Profile
    • ANDROID APPS
Re: Shadow Maker Shader
« Reply #7 on: May 30, 2014, 12:12:35 pm »
Also I would like to confirm if this Algorithm could be applied to any type of Shader right. Like , instead of the Phong Shader if I use gourard shading or perpixel ?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Shadow Maker Shader
« Reply #8 on: May 30, 2014, 05:55:42 pm »
1. How do I pass the Depth Texture to the Phong shader so that it processes the shadow.
By setting it as the second texture layer to all objects in question.
2. Which shader should be set for which object. (I have a Plane , a Cube , a Sphere and a Cone. The cone , the sphere , and the cube lies on the plane.)
In the depth texture path, set your depth map write shader to all objects that should cast a shadow and make all others invisible.
In the actual render pass, set all shadow receivers to the shader that evaluates the depth map.
3. Do I have to use world.setglobalshader(shader)
You might, but i don't think that it's very useful for this. It only affects objects that have to other shader assigned to them.

Offline sushobhit

  • long
  • ***
  • Posts: 109
  • future is now
    • View Profile
    • ANDROID APPS
Re: Shadow Maker Shader
« Reply #9 on: May 31, 2014, 11:29:22 am »
And I believe the reason behind the low resoulution of shadows that this shader creates is because of the size of depth texture it's 512x512 , increasing the size will increase the quality of the output shadow right. Taking in account the vm of the phone/tab.

Also , please can you elaborate as to how to go on the process with jpct.

Also I am trying with Mr thomas's "fps game" but still struggling with it...
« Last Edit: May 31, 2014, 02:06:14 pm by sushobhit »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Shadow Maker Shader
« Reply #10 on: June 01, 2014, 09:10:14 pm »
Also , please can you elaborate as to how to go on the process with jpct.
Well, basically you

  • Assign your depth map writing shader to all shadow casters, make all other objects invisible
  • Assign the depth map texture as render target (has to be the second texture layer (or third or...) for all shader receivers already)
  • Render the scene from the light source's point of view and direction
  • Remove the render target
  • Assign your depth map reading shader to all shadow receivers (if they don't have it already)
  • Setup your uniforms for texture projection and light source position in the depth map reading shader
  • Render the scene from the normal camera's view

Offline sushobhit

  • long
  • ***
  • Posts: 109
  • future is now
    • View Profile
    • ANDROID APPS
Re: Shadow Maker Shader
« Reply #11 on: June 03, 2014, 07:20:07 am »
Thank You for helping me get through this.
I am highly obliged for if you both wouldnt have helped this would have taken
about 2 months to get it running all by myself which took just 1 week.


Yes I have it completed now. Perfect and Universal.

Can be applied to all or any objects.

It is from Thomas "fps game" project finally got it running.