iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
Modern Web

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

[Day14] 用Babylon.js為3D世界加上環景背景(Feature - 單元五)

  • 分享至 

  • xImage
  •  

Feature單元五 A Better Environment:加上環景背景布幕

這次要來玩的是環境,在3D中一個可以利用黑白圖快速生成地形的方式。白色式高點, 黑色是低點,灰階是介於兩者的高度。這種流行的方式提供了一種簡單且高效的方法來創建複雜的、有機的地形,例如山脈、山谷、丘陵或不平整的地面。不需要手動去調整每一個頂點,只需要編輯一張圖片即可。Unity, Unreal Engine, Blender都會使用這樣的概念,而Babylon.js也可以這樣做。

比方說今天我們有這樣的一張圖:

利用CreateGroundFromHeightMap 這個方法把圖丟進去,就能得到下方有高低起伏的地形:

const largeGround = BABYLON.MeshBuilder.CreateGroundFromHeightMap("largeGround", "https://assets.babylonjs.com/environments/villageheightmap.png" /* url to height map */,
    {width:150, height:150, subdivisions: 20, minHeight:0, maxHeight: 10});

再加上草地的材質,就會得到一張有高低起伏的地形圖了

    const largeGroundMat = new BABYLON.StandardMaterial("largeGroundMat");
    largeGroundMat.diffuseTexture = new BABYLON.Texture("https://assets.babylonjs.com/environments/valleygrass.png");   
    largeGround.material = largeGroundMat;

playground 的樣子:https://playground.babylonjs.com/#KBS9I5#40 

地形有了,來加點像一點的天空

想要在3D環境加上天空稱之為天空盒(Skybox),Skybox 的概念很簡單,它是一個巨大的立方體或球體,包圍整個 3D 場景。這個立方體的內壁貼上了六張紋理圖片,每張圖片對應一個方向(上、下、前、後、左、右)。當你在場景中移動攝影機時,這個 Skybox 始終保持在最遠的位置,而且它的渲染方式經過特殊優化,即使攝影機旋轉,它看起來也像是無限遠處的環境但因為有了這個背景,看起來不會像是懸浮在一個空洞的空間裡。

本次範例中使用的六面立方體貼圖是最傳統的方法,需要準備六張分別代表天空盒不同方向的圖片。//

// 建立一個 Skybox 的網格(一個沒有光照、沒有深度測試的立方體)
const skybox = BABYLON.MeshBuilder.CreateBox("skyBox", {size:150}, scene);

// 建立一個立方體紋理(CubeTexture),並指定六張圖片的路徑
// 這些圖片需要遵循特定的命名格式:_px, _nx, _py, _ny, _pz, _nz
const skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
skyboxMaterial.backFaceCulling = false;
skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("textures/skybox", scene);
skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
skybox.material = skyboxMaterial; // 將材質應用到 Skybox 網格上

補充比較現代的天空盒方法:HDRCubeTexture

需要一張 HDR 格式的全景圖,用於需要基於物理的渲染(PBR)和真實光照的場景,更適合WebXR。

它的資料來源通常是一張球形投影的全景圖,但引擎會將這張全景圖的資料,高效地重新投影並渲染到一個立方體紋理(Cube Map)的六個面上。還會生成多層級的紋理提供準確的反射和環境光照。最後仍會以「立方體」的紋理形式被使用和渲染。

// 建立一個天空盒,並載入 HDR 全景圖
// 這裡使用了 "textures/environment.env" 這類檔案,它包含了天空盒與光照資訊
const hdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("textures/environment.env", scene);

// 將 HDR 紋理設定為場景的反射紋理
// 這將同時作為天空盒背景,並提供環境光照(IBL)
scene.environmentTexture = hdrTexture;

// 額外設定,可選:調整背景亮度
scene.environmentTexture.gammaSpace = false;

這個單元最後是Sprite 的部分,有了天空跟地板的環境之後,想要加點花草樹木的話,如果放置一整片的模型會很耗效能對吧。因此,有個常用的手法是Sprite ,他是一個永遠面向攝影機的2D 平面圖片。很常應用在環境中的花草樹木、粒子效果(像是煙霧、下雨下雪)、血條或特效等。那種需要渲染大量,但不需要複雜 3D 幾何體的動態 2D 元素時,就很適合用他。

Babylon.js 的SpriteManager 優勢在於它能用single draw call來渲染所有Sprite,所以能有效的處理成千上百的Sprite。因為 GPU 不需要為每個單獨的精靈圖都執行一次繪製指令,所以極大地提高了效能。

Playground 範例中,是怎麼加上這些Sprite樹的呢?

首先,也是最重要的一步,先建一個SpriteManager ,名叫"treesManager”,圖片來源,manager的容納Sprite最大數量,Sprite 尺寸,應用的場景。

const spriteManagerTrees = new BABYLON.SpriteManager("treesManager", "textures/palm.png" /* url to sprite */, 2000, {width: 512, height: 1024}, scene);

給他迴圈去把樹長出來,並且給他個別一片空間的地方隨機長,最後會得到500棵+500棵,總共1000棵:

for (let i = 0; i < 500; i++) {
    const tree = new BABYLON.Sprite("tree", spriteManagerTrees);
    tree.position.x = Math.random() * (-30);
    tree.position.z = Math.random() * 20 + 8;
    tree.position.y = 0.5;
}

for (let i = 0; i < 500; i++) {
    const tree = new BABYLON.Sprite("tree", spriteManagerTrees);
    tree.position.x = Math.random() * (25) + 7;
    tree.position.z = Math.random() * -35  + 8;
    tree.position.y = 0.5;
}

他們看起來都像是一個3D模型,但其實都是一片紙片,高級一點就是有動畫的紙片。這個技巧也可以適時地放在XR的開發中,但要注意盡量避免像是可以由上往下看的物件,或是塞跟其他模型之間太密的地方等,因為XR的鏡頭是自由的,所以就要考量各種會因為視角轉移而破圖的狀況。

下一篇來看看,當需要生動的粒子效果的話該怎麼做呢?


上一篇
[Day13] 避免碰撞v.s配上Babylon.js物理引擎的碰撞與重力效果(Feature - 單元四)
下一篇
[Day15] 用Babylon.js灑點粒子做出噴泉和火焰(Feature - 單元六)
系列文
WebXR未來新視界:Babylon.js打造Web的VR/AR/XR體驗15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言