Jump to content
  • Advertisement
_WeirdCat_

OpenGL GLSL Screen space shadows few issues

Recommended Posts

So, algorithm looks like this:

Use fbo

Clear depth and color buffers

Write depth

Stretch fbo depth texture to screen size and compare that with final scene

 

GLSL algo looks like this:

Project light position and vertex position to screen space coords then move them to 0..1 space

Compute projected vertex to light vector

Then by defined number of samples go from projected vertex position to projected light position:

- Get the depth from depth texture

- unproject this given texture coord and depth value * 2.0 - 1.0 using inverse of (model*view)*projection matrix

Find closest point on line (world_vertex_pos, wirld light pos) to unprojected point, if its less than 0.0001 then i say the ray hit something and original fragment is in shadow

 

Now i forgot few things, so i'll have to ask:

In vertex shader i do something like this


vertexClip.x = dp43(MVP1, Vpos);
vertexClip.y = dp43(MVP2, Vpos);
vertexClip.z = dp43(MVP3, Vpos);
vertexClip.w = dp43(MVP4, Vpos);

scrcoord = vec3(vertexClip.x, vertexClip.y, vertexClip.z);


Where
float dp43(vec4 matrow, vec3 p)
{
return ( (matrow.x*p.x) + (matrow.y*p.y) + (matrow.z*p.z) + matrow.w );
}

It looks like i dont have to divide scrcoord by vertexClip.w component when i do something like this at the end of shader

gl_Position = vertexClip; and fragments are located where they should be...

I pass scrcoord to fragment shader, then do 0.5 + 0.5 to know from which position of the depth tex i start to unproject values.

So scrcoord should be in -1..1 space right?

Another thing is with unprojecting a screen coord to 3d position:

So far i use this formula:

Get texel depth, do *2.0-1.0 for all xyz components

Then multiple it by inverse of (model*view)*projection matrix like that:

Not quite sure if this isneven correct:

vec3 unproject(vec3 op)
{
	vec3 outpos;
outpos.x = dp43(imvp1, op);
outpos.y = dp43(imvp2, op);
outpos.z = dp43(imvp3, op);

return outpos;
}

 

And last question is about ray sampling i'm pretty sure it will skip some pixels making shadowed fragments unshadowed.... Need somehow to fix that too, but for now i have no clue...


vec3 act_tex_pos = fcoord + projected_ldir * sample_step * float ( i );

 

 

I checked depth tex for values and theyre right.


Vert shader

precision highp float;
attribute vec3 Vpos;
attribute vec3 Vnormal;

uniform vec4 MVP1;
uniform vec4 MVP2;
uniform vec4 MVP3;
uniform vec4 MVP4;

uniform vec4 WM1;
uniform vec4 WM2;
uniform vec4 WM3;
uniform vec4 WM4;

uniform vec3 LPOS;
uniform vec3 LDIFF;
uniform vec3 LAMB;

float dp43(vec4 matrow, vec3 p)
{
return ( (matrow.x*p.x) + (matrow.y*p.y) + (matrow.z*p.z) + matrow.w );
}


float dp33(vec4 matrow, vec3 p)
{
return matrow.x*p.x + matrow.y*p.y + matrow.z*p.z;
}


vec3 vectorAB( vec3 A, vec3 B)
{
return B - A;
}

varying vec4 fragColor;
varying vec3 vertex_pos;
varying vec3 scrcoord;
void main()
{
vec4 vertexClip;

vertexClip.x = dp43(MVP1, Vpos);
vertexClip.y = dp43(MVP2, Vpos);
vertexClip.z = dp43(MVP3, Vpos);
vertexClip.w = dp43(MVP4, Vpos);

scrcoord = vec3(vertexClip.x, vertexClip.y, vertexClip.z);
//scrcoord = scrcoord / vertexClip.w;
vec3 normal;
normal.x = dp33(WM1, Vnormal);
normal.y = dp33(WM2, Vnormal);
normal.z = dp33(WM3, Vnormal);
normal = normalize(normal);

vertex_pos.x = dp43(WM1, Vpos);
vertex_pos.y = dp43(WM2, Vpos);
vertex_pos.z = dp43(WM3, Vpos);

vec3 light_vert = normalize( vectorAB( LPOS, vertex_pos ) );
float intensity = clamp(-dot(light_vert, normal), 0.0, 1.0);


vec3 res_col = clamp( LAMB + LDIFF*intensity, 0.0, 1.0);
fragColor = vec4(res_col, 1.0);
gl_Position = vertexClip;







}

 

 

 

 

Andd frag one

 

precision highp float;
varying vec4 fragColor;

varying vec3 vertex_pos;
varying vec3 scrcoord;
uniform sampler2D depthtex;


highp vec3 vectorAB(highp vec3 A, highp vec3 B)
{
return B-A;
}


