[GLSL] Prevent lights from casting onto shadows

Started by
11 comments, last by L. Spiro 9 years, 4 months ago

GL_SIGNED_RGBA_NV does exactly like what it sounds it does. Color channels range from -128 to 127, instead of from 0 to 255.

jxyscale is also likely exactly like what it sounds. It scales the X and Y coordinates you read from the jitter map. If you are getting good results already, keep it set to 1.0f or keep it set to a ratio of the size of your jitter texture.

Or better yet, just do regular PCF and forget about it.

This method will only work on NVIDIA cards and is definitely a performance issue. If you are planning on anyone else ever seeing the work you are doing you have no choice but to make a standard PCF routine anyway.

It is pretty trivial to implement as you can see here. He has animated examples of many kinds of shadows so you can actively see their results, plus full source code for all samples is there (click the green “example” text near any given sample).

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Advertisement

I've got it to look fairly decent for spotlights now, but point lights are a bit more tricky.

I found one way on how to do it here: http://www.sunandblackcat.com/tipFullView.php?l=eng&topicid=36

Basically, he just samples the shadow with offsets in various different directions, then averages the results. I am again unclear about a couple of things though. Here's his fragment shader:


#version 330

// shadow map
layout(location = 0) uniform samplerCube	u_shadowCubeMap;

// world space position of the fragment
in vec4	o_worldPosition;

// color to the framebuffer
layout(location = 0) out vec4 resultingColor;

// position of the point light source
uniform vec3	u_lightPos;
// distances to near and far cliping planes
uniform vec2	u_nearFarPlane;

// array of offset direction for sampling
vec3 gridSamplingDisk[20] = vec3[]
(
   vec3(1, 1, 1), vec3(1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
   vec3(1, 1, -1), vec3(1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
   vec3(1, 1, 0), vec3(1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
   vec3(1, 0, 1), vec3(-1, 0, 1), vec3(1, 0, -1), vec3(-1, 0, -1),
   vec3(0, 1, 1), vec3(0, -1, 1), vec3(0, -1, -1), vec3(0, 1, -1)
);

// function compares distance from shadow map with current distance
void sampleShadowMap(in vec3 baseDirection, in vec3 baseOffset,
      in float curDistance, inout float shadowFactor, inout float numSamples)
{
   shadowFactor += texture(u_shadowCubeMap,
      vec4(baseDirection + baseOffset, curDistance));
   numSamples += 1;
}

void main(void)
{
   // difference between position of the light source and position of the fragment
   vec3 fromLightToFragment = u_lightPos - o_worldPosition.xyz;
   // normalized distance to the point light source
   float distanceToLight = length(fromLightToFragment);
   float currentDistanceToLight = (distanceToLight - u_nearFarPlane.x) /
            (u_nearFarPlane.y - u_nearFarPlane.x);
   currentDistanceToLight = clamp(currentDistanceToLight, 0, 1);
   // normalized direction from light source for sampling
   fromLightToFragment = normalize(fromLightToFragment);

   // sample shadow cube map
   float referenceDistanceToLight	= texture(u_shadowCubeMap, -fromLightToFragment).r;

   float shadowFactor = 0;
   float numSamples = 0;

   // radius of PCF depending on distance from the light source
   float diskRadius = (1.0 + (1.0 - currentDistanceToLight) * 3) / sizeOfCubeTex;

   // evaluate each sampling direction
   for(int i=0; i<20; i++)
   {
      sampleShadowMap(-fromLightToFragment, gridSamplingDisk[i] * diskRadius,
         currentDistanceToLight, shadowFactor, numSamples);
   }

   // average shadow factor
   shadowFactor /= numSamples;

   // output color to framebuffer
   resultingColor.rgb = vec3(shadowFactor);
   resultingColor.a = 1;
}

I don't quite understand the calculation for the "currentDistanceToLight". From the shader it looks like "u_nearFarPlane" represents the near / far plane of the camera, but shouldn't it be the near / far plane of the light instead? The shadow map is generated with the light's near and far plane after all.

Secondly, in the calculation for the diskRadius:


float diskRadius = (1.0 + (1.0 - currentDistanceToLight) * 3) / sizeOfCubeTex;

Where does the 'times 3' come from?

If you use a single image 6 times taller or wider for your point-light shadow maps and avoid cubemaps altogether then PCF filtering works the same way. It is simpler and faster.
You only have to manually write a sampling routine that takes the same 3 coordinates you would have used on a cubemap and convert them to the correct 2D coordinates in your 2D “cubemap”, which is not difficult (certainly easier then what you are trying to do now).


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement