iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Modern Web

WebXR未來新視界:Babylon.js打造Web的VR/AR/XR體驗系列 第 16

[Day16] 不同的光源和長出影子(Feature - 單元七)

  • 分享至 

  • xImage
  •  

Feature單元六 Light the Night:把場景從白天轉換為黑夜

我們在[Day08] 透過Babylon.js的playground 瞭解構築3D 世界的基礎元素和常用種類有提到燈光有四種:

燈光類型 比喻 Babylon.js 類別 主要用途
半球光 環境光/天空光 BABYLON.HemisphericLight 基礎環境光,提亮場景
平行光 太陽光 BABYLON.DirectionalLight 模擬太陽光,產生平行陰影
點光源 燈泡 BABYLON.PointLight 模擬燈泡、火焰等點狀光源
聚光燈 手電筒 BABYLON.SpotLight 模擬手電筒、舞台燈等聚焦光源

https://ithelp.ithome.com.tw/upload/images/20250926/20103990YbG4WMDqry.png

一般時候最常使用半球光也就是環境光,他是計算成本非常低的光源,從一個半球形的空間發出的光,很均勻的照亮場景中的物體,同時為物體頂部跟底部(從地板反射的光),提供光照亮他的顏色。

而這次Feature的單元會是介紹另外三種光源。首先是聚光燈,聚光燈是向一個特定方向發射一個圓錐形的光束,以下是先宣告一個聚光燈並指定成黃色:

const lampLight = new BABYLON.SpotLight("name", position, direction, angle_of_spread, speed_of_disipation);
lampLight.diffuse = BABYLON.Color3.Yellow();

以下這邊範例又用一個有趣的方式來畫模型了,畫出路燈的柱子,ExtrudeShape 的原理是將一個 2D 的形狀 (shape) 沿著一個 3D 路徑 (path) 進行擠出,形成一個立體物件,所以這邊是畫出一個圓形(形狀) 沿著路徑畫出一根路燈:

// 形狀
const lampShape = [];
    for(let i = 0; i < 20; i++) {
        lampShape.push(new BABYLON.Vector3(Math.cos(i * Math.PI / 10), Math.sin(i * Math.PI / 10), 0));
    }
lampShape.push(lampShape[0]); //close shape

// 路徑
const lampPath = [];
lampPath.push(new BABYLON.Vector3(0, 0, 0));
lampPath.push(new BABYLON.Vector3(0, 10, 0));
for(let i = 0; i < 20; i++) {
    lampPath.push(new BABYLON.Vector3(1 + Math.cos(Math.PI - i * Math.PI / 40), 10 + Math.sin(Math.PI - i * Math.PI / 40), 0));
}
lampPath.push(new BABYLON.Vector3(3, 11, 0));

const lamp = BABYLON.MeshBuilder.ExtrudeShape("lamp", {cap: BABYLON.Mesh.CAP_END, shape: lampShape, path: lampPath, scale: 0.5});

接著才開始做燈泡,並以bulb.parent = lamp; 綁在剛剛做的燈桿上。接著同時透過lampLight.parent = lamp; 把一開始我們宣告的聚光燈綁在這個燈泡上:

    const bulb = BABYLON.MeshBuilder.CreateSphere("bulb", {diameterX: 1.5, diameterZ: 0.8});
    bulb.material = yellowMat;
    bulb.parent = lamp;
    bulb.position.x = 2;
    bulb.position.y = 10.5;

    lampLight.parent = bulb;

https://ithelp.ithome.com.tw/upload/images/20250926/201039906w85PV5hKo.png

在playground上可以看到路燈的效果,如果把light.intensity = 0.5 改成0可以更明顯的看到聚光燈的效果。

若將宣告lampLight 的那行換成底下這個就會是點光源的效果:

const lampLight = new BABYLON.PointLight("lampLight", BABYLON.Vector3.Zero(), scene);

生成影子

接著範例中演示的是透過使用平行光來製造影子,由於宣告平行光的方法跟上面的類似,所以這邊著重在影子的生成。

只有定向光源 (DirectionalLight)、點光源 (PointLight) 和聚光燈 (SpotLight) 可以生成陰影。

簡易的生成影子的方式是用BABYLON.ShadowGenerator ,參數是陰影圖的解析度大小指定哪一個光要去產生陰影,解析度越高,陰影越銳利,但效能成本也越高:

const shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
shadowGenerator.addShadowCaster(myMesh); // 讓 myMesh 投射來自 light 的陰影
// 要在哪裡生成影子 這邊是讓地板生成影子
ground.receiveShadows = true;

由於陰影會是由光影計算而來 N個光源生成陰影 = 場景渲染 N次 + 額外的陰影貼圖計算。可以透過Light Baking優化效能,這能在開發階段就將陰影預先算好。缺點是這只能適用於在環境中靜態的物體,不包含可以玩家或可移動的物體,並且因為事先計算所以會花比較久的時間,檔案也會大很多,這也是需要權衡的地方。在XR中用到陰影的地方可能相對較少,也許大多就是因為效能的考量。

我們完成了基礎的3D世界教學了!Feature中的最後一個單元是關於攝影機的。
然而XR中的攝影機幾乎都是根據玩家就是攝影機本身,幾乎都會使用XR的設置,所以接下們來看要怎麼進入XR 世界啦!


上一篇
[Day15] 用Babylon.js灑點粒子做出噴泉和火焰(Feature - 單元六)
下一篇
[Day17] 用網頁就能看Babylon.js的XR範例Demo - 傳送門
系列文
WebXR未來新視界:Babylon.js打造Web的VR/AR/XR體驗17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言