webgl2-fundamentals icon indicating copy to clipboard operation
webgl2-fundamentals copied to clipboard

Shadows Tutorial Continuation

Open peancored opened this issue 3 years ago • 4 comments

First of all, thank you for such an amazing resource.

Are you planning to finish this part? https://github.com/gfxfundamentals/webgl2-fundamentals/blob/master/webgl/lessons/webgl-shadows-continued.md It's one of the most complex topics on the website and I'd like as much information about this as possible. Would be awesome if you have plans to release it since your tutorials are so easy to follow. The first article on shadows mentions multiple techniques of rendering shadows, so would be nice to read about other options, ray tracing possibly as I've seen it done with WebGL.

In any case, thank you so much, I couldn't have done anything I've already achieved without your tutorials.

peancored avatar Apr 15 '21 01:04 peancored

Sorry I haven't had time to continue the shadows. Mostly I'd try to cover point lights (which is basically the same thing as the current article except you render in 6 directions instead of just one to make a shadow cubemap). Another thing to cover is trying to anti-alias the shadows. Yet another is trying to adjust the math to not waste the the resolution of the shadow map texture for far away stuff but instead use it for close up stuff.

You can read about these topics all over the net, mostly in non-WebGL articles but the ideas are usually easily translatable, especially if you made it through the tutorials to the shadow article.

This article has one example of anti-aliasing and this article has an example of point light shadows

greggman avatar Apr 19 '21 15:04 greggman

I have added anti aliasing/pcf (percentage-closer filtering) for the spotligt and the last samples. Just exchange the fragment shader code with my extended one, that's it and it should work.

happy shadowing easter, friends

point light

var fs=`#version 300 es
precision highp float;
in vec2 v_texcoord;
in vec4 v_projectedTexcoord;
in vec3 v_normal;
in vec3 v_surfaceToLight;
in vec3 v_surfaceToView;

uniform vec4 u_colorMult;
uniform sampler2D u_texture;
uniform sampler2D u_projectedTexture;
uniform float u_bias;
uniform float u_shininess;
uniform vec3 u_lightDirection;
uniform float u_innerLimit;
uniform float u_outerLimit;
//                                   no need to uniform at this sample
float u_shadowVisibility=0.5;
// to uniform -->
//uniform float u_shadowVisibility;//    shadow visibility
//                                              uniform location at init time
//var blabla=gl.getUniformLocation(program, "u_shadowVisibility");
//                                                          uniform at draw time
//gl.uniform1f(blabla, your value);//0.0-1.0    uniform <--

out vec4 outColor;
void main() 
{
  vec3 normal=normalize(v_normal);

  vec3 surfaceToLightDirection=normalize(v_surfaceToLight);
  vec3 surfaceToViewDirection=normalize(v_surfaceToView);
  vec3 halfVector=normalize(surfaceToLightDirection + surfaceToViewDirection);

  float dotFromDirection=dot(surfaceToLightDirection,-u_lightDirection);
  float limitRange=u_innerLimit - u_outerLimit;
  float inLight=clamp((dotFromDirection - u_outerLimit) / limitRange, 0.0, 1.0);
  float light=inLight * dot(normal, surfaceToLightDirection);
  float specular=inLight * pow(dot(normal, halfVector), u_shininess);

  // shadow -->
  vec3 projectedTexcoord=v_projectedTexcoord.xyz/v_projectedTexcoord.w;
  float currentDepth=projectedTexcoord.z+u_bias; 
  float projectedDepth=texture(u_projectedTexture, projectedTexcoord.xy).r; 
  bool inRange=projectedTexcoord.x>=0.0&&projectedTexcoord.x<=1.0&&projectedTexcoord.y>=0.0&&projectedTexcoord.y<=1.0;  
  //float shadowLight=(inRange&&projectedDepth<=currentDepth)?0.0:1.0;  
  float shadowLight=0.0;
  //              anti aliasing/pcf (percentage-closer filtering)
  vec2 texSize=vec2(1)/vec2(textureSize(u_projectedTexture, 0));
  int samples=6;
  for(int x=0;x<samples;++x){ for(int y=0;y<samples;++y)
  {
    float pcf=texture(u_projectedTexture, projectedTexcoord.xy+vec2(x, y)*texSize).r; 
    shadowLight+=inRange&&currentDepth>pcf?u_shadowVisibility:1.0;
  }}
  //     final scene brightnes. needs to be adjusted by the
  shadowLight/=9.0*4.0;//                  amount of samples
  //                 keep the shadow at 0.0 if outside of region
  if(projectedTexcoord.z>1.0)shadowLight=0.0;
  // shadow <--
  
  vec4 texColor=texture(u_texture, v_texcoord) * u_colorMult;
  outColor=vec4(texColor.rgb * light * shadowLight +specular * shadowLight,texColor.a);
}`;

