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