BabylonJS - 網格



在本章中,我們將學習如何使用網格構建器建立不同的形狀。我們已經在之前的章節中學習瞭如何建立形狀。

不同之處在於,使用網格構建器可以靈活地為形狀新增顏色和影像。

使用 MeshBuilder 建立立方體

現在讓我們看看如何使用 MeshBuilder 建立立方體。

演示

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Element-Creating Scene</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0, 0, 1);
            
            var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true);

            var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
            light.intensity = 0.7;

            var pl = new BABYLON.PointLight("pl", BABYLON.Vector3.Zero(), scene);
            pl.diffuse = new BABYLON.Color3(1, 1, 1);
            pl.specular = new BABYLON.Color3(1, 1, 1);
            pl.intensity = 0.8;

            var mat = new BABYLON.StandardMaterial("mat1", scene);
            mat.alpha = 1.0;
            mat.diffuseColor = new BABYLON.Color3(0, 1, 0);
            
            var texture = new BABYLON.Texture("images/cube.png", scene);
            mat.diffuseTexture = texture;

            var hSpriteNb =  3;  // 3 sprites per raw
            var vSpriteNb =  2;  // 2 sprite raws

            var faceUV = new Array(6);
            for (var i = 0; i < 6; i++) {
               faceUV[i] = new BABYLON.Vector4(i/hSpriteNb, i/vSpriteNb, (i+1)/hSpriteNb, (i+1)/vSpriteNb);
            }

            var options = {
               width: 1.5,
               height: 1.5,
               depth: 1.5,
               faceUV: faceUV
            };

            var box = BABYLON.MeshBuilder.CreateBox("box", options, scene);
            box.material = mat;

            scene.registerBeforeRender(function() { 
               pl.position = camera.position;
            });
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

以上程式碼行生成以下輸出:

MeshBuilder CubeBox

對於上面的示例,我們使用瞭如下所示的精靈影像。它水平方向有 3 列,垂直方向有 2 行。

Cube

在這個演示中,我們使用了名為 cube.png 的影像。這些影像儲存在本地 images/ 資料夾中,並在下面貼上以供參考。請注意,cube.png 是一個精靈影像,精靈影像是影像的集合。我們想在立方體上顯示影像,因此需要將立方體的所有面放在一起。您也可以下載您選擇的類似精靈影像,並在演示連結中使用。

createBox 構建器為您提供了尺寸選項。

例如:

var box = BABYLON.MeshBuilder.CreateBox("box", options, scene);

演示

var hSpriteNb =  3;  // 3 sprites per raw ie colums horizontally as shown in the image

var vSpriteNb =  2;  // 2 sprite raws as shown in the image above.

var faceUV = new Array(6); // the cube has 6 sides so creating array for same.
for (var i = 0; i < 6; i++) {
   faceUV[i] = new BABYLON.Vector4(i/hSpriteNb, i/vSpriteNb, (i+1)/hSpriteNb, (i+1)/vSpriteNb);
}

var options = {
   width: 1.5,
   height: 1.5,
   depth: 1.5,
   faceUV: faceUV
};

這稱為使用 createBox 方法將紋理應用於網格構建器。我們使用了名為cube.png的影像,它水平方向有 3 列,垂直方向有 2 行。立方體或盒子有 6 個面。

要應用紋理,我們使用 options 引數。例如:

Var box = BABYLON.MeshBuilder.CreateBox ('box', options, scene);

我們定義了一個名為 faceUV 的陣列,大小為 6,也就是立方體的面數。此陣列將始終包含 Vector4 元素。每個 Vector4(x, y, z, w) 將按如下方式定義:

  • x = Ubottom
  • y = Vbottom
  • z = Utop
  • w = Vtop

這些向量在 [0, 1] 範圍內。Ubottom 和 Vbottom 是紋理裁剪開始的左下角點的二維座標。Utop、Vtop 是紋理裁剪結束的右上角點。

