Skip to content

Commit 5614fa9

Browse files
mrdoobemmanueljl
authored andcommitted
Added Rapier example (mrdoob#25892)
* Added Rapier example. * Updated screenshot. * Fixed DeepScan issue. * RapeirPhysics: Added world.timestep.
1 parent 314b681 commit 5614fa9

File tree

5 files changed

+411
-1
lines changed

5 files changed

+411
-1
lines changed

examples/files.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,8 @@
391391
"physics_ammo_rope",
392392
"physics_ammo_terrain",
393393
"physics_ammo_volume",
394-
"physics_oimo_instancing"
394+
"physics_oimo_instancing",
395+
"physics_rapier_instancing"
395396
],
396397
"misc": [
397398
"misc_animation_groups",
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
async function RapierPhysics( path ) {
2+
3+
const RAPIER = await import( path );
4+
5+
await RAPIER.init();
6+
7+
const frameRate = 60;
8+
9+
// Docs: https://rapier.rs/docs/api/javascript/JavaScript3D/
10+
11+
const gravity = { x: 0.0, y: - 9.81, z: 0.0 };
12+
const world = new RAPIER.World( gravity );
13+
14+
function getCollider( geometry ) {
15+
16+
const parameters = geometry.parameters;
17+
18+
// TODO change type to is*
19+
20+
if ( geometry.type === 'BoxGeometry' ) {
21+
22+
const sx = parameters.width !== undefined ? parameters.width / 2 : 0.5;
23+
const sy = parameters.height !== undefined ? parameters.height / 2 : 0.5;
24+
const sz = parameters.depth !== undefined ? parameters.depth / 2 : 0.5;
25+
26+
return RAPIER.ColliderDesc.cuboid( sx, sy, sz );
27+
28+
} else if ( geometry.type === 'SphereGeometry' || geometry.type === 'IcosahedronGeometry' ) {
29+
30+
const radius = parameters.radius !== undefined ? parameters.radius : 1;
31+
32+
return RAPIER.ColliderDesc.ball( radius );
33+
34+
}
35+
36+
return null;
37+
38+
}
39+
40+
const meshes = [];
41+
const meshMap = new WeakMap();
42+
43+
function addMesh( mesh, mass = 0, restitution = 0 ) {
44+
45+
const shape = getCollider( mesh.geometry );
46+
47+
if ( shape !== null ) {
48+
49+
shape.setMass( mass );
50+
shape.setRestitution( restitution );
51+
52+
if ( mesh.isInstancedMesh ) {
53+
54+
handleInstancedMesh( mesh, mass, shape );
55+
56+
} else if ( mesh.isMesh ) {
57+
58+
handleMesh( mesh, mass, shape );
59+
60+
}
61+
62+
}
63+
64+
}
65+
66+
function handleMesh( mesh, mass, shape ) {
67+
68+
const position = mesh.position;
69+
const quaternion = mesh.quaternion;
70+
71+
const desc = mass > 0 ? RAPIER.RigidBodyDesc.dynamic() : RAPIER.RigidBodyDesc.fixed();
72+
desc.setTranslation( position.x, position.y, position.z );
73+
desc.setRotation( quaternion );
74+
75+
const body = world.createRigidBody( desc );
76+
world.createCollider( shape, body );
77+
78+
if ( mass > 0 ) {
79+
80+
meshes.push( mesh );
81+
meshMap.set( mesh, body );
82+
83+
}
84+
85+
}
86+
87+
function handleInstancedMesh( mesh, mass, shape ) {
88+
89+
const array = mesh.instanceMatrix.array;
90+
91+
const bodies = [];
92+
93+
for ( let i = 0; i < mesh.count; i ++ ) {
94+
95+
const index = i * 16;
96+
97+
const desc = mass > 0 ? RAPIER.RigidBodyDesc.dynamic() : RAPIER.RigidBodyDesc.fixed();
98+
desc.setTranslation( array[ index + 12 ], array[ index + 13 ], array[ index + 14 ] );
99+
100+
const body = world.createRigidBody( desc );
101+
world.createCollider( shape, body );
102+
103+
bodies.push( body );
104+
105+
}
106+
107+
if ( mass > 0 ) {
108+
109+
meshes.push( mesh );
110+
meshMap.set( mesh, bodies );
111+
112+
}
113+
114+
}
115+
116+
const vector = { x: 0, y: 0, z: 0 };
117+
118+
function setMeshPosition( mesh, position, index = 0 ) {
119+
120+
if ( mesh.isInstancedMesh ) {
121+
122+
const bodies = meshMap.get( mesh );
123+
const body = bodies[ index ];
124+
125+
body.setAngvel( vector );
126+
body.setLinvel( vector );
127+
body.setTranslation( position );
128+
129+
} else if ( mesh.isMesh ) {
130+
131+
const body = meshMap.get( mesh );
132+
133+
body.setAngvel( vector );
134+
body.setLinvel( vector );
135+
body.setTranslation( position );
136+
137+
}
138+
139+
}
140+
141+
//
142+
143+
let lastTime = 0;
144+
145+
function step() {
146+
147+
const time = performance.now();
148+
149+
if ( lastTime > 0 ) {
150+
151+
const delta = ( time - lastTime ) / 1000;
152+
153+
world.timestep = delta;
154+
world.step();
155+
156+
for ( let i = 0, l = meshes.length; i < l; i ++ ) {
157+
158+
const mesh = meshes[ i ];
159+
160+
if ( mesh.isInstancedMesh ) {
161+
162+
const array = mesh.instanceMatrix.array;
163+
const bodies = meshMap.get( mesh );
164+
165+
for ( let j = 0; j < bodies.length; j ++ ) {
166+
167+
const body = bodies[ j ];
168+
169+
const position = body.translation();
170+
const quaternion = body.rotation();
171+
172+
compose( position, quaternion, array, j * 16 );
173+
174+
}
175+
176+
mesh.instanceMatrix.needsUpdate = true;
177+
mesh.computeBoundingSphere();
178+
179+
} else if ( mesh.isMesh ) {
180+
181+
const body = meshMap.get( mesh );
182+
183+
mesh.position.copy( body.translation() );
184+
mesh.quaternion.copy( body.rotation() );
185+
186+
}
187+
188+
}
189+
190+
}
191+
192+
lastTime = time;
193+
194+
}
195+
196+
// animate
197+
198+
setInterval( step, 1000 / frameRate );
199+
200+
return {
201+
addMesh: addMesh,
202+
setMeshPosition: setMeshPosition
203+
};
204+
205+
}
206+
207+
function compose( position, quaternion, array, index ) {
208+
209+
const x = quaternion.x, y = quaternion.y, z = quaternion.z, w = quaternion.w;
210+
const x2 = x + x, y2 = y + y, z2 = z + z;
211+
const xx = x * x2, xy = x * y2, xz = x * z2;
212+
const yy = y * y2, yz = y * z2, zz = z * z2;
213+
const wx = w * x2, wy = w * y2, wz = w * z2;
214+
215+
array[ index + 0 ] = ( 1 - ( yy + zz ) );
216+
array[ index + 1 ] = ( xy + wz );
217+
array[ index + 2 ] = ( xz - wy );
218+
array[ index + 3 ] = 0;
219+
220+
array[ index + 4 ] = ( xy - wz );
221+
array[ index + 5 ] = ( 1 - ( xx + zz ) );
222+
array[ index + 6 ] = ( yz + wx );
223+
array[ index + 7 ] = 0;
224+
225+
array[ index + 8 ] = ( xz + wy );
226+
array[ index + 9 ] = ( yz - wx );
227+
array[ index + 10 ] = ( 1 - ( xx + yy ) );
228+
array[ index + 11 ] = 0;
229+
230+
array[ index + 12 ] = position.x;
231+
array[ index + 13 ] = position.y;
232+
array[ index + 14 ] = position.z;
233+
array[ index + 15 ] = 1;
234+
235+
}
236+
237+
export { RapierPhysics };

0 commit comments

Comments
 (0)