GAMES202 作业1

首先是MVP矩阵,这里可以直接调用webgl的函数进行计算。
这里比较有趣的是正交投影区间的选取,要保证能够覆盖整个平面,后面可以通过修改函数来可视化看的见的范围。
选取的投影平面大小会影响阴影锯齿大小

    CalcLightMVP(translate, scale) {
        let lightMVP = mat4.create();
        let modelMatrix = mat4.create();
        let viewMatrix = mat4.create();
        let projectionMatrix = mat4.create();

        // Model transform
        mat4.translate(modelMatrix,modelMatrix,translate);
        mat4.scale(modelMatrix,modelMatrix,scale);
        // View transform
        mat4.lookAt(viewMatrix,this.lightPos,this.focalPoint,this.lightUp);
        // Projection transform
        let t=100;
        let b=-100;
        let l=-100;
        let r=-l
        mat4.ortho(projectionMatrix,l,r,b,t,1e-2,400);
        

        mat4.multiply(lightMVP, projectionMatrix, viewMatrix);
        mat4.multiply(lightMVP, lightMVP, modelMatrix);

        return lightMVP;
    }

接下来是useShadowMap函数
需要注意的是之前在shadowFragment.glsl中,float类型的深度值已经被打包成rgba值存在texture里了,这里要先在纹理中取出深度值,然后再用unpack转回float值。
+0.01是为了避免自遮挡

float useShadowMap(sampler2D shadowMap, vec4 shadowCoord){
  //get 2D position in texture,it is a rgba value
  vec4 rgbaDepth = texture2D(shadowMap,shadowCoord.xy);
  //use the function to transform rgba value to real shadow depth
  float depth = unpack(rgbaDepth);
  //shading point's z depth is just z
  float shadingPointDepth = shadowCoord.z;
  // 这里的深度是指光源到点的z轴长度,是正值。
  float ret = shadingPointDepth < depth+0.01 ? 1.0:0.0;

  return ret;
}

这里借鉴了另一篇博客的方法,所谓选取滤波范围其实只是把随机生成的采样点放大或者缩小,使其落在指定的范围内,采样数恒定不变,但采样范围发生变化。

float PCF(sampler2D shadowMap, vec4 coords) {
  //use coords as seed to initalize 
  uniformDiskSamples(coords.xy);
  
  float textureSize = 2048.0;

  float filterStride = 5.0;

  float filterRange = filterStride/textureSize;

  int unBlockCount=0;
  for(int i=0;i<NUM_SAMPLES;i++){
    vec2 sampleCoord = poissonDisk[i] * filterRange +coords.xy;
    vec4 rgbaDepth = texture2D(shadowMap,sampleCoord);
    float depth = unpack(rgbaDepth);
    float shadingPointDepth = coords.z;
    if(shadingPointDepth < depth+0.01){
      unBlockCount++;
    }
  }
  return float(unBlockCount)/float(NUM_SAMPLES);
}

下面是两种随机采样方式的对比
泊松
 PCS-poissonDiskSamples
uniform
PCS-uniformDiskSamples
这样乍得一看,两种随机采样方式得到的结果似乎差别并不明显,但其实不然。
泊松
PCS-poissonDiskSamples
uniform
PCS-uniformDiskSamples
可以看到,uniform的模式下,阴影的过渡部分有明显的层级,而泊松则平滑许多

还有个有意思的现象,阴影上有均匀分布的白条,从光源的方向观察可以看到他们在不同距离的平面上是可以对齐的,推测产生的原因应该是因为渲染的物体处于shadowmap像素之间的格子上,在选取临近像素时采样出现问题。
在这里插入图片描述

findblocker要注意的是在shadowmap深度值和zreciver比较的时候,要-0.01而不是+,因为这里我们要筛选出来比阴影物体更加远的片元,要反向防止自遮挡现象,可以手动试下把这里改成+会出现什么现象。
LIGHT_WIDTH可以自己设置值,一般来说越大阴影的模糊现象更明显,越小则接近点光源,不会出现太明显的软阴影。

float findBlocker( sampler2D shadowMap,  vec2 uv, float zReceiver ) {
  poissonDiskSamples(uv);
  //uniformDiskSamples(uv);
  float textureSize = 400.0;

  float filterStride = 20.0;

  float filterRange = 1.0/textureSize*filterStride;
  
  int shadowCount=0;
  float depthSum=0.0;
  for(int i=0;i<NUM_SAMPLES;i++){
    vec2 sampleCoord = poissonDisk[i] * filterRange + uv;
    vec4 rgbaDepth = texture2D(shadowMap,sampleCoord);
    float depth = unpack(rgbaDepth);
    if(zReceiver > depth-0.01){
      depthSum+=depth;
      shadowCount+=1;
    }
  }

  return depthSum/float(shadowCount);
}
float PCSS(sampler2D shadowMap, vec4 coords){
  // STEP 1: avgblocker depth
  
  float depthBlocker = findBlocker(shadowMap,coords.xy,coords.z);
  float depthReciver = coords.z;

  // STEP 2: penumbra size
  uniformDiskSamples(coords.xy);
  float textureSize = 400.0;
  float filterStride = 5.0;
  float wp = (depthReciver-depthBlocker)/depthBlocker*LIGHT_WIDTH;
  float filterRange = filterStride/textureSize*wp;

  // // STEP 3: filtering
  int unBlockCount=0;
  for(int i=0;i<NUM_SAMPLES;i++){
    vec2 sampleCoord = poissonDisk[i] * filterRange +coords.xy;
    vec4 rgbaDepth = texture2D(shadowMap,sampleCoord);
    float depth = unpack(rgbaDepth);
    if(depthReciver < depth+0.01){
      unBlockCount++;
    }
  }
  return float(unBlockCount)/float(NUM_SAMPLES);
  //return wp;

}


效果
在这里插入图片描述

下面是一些过程中奇怪的现象

在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值