var hSpriteNb =  3;  // 3 sprites per raw
var vSpriteNb =  2;  // 2 sprite raws

var faceUV = new Array(6);
for (var i = 0; i < 6; i++) {
   faceUV[i] = new BABYLON.Vector4(i/hSpriteNb, i/vSpriteNb, (i+1)/hSpriteNb, (i+1)/vSpriteNb);
}

假設預設紋理(即給定的影像)應用於盒子的所有面。如果您只想更改盒子的一個面或一個邊,您可以直接分配值,如下所示:

var hSpriteNb =  3;  // 3 sprites per raw
var vSpriteNb =  2;  // 2 sprite raws

var faceUV = new Array(6);
faceUV[4] = new BABYLON.Vector4(0, 0, 1/hSpriteNb, 1/vSpriteNb);

示例

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Element-Creating Scene</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>
   
   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0, 0, 1);
            
            var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true);

            var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
            light.intensity = 0.7;

            var pl = new BABYLON.PointLight("pl", BABYLON.Vector3.Zero(), scene);
            pl.diffuse = new BABYLON.Color3(1, 1, 1);
            pl.specular = new BABYLON.Color3(1, 1, 1);
            pl.intensity = 0.8;

            var mat = new BABYLON.StandardMaterial("mat1", scene);
            mat.alpha = 1.0;
            mat.diffuseColor = new BABYLON.Color3(0.8, 0.8, 0.8);
            
            var texture = new BABYLON.Texture("images/3d.png", scene);
            mat.diffuseTexture = texture;

            var hSpriteNb =  3;  // 3 sprites per raw
            var vSpriteNb =  2;  // 2 sprite raws

            var faceUV = new Array(6);
            faceUV[4] = new BABYLON.Vector4(0, 0, 1/hSpriteNb, 1/vSpriteNb);

            var options = {
               width:3,
               height:3,
               depth: 3,
               faceUV:faceUV
            };

            var box = BABYLON.MeshBuilder.CreateBox("box", options, scene);
            box.material = mat;

            scene.registerBeforeRender(function() { 
               pl.position = camera.position;
            });
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

以上程式碼行生成以下輸出:

Textturepahse4

在這個演示中,我們使用了名為 3d.png 的影像。這些影像儲存在本地 images/ 資料夾中,並在下面貼上以供參考。請注意,3d.png 是一個精靈影像;精靈影像是影像的集合。我們想在立方體上顯示影像,並且將立方體的所有面放在一起。您也可以下載您選擇的類似精靈影像,並在演示連結中使用。

用於盒子的紋理 - images/3d.png

3d

MeshCylinder(圓柱體網格)

在本節中,我們將瞭解如何建立 MeshCylinder(圓柱體網格)。

要建立 MeshCylinder(圓柱體網格),您需要使用 BABYLON.MeshBuilder.CreateCylinder 類。

該類的引數如下:

var meshcylinder = BABYLON.MeshBuilder.CreateCylinder("meshcylinder", {
   height: 3,
   diameter: 35,
   tessellation: 52
}, scene);

使用網格和網格構建器建立圓柱體的區別在於:您可以在網格構建器中使用 options。現在我們使用高度、直徑和細分作為要傳遞給圓柱體的選項。我們使用帶有線框的標準材質作為此網格的材質。檢查瀏覽器中的輸出並檢視圓柱體。您可以在遊戲中使用類似的結構作為場景中旋轉的車輪。

演示

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>Babylon.js demo - Mesh Builder</title>
      <script src = "babylon.js"></script>
      <style>
         html,body,canvas { margin: 0; padding: 0; width: 100%; height: 100%; font-size: 0; }
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0.8, 0.8, 0.8);
            
            var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 6, 1.3, 40, new BABYLON.Vector3(0, -3, 0), scene);
            
            var light = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);

            var mat = new BABYLON.StandardMaterial("mat", scene);
            mat.diffuseColor = new BABYLON.Color3(0.1, .5, 0);
            mat.specularColor = new BABYLON.Color3(0, 0, 0);
            mat.wireframe = true;

            var meshcylinder = BABYLON.MeshBuilder.CreateCylinder("meshcylinder", {
               height: 3,
               diameter: 35,
               tessellation: 52
            }, scene);

            meshcylinder.material = mat;
            meshcylinder.position = new BABYLON.Vector3(0, 0, 0);

            scene.activeCamera.attachControl(canvas);
            return scene;
         };
         
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

