WebGL 阴影的实现

1、实现阴影的原理:

原理:根据光源与物体之间的距离(也就是物体在光源坐标系下的深度z值),来决定物体是否可见。如下图,同一条光线上有两个点P1、P2,由于P2的z值大于P1,所以P2在阴影中。

 

 

2、如何实现❓

需要使用两对着色器:(1)一对着色器用来计算光源到物体的距离;(2)另一对根据(1)中计算出的距离绘制场景。

 

(2)如何使用(1)中的距离❓

使用一张纹理图像把(1)的结果传入(2)中,这张纹理图像称为 <阴影贴图>。

通过阴影贴图实现阴影的方法称为 <阴影映射>。

 

阴影映射的过程:

1⃣️ 将视点移到光源的位置处,并运行(1)中的着色器。这时,那些‘将要被绘出’的片元都是被光照射到的,即落在这个像素上的各个片元中最前面的。并不实际绘制出片元的颜色,而是将片元的z值写入到阴影贴图中。

假设P1点z值为1,P2点z值为2,阴影贴图中数据大概如下:

2⃣️ 将视点移回原来的位置,运行(2)中的着色器绘制场景。此时,计算出每个片元在光源坐标系下的坐标,并与阴影贴图中记录的z值比较,如果前者大于后者,就说明当前片元处在阴影之中,用较深暗的颜色绘制。

 

3、具体实现思路:

(1)、投影矩阵: 

  Matrix4.setPerspective(fov, aspect, near, far)

        //  fov - 垂直视角,即可视空间顶面和底面间的夹角,必须大于0.

        //  aspect - 指定近裁剪面的宽高比,应当与canvas 保持一致

        //  near,far - 近、远裁剪面的位置。

⚠️ 光源的投影矩阵:aspect   需要使用生成的阴影贴图的分辨率,eg:256*256、1024*1024

⚠️ 正常绘制时的投影矩阵:aspect   使用canvas的分辨率

 

(2)、生成阴影贴图:

1⃣️ 使用 <光源处> 的视图投影矩阵,绘制模型(模型可能存在偏移、旋转等);

2⃣️ 保存此时的 <光源下的模型视图投影矩阵> ;

3⃣️ 将光源视点下的每个顶点的深度值存入到阴影贴图,保存在帧缓冲区中。 

gl_FragCoord 的内置变量是vec4类型的,用来表示片元的坐标。

gl_FragCoord.x 和 gl_FragCoord.y 是片元在屏幕上的坐标,gl_FragCoord.z 是深度值。

它们是通过 (gl_Position.xyz / gl_Position.w)/2.0+0.5 计算的,并被归一化到[0.0, 1.0]区间。

 

(3)、正常绘制模型:

1⃣️ 使用 <视点处> 的视图投影矩阵,绘制模型(模型可能存在偏移、旋转等);

2⃣️ 根据 <光源下的模型视图投影矩阵> 计算模型在光源坐标系下的顶点位置,顶点的位置需要进行归一化;

WebGL 中的x和y坐标都是在[-1.0, 1.0]区间中的,纹理坐标 s和t是在[0.0, 1.0]中的,所以需要将  模型在光源坐标系下的顶点的x和y坐标 转化为 s和t坐标:

vec3 shadowCoord = (v_PositionFromLight.xyz / v_PositionFromLight.w)/2.0+0.5;

shadowCoord.x 和 shadowCoord.y ,为当前片元在阴影贴图中对应纹素的纹理坐标,shadowCoord.z 为当前片元在光源坐标系中的归一化的z值。

3⃣️ 根据shadowCoord.x 和 shadowCoord.y,去获取到阴影贴图对应点纹素的深度值;

4⃣️ shadowCoord.z > 阴影贴图对应点纹素的深度值,visibility 为0.5,即此位置的片元为 <阴影部分>;

      shadowCoord.z < 阴影贴图对应点纹素的深度值,visibility 为1.0,即此位置的片元为 <非阴影部分>;

 

代码实现可参考:WebGL实现阴影效果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值