【Games202学习笔记02】作业1简单实现

文件及函数参与分析

ShadowMap

在这里插入图片描述

该文件中的 CalcLightMVP() 函数计算得到了后面需要使用的 lightMVP。
在 PhongMaterial.js 中的 buildPhongMaterial() 函数中的 new PhongMaterial() 使用

调用 buildPhongMaterial()return new PhongMaterial(color, specular, light, translate, scale, vertexShader, fragmentShader);

在 PhongMaterial 实例化时
let lightMVP = light.CalcLightMVP(translate, scale);

在 ShadowMaterial.js 中类似也是在bulid函数中和实例化时使用
之后再 loadOBJ.js 中结合定义的 transform 和 scale 赋值传入 material

let material, shadowMaterial;
let Translation = [transform.modelTransX, transform.modelTransY, transform.modelTransZ];
let Scale = [transform.modelScaleX, transform.modelScaleY, transform.modelScaleZ];
let light = renderer.lights[0].entity;
switch (objMaterial) {
	case 'PhongMaterial':
		material = buildPhongMaterial(colorMap, mat.specular.toArray(), light,Translation, Scale,
		 "./src/shaders/phongShader/phongVertex.glsl",
		 "./src/shaders/phongShader/phongFragment.glsl");
		shadowMaterial = buildShadowMaterial(light, Translation, Scale,
		"./src/shaders/shadowShader/shadowVertex.glsl",
		"./src/shaders/shadowShader/shadowFragment.glsl");
	break;
}

transform 和 scale 是在 engine.js 中定义好的

function setTransform(t_x, t_y, t_z, s_x, s_y, s_z) {
	return {
		modelTransX: t_x,
		modelTransY: t_y,
		modelTransZ: t_z,
		modelScaleX: s_x,
		modelScaleY: s_y,
		modelScaleZ: s_z,
	};
}

在 phongFragment.glsl 中的 main() 会使用在 DirectionalLight.js 中创建的 fbo 并将其解包成阴影贴图中的深度之后使用 useShadowMap() 计算 visibility

float useShadowMap(sampler2D shadowMap, vec4 shadowCoord)
{
  float lightDepth = unpack(texture2D(shadowMap, shadowCoord.xy));  // 阴影贴图中的最小深度
  float shadingDepth = shadowCoord.z; // 当前点的深度
  float bias = getBias();
  return lightDepth + EPS <= shadingDepth - bias ? 0.2 : 0.9; //此处的光照系数
}

传入的参数 shadowCoord 在 main() 中需要归一化
//shadowCoord 归一化 这东西的xy本质上是uv z是深度
vec3 shadowCoord = vPositionFromLight.xyz / vPositionFromLight.w;

getBias()

float getBias()
{
  vec3 lightDir = normalize(uLightPos - vFragPos);
  vec3 normal = normalize(vNormal);
  float m = 300.0 / 2048.0 / 2.0; //正交矩阵宽高/shadowmap分辨率/2   DirectionalLight.js 中CalcLightMVP()计算的矩阵
  float bias = max(m * (1.0 - dot(normal, lightDir)), m);
  return bias;
}

PCF

在这里插入图片描述
在这里插入图片描述
相对于直接使用 shadowmap 添加(可变)偏差以减少自遮挡,如果之前shadowmap记录的深度小还不够,得明显的小才行,如果中间有东西就不算了。黄色的那一小段不算。越接近垂直打光偏差空间越小,反之越大,使用夹角判断。
在这里插入图片描述
同样的在phongFragment.glsl中的main()函数中使用 PCF() 计算visibility

visibility = PCF(uShadowMap, vec4(shadowCoord, 1.0));