以上程式碼行生成以下輸出:

Meshcylinder

現在,許多使用網格構建器建立的形狀將一起在一個演示中使用。下面演示連結中介紹的形狀列在後續部分中。

BabylonJS – 網格相交和點

正如您所知,在遊戲中,當兩個物件相交時需要執行什麼操作,網格相交非常重要。以下演示解釋了當網格相交時需要捕獲的事件。

在下面的演示中,我們涵蓋了以下兩個概念:

  • 網格相交
  • 點相交
<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Element-Creating Scene</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(1, 1, 1);
            
            var camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 1, 0.8, 20, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true);

            var matcone = new BABYLON.StandardMaterial("mat1", scene);
            matcone.alpha = 1.0;
            matcone.diffuseColor = new BABYLON.Color3(0, 0, 0);
            matcone.wireframe = true;

            var cone = BABYLON.MeshBuilder.CreateCylinder("cone", {height : 10, diameterTop: 10,diameterBottom:10, tessellation: 5}, scene);
            cone.position= new BABYLON.Vector3(12,1,0);
            cone.material = matcone;	

            var balloon1 = BABYLON.Mesh.CreateSphere("balloon1",5, 1.0, scene);
            var balloon2 = BABYLON.Mesh.CreateSphere("balloon2", 5, 1.0, scene);
            var balloon3 = BABYLON.Mesh.CreateSphere("balloon3", 5, 1.0, scene);
            
            balloon1.material = new BABYLON.StandardMaterial("matBallon", scene);
            balloon2.material = new BABYLON.StandardMaterial("matBallon", scene);
            balloon3.material = new BABYLON.StandardMaterial("matBallon", scene);

            balloon1.position = new BABYLON.Vector3(4, 2, 0);
            balloon2.position = new BABYLON.Vector3(5, 1, 0);
            balloon3.position = new BABYLON.Vector3(7, 0, 0);

            var pointToIntersect = new BABYLON.Vector3(10, 0, 0);
            var a = 0.01;
            
            scene.registerBeforeRender(function () {
               if (balloon1.intersectsMesh(cone, false)) {
                  balloon1.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
               } else {
                  balloon1.material.emissiveColor = new BABYLON.Color3(0, 1, 0);
               }

               if (balloon2.intersectsMesh(cone, false)) {
                  balloon2.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
               } else {
                  balloon2.material.emissiveColor = new BABYLON.Color3(0, 1, 0);
               }

               if (balloon3.intersectsMesh(cone, false)) {
                  balloon3.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
               } else {
                  balloon3.material.emissiveColor = new BABYLON.Color3(0, 1, 0);
               }

               if (balloon3.intersectsPoint(pointToIntersect)) {
                  balloon3.material.emissiveColor = new BABYLON.Color3(0, 0, 0);
               }

               a += 0.01;
               balloon1.position.x += Math.cos(a) / 10;
               balloon2.position.x += Math.cos(a) / 10;
               balloon3.position.x += Math.cos(a) / 10;
            });
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

以上程式碼生成以下輸出:

Mesh Intersection Point

解釋

使用以上程式碼,我們建立了一個線框為 true 的圓柱體。我們建立了 3 個球體。球體的原始顏色為綠色。

scene.registerBeforeRender函式中,我們將根據與網格(此處為圓柱體)的相交來更改球體的顏色。

考慮registerBeforeRender中的以下程式碼:

if (balloon1.intersectsMesh(cone, false)) {
   balloon1.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
} else {
   balloon1.material.emissiveColor = new BABYLON.Color3(0, 1, 0);
}

