在Three.js中,RapierPhysics是一个库,它提供了一组API来实现物理模拟。下面是RapierPhysics库中常用的一些API的入参、出参、属性和方法,以及它们的调用方式。
RapierPhysics API
1. 初始化
import { RapierPhysics } from 'three/addons/physics/RapierPhysics.js';
// 初始化RapierPhysics引擎
const physics = await RapierPhysics();
2. 添加物理场景
physics.addScene(scene);
- 入参:
scene
: THREE.Scene,要添加物理模拟的场景对象。
3. 设置网格对象位置
physics.setMeshPosition(mesh, position, index);
- 入参:
mesh
: THREE.Mesh,要设置位置的网格对象。position
: THREE.Vector3,新的位置向量。index
: 整数,要设置位置的网格实例的索引。
4. 设置刚体速度
physics.setRigidBodyVelocity(body, velocity);
- 入参:
body
: RapierPhysics.RigidBody,要设置速度的刚体对象。velocity
: THREE.Vector3,新的速度向量。
5. 获取刚体位置
const position = physics.getRigidBodyPosition(body);
- 入参:
body
: RapierPhysics.RigidBody,要获取位置的刚体对象。
- 出参:
position
: THREE.Vector3,刚体的当前位置向量。
6. 获取刚体速度
const velocity = physics.getRigidBodyVelocity(body);
- 入参:
body
: RapierPhysics.RigidBody,要获取速度的刚体对象。
- 出参:
velocity
: THREE.Vector3,刚体的当前速度向量。
7. 删除物理模拟
physics.remove();
示例调用方式
import * as THREE from 'three';
import { RapierPhysics } from 'three/addons/physics/RapierPhysics.js';
async function initPhysics() {
const physics = await RapierPhysics();
// 添加场景
physics.addScene(scene);
// 在循环中更新物理模拟
animate();
function animate() {
requestAnimationFrame(animate);
// 更新物理模拟
updatePhysics();
// 渲染场景
renderer.render(scene, camera);
}
function updatePhysics() {
// 更新物理模拟逻辑
// 设置网格对象的位置、刚体的速度等
}
}
这是一个简单的示例,显示了如何初始化RapierPhysics引擎,并在循环中更新物理模拟。在updatePhysics()
函数中,可以调用RapierPhysics的各种方法来更新物理模拟,例如设置网格对象的位置、刚体的速度等。
demo 源码
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js physics - rapier3d 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 - rapier3d instancing
</div>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { RapierPhysics } from 'three/addons/physics/RapierPhysics.js';
import Stats from 'three/addons/libs/stats.module.js';
let camera, scene, renderer, stats;
let physics, position;
let boxes, spheres;
init();
async function init() {
// 引入RapierPhysics库并初始化
physics = await RapierPhysics();
// 用于设置物体位置的向量
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();
// 初始化盒子实例化网格
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() ) );
}
// 初始化球体实例化网格
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 } );
renderer.setPixelRatio( 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();
// 每隔1/60秒随机改变盒子和球体的位置
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 );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
stats.update();
}
</script>
</body>
</html>