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