intersectsMesh如果與傳遞給它的引數中給出的網格相交,則返回 true 或 false。

例如:

balloon1.intersectsMesh(cone, false); //cone refers to the cylinder mesh here.

如果球體與圓柱體相交,則球體的顏色將變為紅色;否則為綠色。

以下程式碼用於點相交:

var pointToIntersect = new BABYLON.Vector3(10, 0, 0);
if (balloon3.intersectsPoint(pointToIntersect)) {
   balloon3.material.emissiveColor = new BABYLON.Color3(0, 0, 0);
}

這裡,pointtoIntersect變數是位置向量,在 x 軸上為 10。如果球體穿過相交點,則球體的顏色將變為黑色。

BabylonJS – 網格拾取碰撞

拾取碰撞實際上會為您提供座標,您可以將網格放置在該位置。物件由滑鼠拾取,您可以將其放置在滑鼠單擊的位置。假設您需要將網格(物件)放置在使用者單擊滑鼠的位置;因此,藉助拾取碰撞,它可以幫助您獲得單擊位置的座標。

演示

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Element-Creating Scene</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>
   
   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(1, 1, 1);

            // setup environment
            var light0 = new BABYLON.PointLight("Omni", new BABYLON.Vector3(0, 10, 20), scene);
            var freeCamera = new BABYLON.FreeCamera("FreeCamera", new BABYLON.Vector3(0, 0, -30), scene);

            var balloon1 = BABYLON.Mesh.CreateSphere("balloon1",5, 1.0, scene);
            var balloon2 = BABYLON.Mesh.CreateSphere("balloon2", 5, 1.0, scene);
            balloon1.material = new BABYLON.StandardMaterial("matBallon", scene);
            balloon2.material = new BABYLON.StandardMaterial("matBallon", scene);

            balloon1.position = new BABYLON.Vector3(0, 0, -0.1);
            balloon2.position = new BABYLON.Vector3(0, 0, -0.1);
            balloon1.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
            balloon2.material.emissiveColor = new BABYLON.Color3(0, 0, 1);

            //Wall
            var wall = BABYLON.Mesh.CreatePlane("wall", 30.0, scene);
            wall.material = new BABYLON.StandardMaterial("wallMat", scene);
            wall.material.emissiveColor = new BABYLON.Color3(0.5, 1, 0.5);

            //When pointer down event is raised

            scene.onPointerDown = function (evt, pickResult) {
               // if the click hits the ground object, we change the impact position
               if (pickResult.hit) {
                  var dateValue = new Date();
                  var secondNumber = dateValue.getSeconds();
                  if (secondNumber % 2 == 0) {
                  balloon1.position.x = pickResult.pickedPoint.x;
                  balloon1.position.y = pickResult.pickedPoint.y;
                  } else {
                     balloon2.position.x = pickResult.pickedPoint.x;
                     balloon2.position.y = pickResult.pickedPoint.y;
                  }
               }
            };
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

Picking collision

解釋

在上面的示例中,我們使用了平面和 2 個球體。要生成此輸出,請使用以下程式碼:

scene.onPointerDown = function (evt, pickResult) {
   // if the click hits the ground object, we change the impact position
   if (pickResult.hit) {
      var dateValue = new Date();
      var secondNumber = dateValue.getSeconds();
      if (secondNumber % 2 == 0) {
      balloon1.position.x = pickResult.pickedPoint.x;
      balloon1.position.y = pickResult.pickedPoint.y;
      } else {
         balloon2.position.x = pickResult.pickedPoint.x;
         balloon2.position.y = pickResult.pickedPoint.y;
      }
   }
};

scene.onPointerDown事件為您提供座標 -x、y 和 z,在我們的示例中為pickResult

如果單擊地面網格,則它會將 pickResult.hit 設為 true。我們考慮奇數/偶數秒,並將球體的座標更改為 pickResult z 和 y 座標,如上所示。更改位置後,球體將放置在您單擊和放置滑鼠的位置。您可以嘗試上面的演示來實現相同的效果。

