threejs之cannon-es 物理引擎

1,156 阅读2分钟

image.png

俗话的好工欲善其事,必先利其器,有一个好的工具可以让项目开发更为高效。

这里说下常配合threejs使用的物理引擎库[cannon-es](GitHub - pmndrs/cannon-es:💣一个用JavaScript编写的轻量级3D物理引擎。)。

cannon-es是一个3d物理引擎,它能实现常见的碰撞检测,各种体形,接触,摩擦和约束功能。

在这里我将一步一步使用cannon-es配合threejs

前提基于umi4框架基础上实现,在这里假设你已使用了[umi框架](快速上手 | UmiJS)

  1. 首先初始化threejs,且引入cannon-es
  import * as CANNON from "cannon-es";
  ...
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  // 设置相机位置
  camera.position.set(0, 0, 15);
  scene.add(camera);

  // 渲染器
  const renderer = new THREE.WebGLRenderer({
    alpha: true,
  });
  // 设置渲染大小
  renderer.setSize(window.innerWidth, window.innerHeight);
  //   设置渲染器透明
  dom.appendChild(renderer.domElement);

  renderer.render(scene, camera);
  let clock = new THREE.Clock();

  const render = () => {

    renderer.render(scene, camera);
    requestAnimationFrame(render);
  };

  render();
  1. threejs与cannon结合,模拟小球受重力影响向下坠落
  // 首先我们在场景中创建一个小球
  const sphereGeometry = new THREE.SphereGeometry(1, 20, 20);
  const sphereMater = new THREE.MeshStandardMaterial();
  const sphere = new THREE.Mesh(sphereGeometry, sphereMater);
  sphere.castShadow = true;
  scene.add(sphere);

  // 然后创建一个平面用于后续接收小球
  const floor = new THREE.Mesh(
    new THREE.PlaneGeometry(20, 20),
    new THREE.MeshStandardMaterial()
  );
  floor.position.set(0, -5, 0);
  floor.rotation.x = -Math.PI / 2;
  floor.receiveShadow = true;
  scene.add(floor);

   // cannon 使用 ------------------------
  // 首先先创建物理世界
  const World = new CANNON.World();
  // 设置向下的作用力
  World.gravity.set(0, -9.8, 0);
  // 创建物理世界小球以及物体
  const sphereShape = new CANNON.Sphere(1);
  const sphereWorldMaterial = new CANNON.Material();
  const sphereBody = new CANNON.Body({
    shape: sphereShape,
    position: new CANNON.Vec3(0, 0, 0),
    // 小球质量
    mass: 1,
    // 物体的材质,可影响阻力,弹力系数等
    material: sphereWorldMaterial,
  });
  // 物体添加到物理世界中
  World.addBody(sphereBody);

  // 环境光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  scene.add(ambientLight);
  // 平行光
  const dirLight = new THREE.DirectionalLight(0xffffff, 0.5);
  dirLight.castShadow = true;
  scene.add(dirLight);
  
  ...
  //同时在render函数中不断更新物理世界中的物体

   config.World.step(1 / 120, deltaTime);
  
  // 将物理世界中的位置同步到threejs场景中 我们就可以模拟受重力物体向下运动了 
  config.sphere.position.copy(config.sphereBody.position);
  
  1. 实现小球落地面上停下来
  // 我们只需要在物理世界中也创建地面,同时将地面添加到物理世界中,在物理世界中小球遇到面物体后会停止下落。
  const floorShape = new CANNON.Plane();
  const floorBody = new CANNON.Body({
    // 设置为0时保证地面不动
    mass: 0,
    shape: floorShape,
    // 需要与threejs中地面位置同步
    position: new CANNON.Vec3(0, -5, 0),
  });
  floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
  World.addBody(floorBody);