AmmoPhysics
是一个异步函数,用于创建 Ammo.js 物理引擎的实例。让我们逐个讲解其入参、出参、方法和属性:
入参:
- 无入参。
出参:
- 返回一个 Promise 对象,该 Promise 对象在解析时会提供 AmmoPhysics 实例。
方法和属性:
-
addScene(scene: THREE.Scene): void
- 参数:
scene
:THREE.Scene 类型的场景对象,需要将该场景添加到物理引擎中以实现物理模拟。
- 描述:将指定的 THREE.Scene 场景对象添加到物理引擎中,以便对其中的物体进行物理模拟。
- 参数:
-
setMeshPosition(mesh: THREE.InstancedMesh, position: THREE.Vector3, index: number): void
- 参数:
mesh
:THREE.InstancedMesh 类型的实例化网格对象,表示要设置位置的网格。position
:THREE.Vector3 类型的位置向量,表示要设置的新位置。index
:数字类型,表示要设置位置的实例在网格中的索引。
- 描述:设置实例化网格中指定索引的实例的位置。
- 参数:
-
setMeshRotation(mesh: THREE.InstancedMesh, quaternion: THREE.Quaternion, index: number): void
- 参数:
mesh
:THREE.InstancedMesh 类型的实例化网格对象,表示要设置旋转的网格。quaternion
:THREE.Quaternion 类型的四元数,表示要设置的新旋转。index
:数字类型,表示要设置旋转的实例在网格中的索引。
- 描述:设置实例化网格中指定索引的实例的旋转。
- 参数:
-
setMeshScale(mesh: THREE.InstancedMesh, scale: THREE.Vector3, index: number): void
- 参数:
mesh
:THREE.InstancedMesh 类型的实例化网格对象,表示要设置缩放的网格。scale
:THREE.Vector3 类型的缩放向量,表示要设置的新缩放值。index
:数字类型,表示要设置缩放的实例在网格中的索引。
- 描述:设置实例化网格中指定索引的实例的缩放值。
- 参数:
-
removeScene(scene: THREE.Scene): void
- 参数:
scene
:THREE.Scene 类型的场景对象,表示要从物理引擎中移除的场景。
- 描述:从物理引擎中移除指定的 THREE.Scene 场景对象,停止对其中物体的物理模拟。
- 参数:
-
update(deltaTime: number): void
- 参数:
deltaTime
:数字类型,表示自上一帧以来经过的时间(以秒为单位)。
- 描述:在每一帧中调用此方法以更新物理引擎中的物理模拟。传入的
deltaTime
参数用于控制模拟的运行速度。
- 参数:
demo 源码
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js physics - ammo.js instancing</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> physics - ammo.js instancing
</div>
<script src="jsm/libs/ammo.wasm.js"></script>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three'; // 导入 three.js 库
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; // 导入 OrbitControls 控制器
import { AmmoPhysics } from 'three/addons/physics/AmmoPhysics.js'; // 导入 AmmoPhysics 物理引擎
import Stats from 'three/addons/libs/stats.module.js'; // 导入性能统计库
let camera, scene, renderer, stats; // 声明相机、场景、渲染器和性能统计对象
let physics, position; // 声明物理引擎和位置向量
let boxes, spheres; // 声明盒子和球体对象
init(); // 调用初始化函数
async function init() {
physics = await AmmoPhysics(); // 等待物理引擎加载完毕
position = new THREE.Vector3(); // 创建一个位置向量
//
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); // 创建透视相机
camera.position.set(-1, 1.5, 2); // 设置相机位置
camera.lookAt(0, 0.5, 0); // 设置相机焦点
scene = new THREE.Scene(); // 创建场景
scene.background = new THREE.Color(0x666666); // 设置场景背景颜色
const hemiLight = new THREE.HemisphereLight(); // 创建半球光源
scene.add(hemiLight); // 将半球光源添加到场景中
const dirLight = new THREE.DirectionalLight(0xffffff, 3); // 创建定向光源
dirLight.position.set(5, 5, 5); // 设置光源位置
dirLight.castShadow = true; // 光源产生阴影
dirLight.shadow.camera.zoom = 2; // 设置阴影相机缩放比例
scene.add(dirLight); // 将定向光源添加到场景中
const floor = new THREE.Mesh( // 创建地面
new THREE.BoxGeometry(10, 5, 10), // 地面几何体
new THREE.ShadowMaterial({ color: 0x444444 }) // 地面材质
);
floor.position.y = -2.5; // 设置地面位置
floor.receiveShadow = true; // 地面接收阴影
floor.userData.physics = { mass: 0 }; // 设置地面的物理属性
scene.add(floor); // 将地面添加到场景中
//
const material = new THREE.MeshLambertMaterial(); // 创建兰伯特材质
const matrix = new THREE.Matrix4(); // 创建变换矩阵
const color = new THREE.Color(); // 创建颜色对象
// Boxes
const geometryBox = new THREE.BoxGeometry(0.075, 0.075, 0.075); // 创建盒子几何体
boxes = new THREE.InstancedMesh(geometryBox, material, 400); // 创建盒子实例化网格
boxes.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // 设置实例矩阵的使用方式,每帧更新
boxes.castShadow = true; // 盒子投射阴影
boxes.receiveShadow = true; // 盒子接收阴影
boxes.userData.physics = { mass: 1 }; // 设置盒子的物理属性
scene.add(boxes); // 将盒子添加到场景中
for (let i = 0; i < boxes.count; i++) { // 遍历每个盒子实例
matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); // 设置盒子的随机位置
boxes.setMatrixAt(i, matrix); // 设置盒子的变换矩阵
boxes.setColorAt(i, color.setHex(0xffffff * Math.random())); // 设置盒子的随机颜色
}
// Spheres
const geometrySphere = new THREE.IcosahedronGeometry(0.05, 4); // 创建球体几何体
spheres = new THREE.InstancedMesh(geometrySphere, material, 400); // 创建球体实例化网格
spheres.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // 设置实例矩阵的使用方式,每帧更新
spheres.castShadow = true; // 球体投射阴影
spheres.receiveShadow = true; // 球体接收阴影
spheres.userData.physics = { mass: 1 }; // 设置球体的物理属性
scene.add(spheres); // 将球体添加到场景中
for (let i = 0; i < spheres.count; i++) { // 遍历每个球体实例
matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); // 设置球体的随机位置
spheres.setMatrixAt(i, matrix); // 设置球体的变换矩阵
spheres.setColorAt(i, color.setHex(0xffffff * Math.random())); // 设置球体的随机颜色
}
physics.addScene(scene); // 将场景添加到物理引擎中
//
renderer = new THREE.WebGLRenderer({ antialias: true }); // 创建 WebGL 渲染器
renderer.setPixel
Ratio(window.devicePixelRatio); // 设置像素比例
renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器尺寸
renderer.shadowMap.enabled = true; // 启用阴影
document.body.appendChild(renderer.domElement); // 将渲染器元素添加到文档中
stats = new Stats(); // 创建性能统计对象
document.body.appendChild(stats.dom); // 将性能统计元素添加到文档中
//
const controls = new OrbitControls(camera, renderer.domElement); // 创建轨道控制器
controls.target.y = 0.5; // 设置控制器焦点
controls.update(); // 更新控制器
animate(); // 调用动画函数
setInterval(() => {
let index = Math.floor(Math.random() * boxes.count); // 随机获取盒子索引
position.set(0, Math.random() + 1, 0); // 设置随机位置
physics.setMeshPosition(boxes, position, index); // 设置盒子位置
//
index = Math.floor(Math.random() * spheres.count); // 随机获取球体索引
position.set(0, Math.random() + 1, 0); // 设置随机位置
physics.setMeshPosition(spheres, position, index); // 设置球体位置
}, 1000 / 60); // 每 1/60 秒执行一次
}
function animate() {
requestAnimationFrame(animate); // 请求动画帧
renderer.render(scene, camera); // 渲染场景
stats.update(); // 更新性能统计
}
</script>
</body>
</html>