BabylonJS – 光線投射

光線投射就像太陽的光線,用於檢查場景中的碰撞和相交。

語法

var ray = new BABYLON.Ray(origin, direction, length);

引數

考慮光線投射的以下引數:

  • 起點 - 光線開始的位置。

  • 方向 - 光線的方向計算如下:

var forward = new BABYLON.Vector3(0,0,1);		
forward = vecToLocal(forward, box);
var direction = forward.subtract(origin);

然後,要獲得方向,我們從起點(盒子位置)減去它:

  • 長度 - 光線的長度。

演示

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Element-Creating Scene</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);

            var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(0, 100, 100), scene);
            
            var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0.8, 100, new BABYLON.Vector3.Zero(), scene);
            camera.attachControl(canvas, true);

            var ground = BABYLON.Mesh.CreateGround("ground", 500, 500, 10, scene);

            var box = BABYLON.Mesh.CreateBox("box", 4.0, scene);
            box.position.y = 2;
            box.scaling.z = 2;
           
            var matBox = new BABYLON.StandardMaterial("matBox", scene);
            matBox.diffuseColor = new BABYLON.Color3(0.8, 0.1, 0.5);
            box.material = matBox;
            box.isPickable = false; 

            var box2 = BABYLON.Mesh.CreateBox("box2", 8.0, scene);
            box2.position = new BABYLON.Vector3(-20, 4, 0); 
            
            var matBox2 = new BABYLON.StandardMaterial("matBox2", scene);
            matBox2.diffuseColor = new BABYLON.Color3(1, 0, 0);
            box2.material = matBox2;

            var box3 = BABYLON.Mesh.CreateBox("box3", 8.0, scene);
            box3.position = new BABYLON.Vector3(20, 4, 0); 
            
            var matBox3 = new BABYLON.StandardMaterial("matBox3", scene);
            matBox3.diffuseColor = new BABYLON.Color3(1, 0, 0);
            box3.material = matBox3;

            var box4 = BABYLON.Mesh.CreateBox("box4", 8.0, scene);
            box4.position = new BABYLON.Vector3(0, 0, 20); 
            
            var matBox4 = new BABYLON.StandardMaterial("matBox4", scene);
            matBox4.diffuseColor = new BABYLON.Color3(0, 1, 0);
            box4.material = matBox4;

            var box5 = BABYLON.Mesh.CreateBox("box5", 8.0, scene);
            box5.position = new BABYLON.Vector3(0, 0, -20); 
            
            var matBox5 = new BABYLON.StandardMaterial("matBox5", scene);
            matBox5.diffuseColor = new BABYLON.Color3(0, 1, 0);
            box5.material = matBox5;

            function mousemovef() {
               var pickResult = scene.pick(scene.pointerX, scene.pointerY);

               if (pickResult.hit) {
                  var diffX = pickResult.pickedPoint.x - box.position.x;
                  var diffY = pickResult.pickedPoint.z - box.position.z;
                  box.rotation.y = Math.atan2(diffX,diffY);			
               }	
            }

            scene.onPointerMove = function () {
               mousemovef();
            };

            function vecToLocal(vector, mesh) {
               var m = mesh.getWorldMatrix();
               var v = BABYLON.Vector3.TransformCoordinates(vector, m);
               return v;		
            }   

            scene.registerBeforeRender(function () {
               var origin = box.position;

               var forward = new BABYLON.Vector3(0,0,1);		
               forward = vecToLocal(forward, box);

               var direction = forward.subtract(origin);
               direction = BABYLON.Vector3.Normalize(direction);

               var length = 100;

               var ray = new BABYLON.Ray(origin, direction, length);
               // ray.show(scene, new BABYLON.Color3(1, 1, 0.1));

               var hit = scene.pickWithRay(ray);

               if (hit.pickedMesh) {
                  hit.pickedMesh.scaling.y  += 0.01;
               }
            });		
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

