BabylonJS - 物理引擎



Babylon.js 有一個物理引擎外掛系統,有助於向場景新增互動。它顯示了兩個物體之間的碰撞和反彈,使其更像真實的互動。演示將顯示球體彼此碰撞並圍繞碰撞移動,然後靜止。我們在臺球等遊戲中注意到同樣的行為,玩家用球杆擊球,球與其他球碰撞等等。在這裡,物理引擎試圖給出一個真實的球體碰撞和反彈(當它們撞擊地面時)的檢視。該引擎具有類和API,有助於應用衝量、力、改變速度、在需要時呼叫的回撥函式,以及當我們需要在網格與其他網格碰撞時執行某些操作時。

可以使用3個物理外掛:

  • Cannon.js
  • Oimo.js
  • Energy.js

演示

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Ball/Ground Demo</title>
      <script type = "text/javascript" src="https://cdn.babylonjs.com/Oimo.js"></script>
      <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 v3 = BABYLON.Vector3;
         
         var createScene = function () {	
            // This creates a basic Babylon Scene object (non-mesh)
            var scene = new BABYLON.Scene(engine);

            var camera = new BABYLON.ArcRotateCamera("Camera", 0.86, 1.37, 250, BABYLON.Vector3.Zero(), scene);
            
            camera.attachControl(canvas);
            camera.maxZ = 5000;
            camera.lowerRadiusLimit = 120;
            camera.upperRadiusLimit = 430;
            camera.lowerBetaLimit =0.75;
            camera.upperBetaLimit =1.58 ;

            new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);

            var randomNumber = function (min, max) {
               if (min == max) {
                  return (min);
               }
               var random = Math.random();
               return ((random * (max - min)) + min);
            };

            var mat = new BABYLON.StandardMaterial("ground", scene);
            var t = new BABYLON.Texture("images/gr1.jpg", scene);
            t.uScale = t.vScale = 10;
            mat.diffuseTexture = t;
            mat.specularColor = BABYLON.Color3.Black();
            
            var g = BABYLON.Mesh.CreateBox("ground", 200, scene);
            
            g.position.y = -20;
            g.position.x = 0
            g.scaling.y = 0.01;
            g.material = mat;	
            
            scene.enablePhysics(new BABYLON.Vector3(0, -10, 0), new BABYLON.OimoJSPlugin());
            
            g.physicsImpostor = new BABYLON.PhysicsImpostor(g, BABYLON.PhysicsImpostor.BoxImpostor, { 
               mass: 0, 
               restitution: 0.9 
            }, scene);
            
            var getPosition = function(y) {
               return new v3(randomNumber(-100, 100), y, randomNumber(-100, 100));
            };
            
            var allspheres = [];
            var y = 50;
            var max = 50;
            
            for (var index = 0; index < max; index++) {
               var redSphere = BABYLON.Mesh.CreateSphere("s" + index, 32, 8, scene);
               redSphere.position = getPosition(y);
               redSphere.physicsImpostor = new BABYLON.PhysicsImpostor(redSphere, BABYLON.PhysicsImpostor.SphereImpostor,{
                  mass: 1, restitution:0.9
               }, scene);
               
               redSphere.physicsImpostor.applyImpulse(new BABYLON.Vector3(1, 2, -1), new BABYLON.Vector3(1, 2, 0));
               
               var redMat = new BABYLON.StandardMaterial("ground", scene);
               redMat.diffuseColor = new BABYLON.Color3(0.4, 0.4, 0.4);
               redMat.specularColor = new BABYLON.Color3(0.4, 0.4, 0.4);
               redMat.emissiveColor = BABYLON.Color3.Red();
               redSphere.material = redMat;
               
               // push all spheres in the allspheres variable
               allspheres.push(redSphere);			
               y += 10; // increment height
            }
            scene.registerBeforeRender(function() {
               allspheres.forEach(function(obj) { 
                  // if the sphers falls down its updated again over here
                  // If object falls
                  if (obj.position.y < -100) {
                     obj.position = getPosition(200);				
                  }
               });
            })
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

輸出

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

Physics engine

在這個演示中,我們使用了影像images/gr1.jpg。這些影像儲存在本地images/資料夾中,並也在下面貼上以供參考。您可以下載任何您選擇的影像,並在演示連結中使用。

images/gr1.jpg

GR1

解釋

scene.enablePhysics(new BABYLON.Vector3(0,-10,0), new BABYLON.OimoJSPlugin());

以上程式碼啟用物理外掛。您可以使用您選擇的外掛。我們使用了OimoJsplugin()。

g.physicsImpostor = newBABYLON.PhysicsImpostor(g, BABYLON.PhysicsImpostor.BoxImpostor, { 
   mass: 0, 
   restitution: 0.9 
}, scene);

對於互動,物理引擎使用模擬體。當應用於模擬體時,物體的形狀不能改變。如果更改,則必須建立一個新的模擬體。

對於球體,我們將設定模擬體並新增衝量以實現反彈效果,如下所示:

redSphere.physicsImpostor = new BABYLON.PhysicsImpostor(
   redSphere, BABYLON.PhysicsImpostor.SphereImpostor, { 
      mass: 1, 
      restitution:0.9
   }, scene
);

redSphere.physicsImpostor.applyImpulse(
   new BABYLON.Vector3(1, 2, -1), 
   new BABYLON.Vector3(1, 2, 0)
);

physicsImposter引數

考慮以下物理效果引數:

物體

這裡指的是要應用互動的物體。例如,球體、盒子等。

型別

型別可以是以下之一:

  • BABYLON.PhysicsImpostor.SphereImpostor;
  • BABYLON.PhysicsImpostor.BoxImpostor;
  • BABYLON.PhysicsImpostor.PlaneImpostor;
  • BABYLON.PhysicsImpostor.MeshImpostor;
  • BABYLON.PhysicsImpostor.CylinderImpostor;
  • BABYLON.PhysicsImpostor.ParticleImpostor;
  • BABYLON.PhysicsImpostor.HeightmapImpostor;

質量

唯一必需的引數是質量,它以千克為單位表示物體的質量。值為0將建立一個靜態模擬體——適合地面。

恢復係數

這是物體在碰撞時“回饋”的力的大小。較低的值將不會產生反彈,值為1將產生非常有彈性的互動。

scene.registerBeforeRender(function() {
   allspheres.forEach(function(obj) { 
      // if the sphers falls down its updated again over here
      // If object falls
      if (obj.position.y < -100) {
         obj.position = getPosition(200);
      }					
   });
})

以上程式碼將掉落在地面上的球體帶回地面。它不斷更新地面上的任何掉落的球體。在瀏覽器中嘗試以上演示以檢視物理效果。

廣告