/**
 * @param {sampler2D}  提取来自方向光(DirectionalLight)中创建的FBO中的深度信息
 * @param {vec4}
 * @param {float}  取样范围
*/
float PCF(sampler2D shadowMap, vec4 coords) 
{
  // 给定步长和shadowMap分辨率,初始输出值、卷积核心当前的深度
  float stride = 10.0;
  float shadowMapSize = 2048.0; //在 engine.js 里可以看
  float visibility = 0.0;
  float shadingDepth = coords.z;

  // 使用泊松分布获取采样点
  poissonDiskSamples(coords.xy);

  // 对所有点进行深度比较并进行累加
  for(int i = 0; i < NUM_SAMPLES; i++) 
  {
    vec4 shadowColor = texture2D(shadowMap, coords.xy + poissonDisk[i] * stride / shadowMapSize);
    float lightDepth = unpack(shadowColor);
    float res = lightDepth + EPS <= shadingDepth ? 0.0 : 1.0;
    visibility += res;
  }
  return visibility / float(NUM_SAMPLES);
}

泊松分布这里我只用了圆盘采样 记得写到 PCF() 上面
//泊松圆盘采样 https://blog.csdn.net/qq_21476953/article/details/118440245
//https://blog.csdn.net/xiaoyaolangwj/article/details/119180217
vec2 poissonDisk[NUM_SAMPLES];

void poissonDiskSamples( const in vec2 randomSeed ) {

  float ANGLE_STEP = PI2 * float( NUM_RINGS ) / float( NUM_SAMPLES );
  float INV_NUM_SAMPLES = 1.0 / float( NUM_SAMPLES );

  float ANGLE = rand_2to1( randomSeed ) * PI2;
  float radius = INV_NUM_SAMPLES;
  float radiusStep = radius;

  for( int i = 0; i < NUM_SAMPLES; i ++ ) {
    poissonDisk[i] = vec2( cos( ANGLE ), sin( ANGLE ) ) * pow( radius, 0.75 );
    radius += radiusStep;
    ANGLE += ANGLE_STEP;
  }
}

PCSS

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
PCSS同样在main()中计算 visibility 使用

float findBlocker( sampler2D shadowMap,  vec2 uv, float zReceiver ) 
{
  // zReceiver 就是传入的当前coords的深度值
  int blockNumber = 0;
  float blockDepth = 0.0;
  float shadowMapSize = 2048.0;
  float stride = 50.0;

  // 泊松采样得到点
  poissonDiskSamples(uv);

  // 判断是否在阴影里 以决定是否累加
  for(int i = 0; i < NUM_SAMPLES; i++) 
  {
    vec4 shadowColor = texture2D(shadowMap, uv + poissonDisk[i] * stride / shadowMapSize);
    float shadowDepth = unpack(shadowColor);
    if(zReceiver > shadowDepth + 0.01)
    {
      blockNumber++;
      blockDepth += shadowDepth;
    }
  }
  
  // 被光照的地方要返回1不然场景是全黑的
  if(blockNumber == 0)
  {
    return 1.0;
  }

  return  float(blockDepth) / float(blockNumber);
}

float PCSS(sampler2D shadowMap, vec4 coords)
{
  // STEP 1: avgblocker depth
  float depthBlocker = findBlocker(shadowMap, coords.xy, coords.z);
  float weighLight = 1.0; // 视作点光源
  float depthReceiver = coords.z;
  // STEP 2: penumbra size
  float weighPenumbra = weighLight *(depthReceiver - depthBlocker) / depthBlocker;
  // STEP 3: filtering
  float stride = 20.0;
  float shadowMapSize = 2048.0; //在 engine.js 里可以看
  float visibility = 0.0;
  float shadingDepth = coords.z;

  for(int i = 0; i < NUM_SAMPLES; i++) 
  {
    vec4 shadowColor = texture2D(shadowMap, coords.xy + poissonDisk[i] * stride / shadowMapSize * weighPenumbra);
    float lightDepth = unpack(shadowColor);
    float res = lightDepth + EPS <= shadingDepth  ? 0.0 : 1.0;
    visibility += res;
  }
  return visibility / float(NUM_SAMPLES);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值