以上程式碼行生成以下輸出:

Raycast

解釋

中心有一個主盒子充當光線投射。一旦它指向任何盒子,盒子的尺寸就會增加。在玩遊戲時,這個概念非常有用,因為它可以知道哪些其他物體正在接觸,並且可以採取必要的措施。

新增box.isPickable = false;以便不考慮中心的中央盒子。如果您不希望任何物件包含在光線接觸中,請向其新增box.isPickable = false;

以下程式碼添加了被光線拾取的盒子的縮放。

scene.registerBeforeRender(function () {
   var origin = box.position;	
   var forward = new BABYLON.Vector3(0,0,1);		
   forward = vecToLocal(forward, box);

   var direction = forward.subtract(origin);
   direction = BABYLON.Vector3.Normalize(direction);

   var length = 100;

   var ray = new BABYLON.Ray(origin, direction, length);

   var hit = scene.pickWithRay(ray);

   if (hit.pickedMesh) {
      hit.pickedMesh.scaling.y  += 0.01;
   }
});	

var ray = new BABYLON.Ray(origin, direction, length);建立一個光線,它將主盒子的位置作為起點。

光線的方向計算如下:

var forward = new BABYLON.Vector3(0,0,1);		
forward = vecToLocal(forward, box);
var direction = forward.subtract(origin);

然後,要獲得方向,我們從起點(盒子的位置)減去它。vecToLocal函式旨在透過將向量乘以網格矩陣來轉換從網格角度來看的位置。

我們使用var hit = scene.pickWithRay(ray);從光線中獲取命中點。

它給出光線與網格重合的位置。

透過執行以下程式碼行,將縮放應用於被拾取的網格:

if (hit.pickedMesh) {
   hit.pickedMesh.scaling.y  += 0.01;
}

在瀏覽器中嘗試以上示例以檢視輸出。

帶有謂詞函式的光線投射

現在讓我們看看帶有謂詞函式的光線投射是如何工作的以及光線輔助工具顯示的方向。