last sample on the Website

var fs=`#version 300 es
precision highp float;
in vec2 v_texcoord;
in vec4 v_projectedTexcoord;
in vec3 v_normal;

uniform vec4 u_colorMult;
uniform sampler2D u_texture;
uniform sampler2D u_projectedTexture;
uniform float u_bias;
uniform vec3 u_reverseLightDirection;
//                                   no need to uniform at this sample
float u_shadowVisibility=0.5;
// to uniform -->
//uniform float u_shadowVisibility;//    shadow visibility
//                                              uniform location at init time
//var blabla=gl.getUniformLocation(program, "u_shadowVisibility");
//                                                          uniform at draw time
//gl.uniform1f(blabla, your value);//0.0-1.0    uniform <--

out vec4 outColor;
void main() 
{
  vec3 normal=normalize(v_normal); 
  float light=dot(normal, u_reverseLightDirection);
  
  // shadow -->
  vec3 projectedTexcoord=v_projectedTexcoord.xyz/v_projectedTexcoord.w;
  float currentDepth=projectedTexcoord.z+u_bias; 
  float projectedDepth=texture(u_projectedTexture, projectedTexcoord.xy).r; 
  bool inRange=projectedTexcoord.x>=0.0&&projectedTexcoord.x<=1.0&&projectedTexcoord.y>=0.0&&projectedTexcoord.y<=1.0;
  //float shadowLight=(inRange&&projectedDepth<=currentDepth)?0.0:1.0;  
  float shadowLight=0.0;
  //              anti aliasing/pcf (percentage-closer filtering)
  vec2 texSize=vec2(1)/vec2(textureSize(u_projectedTexture, 0));
  
  int samples=3;
  for(int x=0;x<samples;++x){ for(int y=0;y<samples;++y)
  {
    float pcf=texture(u_projectedTexture, projectedTexcoord.xy+vec2(x, y)*texSize).r; 
    shadowLight+=inRange&&currentDepth>pcf?u_shadowVisibility:1.0;
  }}
  //     final scene brightnes. needs to be adjusted by the
  shadowLight/=9.0;//                         amount of samples
  //                 keep the shadow at 0.0 if outside of region
  if(projectedTexcoord.z>1.0)shadowLight=0.0;
  // shadow <--
  
  vec4 texColor=texture(u_texture, v_texcoord)*u_colorMult;
  outColor=vec4(texColor.rgb*light*shadowLight,texColor.a);
}`;

Khgiikbvhkbvv avatar Mar 22 '24 16:03 Khgiikbvhkbvv

Pardon, from this website

https://webgl2fundamentals.org/webgl/lessons/webgl-shadows.html

Khgiikbvhkbvv avatar Mar 22 '24 16:03 Khgiikbvhkbvv

Pardon again...my bad. First code is for the spotligt sample, the second one for the sampe after.

Best regards

Khgiikbvhkbvv avatar Mar 22 '24 16:03 Khgiikbvhkbvv