highp float getDepth(highp vec2 pos)
{

    highp vec4 packedZValue = texture2D(depthtex, pos);

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

highp float dp43(highp vec4 matrow, highp vec3 p)
{
return ( (matrow.x*p.x) + (matrow.y*p.y) + (matrow.z*p.z) + matrow.w );
}




uniform vec3 LPOS;
//inverse (model*view)*projection matrix
uniform vec4 imvp1;
uniform vec4 imvp2;
uniform vec4 imvp3;
uniform vec4 imvp4;


uniform vec4 MVP1;
uniform vec4 MVP2;
uniform vec4 MVP3;
uniform vec4 MVP4;


highp float n3ddistance(highp vec3 first_point, highp vec3 second_point)
{
highp float x = first_point.x-second_point.x;
highp float y = first_point.y-second_point.y;
highp float z = first_point.z-second_point.z;
highp float val = x*x + y*y + z*z;
return sqrt(val);
}

vec3 ClosestPointOnLine (vec3 vA,vec3 vB,vec3 vPoint)
{
	vec3 vVector1 = vPoint - vA;
	vec3 vVector2 = normalize(vB - vA);

float d = n3ddistance(vA, vB);
float t = dot(vVector2, vVector1);


    if (t <= 0.0) return vA;
    if (t >= d) return vB;


vec3 vVector3 		= vVector2 * t;
vec3 vClosestPoint 	= vA + vVector3;


	return vClosestPoint;
}

vec3 unproject(vec3 op)
{
	vec3 outpos;
outpos.x = dp43(imvp1, op);
outpos.y = dp43(imvp2, op);
outpos.z = dp43(imvp3, op);

return outpos;
}

const int num_samples = 100;

void main()
{
vec3 ray_dir = normalize( vectorAB(vertex_pos, LPOS) );


vec4 lightpos_projected2;
/*
project light position and vertex world position to 0..1 of scr coord
*/
lightpos_projected2.x = dp43(MVP1, LPOS);
lightpos_projected2.y = dp43(MVP2, LPOS);
lightpos_projected2.z = dp43(MVP3, LPOS);
lightpos_projected2.w = dp43(MVP4, LPOS);
vec3 lightpos_projected;
lightpos_projected = lightpos_projected2.xyz / lightpos_projected2.w;
lightpos_projected = lightpos_projected * 0.5 + 0.5;

vec3 fcoord = scrcoord * 0.5 + 0.5;

//get the projected vector
vec3 projected_ldir = normalize( vectorAB( fcoord, lightpos_projected) );
float vldst = n3ddistance( fcoord, lightpos_projected );


float sample_step = vldst / float ( num_samples );


bool shadowed = false;
for (int i=1; i < num_samples; i++) //start from 1 cause wendont want to check start vertex
{
vec3 act_tex_pos = fcoord + projected_ldir * sample_step * float ( i );

if (act_tex_pos.x < 0.0) continue;
if (act_tex_pos.x > 1.0) continue;
if (act_tex_pos.y < 0.0) continue;
if (act_tex_pos.y > 1.0) continue;

float zcoord =  getDepth(act_tex_pos.xy);
if ( zcoord >=0.98 ) continue;
if ( zcoord <= 0.0 ) continue;


zcoord = zcoord * 2.0 - 1.0;
vec3 uppos = act_tex_pos * 2.0 - 1.0;
uppos.z = zcoord;

vec3 unprojected_position = unproject(uppos);
vec3 cpol = ClosestPointOnLine( LPOS, vertex_pos, unprojected_position);

if (n3ddistance(cpol, unprojected_position) <= 0.0001)
{
	shadowed = true;
	break;
}


}
vec4 ahue = vec4(1.0, 1.0, 1.0, 1.0);
if (shadowed)
	gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
//ahue = vec4(0.2, 0.2, 0.2, 1.0);
else
gl_FragColor = vec4(fragColor.x*ahue.x, fragColor.y*ahue.y, fragColor.z*ahue.z, 1.0);

}

 

 

Like you see shadow shall be colored in red. But i dont see any red.

https://i.imgur.com/U39BYF0.png

Share this post


Link to post
Share on other sites
Advertisement
15 hours ago, KKTHXBYE said:

And last question is about ray sampling i'm pretty sure it will skip some pixels making shadowed fragments unshadowed.... Need somehow to fix that too, but for now i have no clue...

Is the basic thrust of this that you are trying to do a shadow test in the vertex shader? Is that based on someones suggestion? You can do a shadow test entirely in pixel. The principle is simple, get the depth of a point from the camera and the (probably single) light source. If they are different, something is in the way. The rest is details for performance and aesthetics like blending different scale shadow maps, dealing with blockiness or  'acne' etc. Between the http://www.rastertek.com/dx11tut40.html and http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/ examples it should be followable (assuming you aren't a complete beginner). 

 

The only thing I'd add is there is sometimes confusion around homogeneous coordinates and the need to divide by w to undo the projection, have a look at https://www.tomdalling.com/blog/modern-opengl/explaining-homogenous-coordinates-and-projective-geometry/.

Share this post


Link to post
Share on other sites

Well the main problem is with unprojecting the fragment - im not surenif i donthat correctly, second thing is i do shadowtest enteirly in fragment shader i only pass world vertex position and screen coord to fragment shader

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!