Jump to content

Screen-space shadows


Josh
 Share

Recommended Posts

I basically took the ray-tracing code that Igor and Shadmar developed, with my own additions, and am trying to use that to trace shadows in screen space. The result of the shadowmap lookup is multiplied by the result of the ray-trace lookup for finer resolution.

 

It's very expensive to render and not that great, but go ahead and try it out if you like.

 

DirectionalLight.shader pixel shader:

#version 400

#define PI 3.14159265359

#define HALFPI PI/2.0

#define LOWERLIGHTTHRESHHOLD 0.001

#ifndef SHADOWSTAGES

#define SHADOWSTAGES 4

#endif

#ifndef SAMPLES

#define SAMPLES 1

#endif

#ifndef KERNEL

#define KERNEL 3

#endif

#define KERNELF float(KERNEL)

#define GLOSS 10.0

 

#if SAMPLES==0

uniform sampler2D texture0;//depth

uniform sampler2D texture1;//diffuse.rgba

uniform sampler2D texture2;//normal.xyz, diffuse.a

uniform sampler2D texture3;//specular, ao, flags, diffuse.a

uniform sampler2D texture4;//emission.rgb, diffuse.a

#else

uniform sampler2DMS texture0;//depth

uniform sampler2DMS texture1;//diffuse.rgba

uniform sampler2DMS texture2;//normal.xyz, diffuse.a

uniform sampler2DMS texture3;//specular, ao, flags, diffuse.a

uniform sampler2DMS texture4;//emission.rgb, diffuse.a

#endif

 

uniform sampler2DShadow texture5;//shadowmap

 

/* Possible future optimization:

uniform sampler2DMS texture0;//depth

uniform sampler2DMS texture1;//diffuse.rgba

uniform sampler2DMS texture2;//normal.xyz, specular

uniform sampler2DMS texture4;//emission.rgb, flags

*/

 

uniform mat3 cameranormalmatrix;

uniform mat3 camerainversenormalmatrix;

uniform vec2[4] shadowstagepositon;

uniform vec2 shadowstagescale;

uniform vec4 ambientlight;

uniform vec2 buffersize;

uniform vec3 lightdirection;

uniform vec4 lightcolor;

uniform vec4 lightspecular;

uniform vec2 camerarange;

uniform float camerazoom;

uniform vec2[sHADOWSTAGES] lightshadowmapoffset;

uniform mat4 lightmatrix;

uniform mat3 lightnormalmatrix0;

uniform mat3 lightnormalmatrix1;

uniform mat3 lightnormalmatrix2;

uniform mat3 lightnormalmatrix3;

uniform vec2 shadowmapsize;

uniform vec2 lightrange;

uniform vec3[sHADOWSTAGES] lightposition;

//uniform vec3 lightposition0;

//uniform vec3 lightposition1;

//uniform vec3 lightposition2;

//uniform vec3 lightposition3;

uniform float[sHADOWSTAGES] shadowstagearea;

uniform float[sHADOWSTAGES] shadowstagerange;

uniform bool isbackbuffer;

uniform mat4 projectioncameramatrix;

uniform vec3 cameraposition;

 

//User variables

#define reflectionfalloff 10.0

#define maxstep 100

#define edgefadefactor 0.95

#define raylength 0.01

#define hitThreshold 0.01

 

out vec4 fragData0;

 

vec4 getPosition(in vec2 texCoord, out float z)

{

float x = texCoord.s * 2.0f - 1.0f;

float y = texCoord.t * 2.0f - 1.0f;

z = texelFetch(texture0, ivec2(texCoord*buffersize),0).r;

vec4 posProj = vec4(x,y,z,1.0f);

vec4 posView = inverse(projectioncameramatrix) * posProj;

posView /= posView.w;

return posView;

}

 

float LinePointDistance(in vec3 v, in vec3 w, in vec3 p)

