WebGL實踐之半透陰影

netcy發表於2022-07-11

楔子

相信很多人都知道,通過ShadowMap可以產生陰影,通過渲染陰影可以增加場景渲染的對比度,增加渲染的真實效果。 如下圖所示:

image.png

但是對於透明或者半透明的物件,WebGL在處理陰影效果的時候,會把他當成一個不透明的物件來處理,這也渲染的陰影效果就顯得很假。 比如下面樹得陰影效果:

image.png

真實物理得效果中,樹可能會有一些透光得間歇,所以陰影一般都不是一整塊得效果。而是有些透光得亮點,如下圖所示:

image.png

場景中,多家一些樹,這種對比會更加明細,如下面兩幅圖所示,前面一個是整片陰影,後面一個是有半透陰影得效果:

整片陰影

有間歇得陰影

半透陰影效果原來

實現半透陰影,可以通過透明度測試(alphaTest)功能來實現。一般來說,一張半透明得圖片中,一部分地方是很透明得,opacity接近與零,我們希望在opacity小於某個值得時候,不生成陰影,可以通過alphaTest,把小於閾值得片元在生成陰影貼圖的時候丟棄掉,自然就不會生成陰影。 所以流程大致如此:

  • 繪製陰影貼圖的時候,生成一個深度材質,設定深度材質alpahTest(=[閾值])和map,map是原本材質的貼圖。 如果原本材質有alphaMap,也需要考慮在深度材質上面加上alphaMap。
  • 正常繪製場景流程。

threejs 實踐

通過three 實踐,首先在材質上面增加要給屬性shadowAlphaTest,通過shadowAlphaTest動態指定繪製陰影時候的alphaTest,如下所示:

  this.shadowAlphaTest = undefined;

在生成深度材質的地方,如下修改:

result.alphaTest =  material.shadowAlphaTest || material.alphaTest;
result.map = material.map;
result.alphaMap = material.alphaMap;

然後再繪製的時候,可以動態修改shadowAlphaTest的值,來達到控制半透陰影的效果,如下所示:

child.material.transparent = true;
child.material.opacity = 1.0;
child.material.shadowAlphaTest = 0.5;

最終的效果如下所示:

animate.gif

結語

如果有疑問,關注公號“ITMan彪叔” 可以新增作者微信進行交流,及時收到更多有價值的文章。

相關文章