3D中实现实时阴影技术中比较常见的方式是阴影映射(Shadow Mapping),咱们这里也以这种技术来实现实时阴影。html
阴影映射背后的思路很是简单:咱们先以光的位置为视角进行渲染,咱们能看到的东西都将被点亮,看不见的必定是在阴影之中了(这里会将是否可视的信息做为深度贴图进行渲染)。假设有一个地板,在光源和它之间有一个大盒子。因为光源处向光线方向看去,能够看到这个盒子,但看不到地板的一部分,这部分就应该在阴影中了。git
相对来讲,平行光的实现要简单得多,下面咱们看看平行光的阴影实现原理:github
示例请查看:https://hammerc.github.io/dou3d-ts/examples/learningNotes/lesson_10/Shadow.htmlapp
片断着色器中判断当前像素是否处于阴影之中的代码以下:less
float visibility = (shadowCoord.z > depth) ? 0.7 : 1.0;
这么写的话,会出现一条一条的纹路,被称为马赫带,解决办法是给深度加上 0.005 的份量,以下:spa
float visibility = (shadowCoord.z > depth + 0.005) ? 0.7 : 1.0;
通常来讲模拟平行光时,生成阴影贴图使用可使用正交相机,固然也可使用透视相机来实现距离越近阴影越大的效果;.net
点光源,点光源不一样于平行光,是向全部方向发射光源,因此不能简单的使用平行光的方法来实现,主要的区别在于平行光使用了一个平面贴图,而点光源须要使用一个立方体贴图来实现,具体能够参考:https://blog.csdn.net/jxw167/article/details/574772613d
上面咱们实现了阴影,不过有一个问题,当咱们把光照的位置拉远以后(仅使用透视矩阵生成阴影贴图时),会发现阴影消失了:code
var LIGHT_X = 0, LIGHT_Y = 40, LIGHT_Z = 2;
这是由于,咱们把 gl_FragCoord.z 的深度值存储在只有 8 位的红色份量中致使的,因此距离过远以后,8 位的红色份量就存储不下了,好的方法是全部的份量都用上来存储;htm
修改后的示例以下:https://hammerc.github.io/dou3d-ts/examples/learningNotes/lesson_10/Shadow_highp.html
除了能够投影到平面,阴影也能够投影到任意模型上,好比球体:https://hammerc.github.io/dou3d-ts/examples/learningNotes/lesson_10/Shadow_highp_sphere.html