{

// Return minimum distance between line segment vw and point p

vec3 d = w-v;

float l2 = d.x*d.x+d.y*d.y+d.z*d.z; // i.e. |w-v|^2 - avoid a sqrt

if (l2 == 0.0) return distance(p, v); // v == w case

//float t = max(0.0f, min(1.0f, dot(p - v, w - v) / l2));

float t = dot(p - v, w - v) / l2;

vec3 projection = v + t * (w - v); // Projection falls on the segment

return distance(p, projection);

}

 

float rand(vec2 co){

return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);

}

 

float depthToPosition(in float depth, in vec2 depthrange)

{

return depthrange.x / (depthrange.y - depth * (depthrange.y - depthrange.x)) * depthrange.y;

}

 

float positionToDepth(in float z, in vec2 depthrange) {

return (depthrange.x / (z / depthrange.y) - depthrange.y) / -(depthrange.y - depthrange.x);

}

 

float ScreenSpaceShadow()

{

vec2 icoord = gl_FragCoord.xy / buffersize;

if (isbackbuffer) icoord.y = 1.0f - icoord.y;

 

float roughness=1.0;

vec4 color;

vec3 normalView;

 

//Get position and out depth (z)

float z;

vec3 posView = getPosition(icoord,z).xyz;

 

//Reflect vector

vec3 reflected = -normalize(cameranormalmatrix * lightdirection);

 

float rayLength = raylength;

vec4 T = vec4(0.0f);

vec3 newPos;

 

//Raytrace

for (int i = 0; i < maxstep; i++)

{

//newPos = posView + reflected * rayLength;

newPos = posView + reflected * raylength * float(i);

T = projectioncameramatrix * vec4(newPos, 1.0f);

T.xy = vec2(0.5f) + 0.5f * T.xy / T.w;

T.z /= T.w;

 

if (abs(z - T.z) < 1.0f && T.x <= 1.0f && T.x >= 0.0f && T.y <= 1.0f && T.y >= 0.0f)

{

float depth;

newPos = getPosition(T.xy,depth).xyz;

rayLength = length(posView - newPos);

 

//Check distance of this pixel to the reflection ray. If it's close enough we count it as a hit.

if (LinePointDistance(posView,posView+reflected,newPos) < hitThreshold)

{

//Get the pixel at this normal

vec4 n1=texelFetch(texture2, ivec2(T.xy*buffersize),0);

vec3 normalView1 = normalize(n1.xyz * 2.0f - 1.0f);

 

//Make sure the pixel faces the reflection vector

if (dot(reflected,normalView1)<0.0f)

{

//Fading to screen edges

vec2 fadeToScreenEdge = vec2(1.0f);

fadeToScreenEdge.x *= distance(T.x , 1.0f);

fadeToScreenEdge.x *= distance(T.x, 0.0f) * 4.0f;

fadeToScreenEdge.y *= distance(T.y, 1.0f);

fadeToScreenEdge.y *= distance(T.y, 0.0f) * 4.0f;

float edgefade = 1.0 - clamp(fadeToScreenEdge.x * fadeToScreenEdge.y,0.0,1.0);

 

float stepfade = float(i) / float(maxstep);

//stepfade = clamp(stepfade,0.0,1.0);

 

return max(edgefade,stepfade);

}

}

}

else

{

return 1.0f;

}

}

return 1.0f;

}

 

float shadowLookup(in sampler2DShadow shadowmap, in vec3 shadowcoord, in vec2 offset)

{

if (shadowcoord.y<0.0) return 0.5;

if (shadowcoord.y>1.0) return 0.5;

if (shadowcoord.x<0.0) return 0.5;

if (shadowcoord.x>1.0) return 0.5;

 

float f=0.0;

int x,y;

vec2 sampleoffset;

 

for (x=0; x<KERNEL; ++x)

{

sampleoffset.x = float(x) - KERNELF*0.5 + 0.5;

for (y=0; y<KERNEL; ++y)

{

sampleoffset.y = float(y) - KERNELF*0.5 + 0.5;

f += texture(shadowmap,vec3(shadowcoord.x+sampleoffset.x*offset.x,shadowcoord.y+sampleoffset.y*offset.y,shadowcoord.z));

}

}

//return f/(KERNEL*KERNEL);

return f/float(KERNEL*KERNEL) * ScreenSpaceShadow();

//return ScreenSpaceShadow();

}

 