演示

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Element-Creating Scene</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>
   
   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);

            var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(0, 100, 100), scene);
            var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0.8, 100, new BABYLON.Vector3.Zero(), scene);
            camera.attachControl(canvas, true);

            var ground = BABYLON.Mesh.CreateGround("ground", 500, 500, 10, scene);

            var box = BABYLON.Mesh.CreateBox("box", 4.0, scene);
            box.position.y = 2;
            box.scaling.z = 2;
            var matBox = new BABYLON.StandardMaterial("matBox", scene);
            matBox.diffuseColor = new BABYLON.Color3(0.8, 0.1, 0.5);
            box.material = matBox;
            box.isPickable = false; 

            var box2 = BABYLON.Mesh.CreateBox("box2", 8.0, scene);
            box2.position = new BABYLON.Vector3(-20, 4, 0); 
            var matBox2 = new BABYLON.StandardMaterial("matBox2", scene);
            matBox2.diffuseColor = new BABYLON.Color3(1, 0, 0);
            box2.material = matBox2;

            var box3 = BABYLON.Mesh.CreateBox("box3", 8.0, scene);
            box3.position = new BABYLON.Vector3(20, 4, 0); 
            var matBox3 = new BABYLON.StandardMaterial("matBox3", scene);
            matBox3.diffuseColor = new BABYLON.Color3(1, 0, 0);
            box3.material = matBox3;

            var box4 = BABYLON.Mesh.CreateBox("box4", 8.0, scene);
            box4.position = new BABYLON.Vector3(0, 0, 20); 
            var matBox4 = new BABYLON.StandardMaterial("matBox4", scene);
            matBox4.diffuseColor = new BABYLON.Color3(0, 1, 0);
            box4.material = matBox4;

            var box5 = BABYLON.Mesh.CreateBox("box5", 8.0, scene);
            box5.position = new BABYLON.Vector3(0, 0, -20); 
            var matBox5 = new BABYLON.StandardMaterial("matBox5", scene);
            matBox5.diffuseColor = new BABYLON.Color3(0, 1, 0);
            box5.material = matBox5;

            //ray showing the direction
            var ray = new BABYLON.Ray();
            var rayHelper = new BABYLON.RayHelper(ray);

            var localMeshDirection = new BABYLON.Vector3(0, 0, -1);
            var localMeshOrigin = new BABYLON.Vector3(0, 0, -.4);
            var length = 10;

            rayHelper.attachToMesh(box, localMeshDirection, localMeshOrigin, length);
            rayHelper.show(scene);

            function mousemovef() {
               var pickResult = scene.pick(scene.pointerX, scene.pointerY);

               if (pickResult.hit) {
                  var diffX = pickResult.pickedPoint.x - box.position.x;
                  var diffY = pickResult.pickedPoint.z - box.position.z;
                  box.rotation.y = Math.atan2(diffX,diffY);			
               }	
            }

            scene.onPointerMove = function () {
               mousemovef();
            };

            function vecToLocal(vector, mesh) {
               var m = mesh.getWorldMatrix();
               var v = BABYLON.Vector3.TransformCoordinates(vector, m);
               return v;		
            }   

            scene.registerBeforeRender(function () {
               var origin = box.position;
               function predicate(mesh) {
                  if (mesh == box2 || mesh == box || mesh == box5) {
                     return false;
                  }
                  return true;
               }
               
               var forward = new BABYLON.Vector3(0,0,1);		
               forward = vecToLocal(forward, box);

               var direction = forward.subtract(origin);
               direction = BABYLON.Vector3.Normalize(direction);

               var length = 100;

               var ray = new BABYLON.Ray(origin, direction, length);
               // ray.show(scene, new BABYLON.Color3(1, 1, 0.1));

               var hit = scene.pickWithRay(ray, predicate);
               if (hit.pickedMesh) {
                  hit.pickedMesh.scaling.y  += 0.01;
               }
            });		
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

以上程式碼行生成以下輸出:

Raycast Predicate

解釋

帶有謂詞函式的光線投射有助於選擇我們想要的網格。如果我們不希望拾取網格,我們可以忽略它。

function predicate(mesh) {
   if (mesh == box2 || mesh == box || mesh == box5) {
      return false;
   }
   return true;
}

上述函式給出光線選擇的網格。如果選擇的網格是 box2、box 或 box5,則返回 false;否則返回 true。

您可以嘗試以上示例來實現相同的效果。

BabylonJS – 網格陰影

陰影根據光線照射到建立的網格的方式進行渲染。它們在使三維世界中的輸出看起來更逼真方面發揮著重要作用。

現在讓我們學習如何使用 babylonjs 建立陰影。

語法

var shadowGenerator00 = new BABYLON.ShadowGenerator(shadowsize, light);

引數

考慮以下與網格陰影相關的引數:

  • 陰影大小 - 陰影的大小。

  • 光照 - 場景中使用的光照。

演示

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Element-Creating Scene</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(1, 1, 1);	
            var camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 1, 0.8, 20, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true);
            // light1
            var light = new BABYLON.DirectionalLight("dir01", new BABYLON.Vector3(-1, -2, -1), scene);
            light.position = new BABYLON.Vector3(20, 40, 20);

            var ground01 = BABYLON.Mesh.CreateGround("Spotlight Hard Shadows", 24, 60, 1, scene, false);
            var groundMaterial = new BABYLON.StandardMaterial("ground", scene);
            groundMaterial.diffuseTexture = new BABYLON.Texture("images/gr1.jpg", scene);
            groundMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
            groundMaterial.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2);

            ground01.material = groundMaterial;
            ground01.receiveShadows = true;
            ground01.position.x = -5;

            var box = BABYLON.Mesh.CreateBox("box", 3.0, scene);
            box.position.x = -5;
            box.position.y = 5;
            var shadowGenerator00 = new BABYLON.ShadowGenerator(512, light);
            shadowGenerator00.getShadowMap().renderList.push(box);
            //shadowGenerator00.usePoissonSampling = true;
            //shadowGenerator00.useExponentialShadowMap = true;
            shadowGenerator00.useBlurExponentialShadowMap = true;
            shadowGenerator00.bias = 0.01;
            scene.registerBeforeRender(function() {
               box.rotation.x += 0.01;
               box.rotation.x += 0.01;
            });
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

以上程式碼行生成以下輸出:

Shadows

解釋

要建立陰影,您需要建立 shadowgenerator。請考慮以下示例。

var shadowGenerator00 = new BABYLON.ShadowGenerator(512, light);

要定義需要陰影的網格,您需要將其新增到上面的生成器。

shadowGenerator00.getShadowMap().renderList.push(box);

現在,我們建立了一個地面和一個放在上面的盒子。我們希望盒子的陰影落在地面上。為此,我們需要確保地面被標記為接收陰影,方法如下:

ground01.receiveShadows = true;

有一些可用於陰影的過濾器,如下所示:

shadowGenerator.usePoissonSampling = true; - Called Poisson sampling 
shadowGenerator.useExponentialShadowMap = true; - Exponential Shadow Map
shadowGenerator.useBlurExponentialShadowMap= true;  - Blur Exponential Shadow Map

在我們的演示中,我們使用了 shadowGenerator00.useBlurExponentialShadowMap = true; 您可以嘗試其他方法,並檢視輸出的外觀。

這裡,我們使用了名為 gr1.jpg 的影像。這些影像儲存在本地 images/ 資料夾中。您可以下載您選擇的任何影像,並在演示連結中使用。

BabylonJS – 網格上的高階紋理

在本節中,我們將學習有關網格上高階紋理的知識。不同的紋理如下所示:

讓我們將一些複雜的紋理應用於網格 - 映象、凹凸、影片和折射。

序號 網格和說明
1 網格高亮層

高亮層用於突出顯示場景中的網格。您可以為其指定顏色,顏色將應用於網格的邊框。如果您想在遊戲中突出顯示,可以使用網格高亮層來實現。

2 變形網格

變形透過某種轉換方式將一個物體的形狀更改為另一個物體。我們已經看到了形狀的可更新引數;否則該引數設定為 false。對於變形,它設定為 true,並且網格會更新以更改形狀。

3 網格操作

操作用於向網格新增互動。當您單擊網格時,或者當網格相交或碰撞時,事件就會被啟用。

4 網格 AssetsManager

使用 assestsmanager 類,您可以在場景中載入網格、影像和二進位制檔案。

5 匯入網格

我們將學習如何使用匯入網格。

6 網格變形目標

我們已經看到了線條、帶狀物、多邊形等的變形。現在,我們將在演示中看到球體和盒子的變形。使用變形目標,球體的形狀會發生變化,這在下面的演示中可以看到。

7 網格例項

如果您想在場景中繪製相同的網格,請使用例項。

8 網格 LOD 和例項

LOD 代表視距(線)。此功能允許您根據觀察者的距離指定網格。隨著觀察者到物體的距離增加,使用 LOD 可以清晰地顯示網格的細節級別。

9 網格體積光散射後期處理

此過程會散射光線,如下面的輸出所示。在瀏覽器中測試一下,您將看到光線如何穿過網格。

10 網格邊緣渲染器

邊緣渲染用於繪製網格周圍的邊緣,如上圖所示。

11 網格混合模式

您可以透過修改材質的 alphamode 來建立混合模式。

12 網格實體粒子

實體粒子系統在網格上更新。我們在網格上看到的所有屬性都可以在實體粒子上使用。

13 網格面數據

面數據佔用大量記憶體,此功能預設情況下未啟用。要啟用它,我們需要根據需要建立網格並向其更新面數據。

廣告
© . All rights reserved.