void main(void)

{

vec3 flipcoord = vec3(1.0);

if (!isbackbuffer) flipcoord.y = -1.0;

 

//----------------------------------------------------------------------

//Calculate screen texcoord

//----------------------------------------------------------------------

vec2 coord = gl_FragCoord.xy / buffersize;

if (isbackbuffer) coord.y = 1.0 - coord.y;

 

ivec2 icoord = ivec2(gl_FragCoord.xy);

if (isbackbuffer) icoord.y = int(buffersize.y) - icoord.y;

 

float depth;

vec4 diffuse;

vec3 normal;

vec4 materialdata;

float specularity;

float ao;

bool uselighting;

vec4 emission;

vec4 sampleoutput;

vec4 stagecolor;

vec3 screencoord;

vec3 screennormal;

float attenuation;

vec4 specular;

vec3 lightreflection;

float fade;

vec3 shadowcoord;

float dist;

vec3 offset;

mat3 lightnormalmatrix;

vec2 sampleoffset;

vec3 lp;

vec4 normaldata;

int materialflags;

 

fragData0 = vec4(0.0);

 

for (int i=0; i<max(1,SAMPLES); i++)

{

//----------------------------------------------------------------------

//Retrieve data from gbuffer

//----------------------------------------------------------------------

#if SAMPLES==0

depth = texture(texture0,coord).x;

diffuse = texture(texture1,coord);

normaldata = texture(texture2,coord);

emission = texture(texture3,coord);

#else

depth = texelFetch(texture0,icoord,i).x;

diffuse = texelFetch(texture1,icoord,i);

normaldata = texelFetch(texture2,icoord,i);

emission = texelFetch(texture3,icoord,i);

#endif

normal = camerainversenormalmatrix * normalize(normaldata.xyz*2.0-1.0);

specularity = emission.a;

materialflags = int(normaldata.a * 255.0 + 0.5);

uselighting = false;

if ((1 & materialflags)!=0) uselighting=true;

sampleoutput = diffuse + emission;

stagecolor = vec4(1.0,0.0,1.0,1.0);

 

//Calculate gloss

float gloss=70.0;

if ((32 & materialflags)!=0) gloss -= 40.0;

if ((64 & materialflags)!=0) gloss -= 20.0;

 

//----------------------------------------------------------------------

//Calculate screen position and vector

//----------------------------------------------------------------------

screencoord = vec3(((gl_FragCoord.x/buffersize.x)-0.5) * 2.0 * (buffersize.x/buffersize.y),((-gl_FragCoord.y/buffersize.y)+0.5) * 2.0,depthToPosition(depth,camerarange));

screencoord.x *= screencoord.z / camerazoom;

screencoord.y *= -screencoord.z / camerazoom;

screennormal = normalize(screencoord);

if (!isbackbuffer) screencoord.y *= -1.0;

 

if (uselighting)

{

//----------------------------------------------------------------------

//Calculate lighting

//----------------------------------------------------------------------

 

attenuation = max(0.0,-dot(lightdirection,normal));

lightreflection = normalize(reflect(lightdirection,normal));

if (!isbackbuffer) lightreflection.y *= -1.0;

specular = lightspecular * specularity * vec4( pow(clamp(-dot(lightreflection,screennormal),0.0,1.0),gloss) * 0.5);

specular *= lightcolor.r * 0.299 + lightcolor.g * 0.587 + lightcolor.b * 0.114;

 

#ifdef USESHADOW

fade=1.0;

if (attenuation>LOWERLIGHTTHRESHHOLD)

{

//----------------------------------------------------------------------

//Shadow lookup

//----------------------------------------------------------------------

dist = clamp(length(screencoord)/shadowstagerange[0],0.0,1.0);

offset = vec3(0.0);

//vec3 lightposition;

lightnormalmatrix = mat3(0);

sampleoffset = shadowstagepositon[0];

fade=1.0;

lp = vec3(0);

 

if (dist<1.0)

{

//offset.x = 0.0;

offset.z = -lightshadowmapoffset[0].x;

lp = lightposition[0];

lightnormalmatrix = lightnormalmatrix0;

fade=0.0;

stagecolor=vec4(1.0,0.0,0.0,1.0);

}

else

{

//fade=0.0;

dist = clamp(length(screencoord)/shadowstagerange[1],0.0,1.0);

if (dist<1.0)

{

//offset.x = 1.0;

offset.z = -lightshadowmapoffset[1].x;

lp = lightposition[1];

lightnormalmatrix = lightnormalmatrix1;

fade=0.0;

sampleoffset = shadowstagepositon[1];

stagecolor=vec4(0.0,1.0,0.0,1.0);

#if SHADOWSTAGES==2

fade = clamp((dist-0.75)/0.25,0.0,1.0);// gradually fade out the last shadow stage

#endif

}

#if SHADOWSTAGES>2

else

{

dist = clamp(length(screencoord)/shadowstagerange[2],0.0,1.0);

if (dist<1.0)

{

//offset.x = 2.0;

offset.z = -lightshadowmapoffset[2].x;

lp = lightposition[2];

lightnormalmatrix = lightnormalmatrix2;

stagecolor=vec4(0.0,0.0,1.0,1.0);

fade=0.0;

sampleoffset = shadowstagepositon[2];

#if SHADOWSTAGES==3

fade = clamp((dist-0.75)/0.25,0.0,1.0);// gradually fade out the last shadow stage

#endif

}

#if SHADOWSTAGES==4

else

{

dist = clamp(length(screencoord)/shadowstagerange[3],0.0,1.0);

if (dist<1.0)

{

stagecolor=vec4(0.0,1.0,1.0,1.0);

//offset.x = 3.0;

offset.z = -lightshadowmapoffset[3].x;

lp = lightposition[3];

lightnormalmatrix = lightnormalmatrix3;

fade = clamp((dist-0.75)/0.25,0.0,1.0);// gradually fade out the last shadow stage

sampleoffset = shadowstagepositon[3];

}

else

{

fade = 1.0;

}

}

#endif

}

#endif

}

if (fade<1.0)

{

shadowcoord = lightnormalmatrix * (screencoord - lp);

shadowcoord += offset;

shadowcoord.z = (shadowcoord.z - lightrange.x) / (lightrange.y-lightrange.x);

shadowcoord.xy += 0.5;

shadowcoord.xy *= shadowstagescale;

shadowcoord.xy += sampleoffset;

attenuation = attenuation * fade + attenuation * shadowLookup(texture5,shadowcoord,1.0/shadowmapsize) * (1.0-fade);

}

}

#endif

 

//----------------------------------------------------------------------

//Final light calculation

//----------------------------------------------------------------------

sampleoutput = (diffuse * lightcolor + specular) * attenuation + emission + diffuse * ambientlight;

//sampleoutput = (sampleoutput + stagecolor) / 2.0;

}

//Blend with red if selected

if ((2 & materialflags)!=0)

{

sampleoutput = (sampleoutput + vec4(1.0,0.0,0.0,0.0))/2.0;

}

fragData0 += sampleoutput * 1.0;

}

 

fragData0 /= float(max(1,SAMPLES));

fragData0 = max(fragData0,0.0);

gl_FragDepth = depth;

}

 

Without:

post-1-0-21534800-1480219240_thumb.jpg

 

With:

post-1-0-45472000-1480219245_thumb.jpg

post-1-0-41004900-1480219851_thumb.jpg

post-1-0-82266700-1480219857_thumb.jpg

  • Upvote 3

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...