소스 검색

Examples: Replaced custom physics code with Rapier in webxr_xr_ballshooter (#26032)

* Examples: Replaced custom physics code with Rapier in webxr_xr_ballshooter.

* Update RapierPhysics.js
mrdoob 2 년 전
부모
커밋
374bf61c06
3개의 변경된 파일99개의 추가작업 그리고 105개의 파일을 삭제
  1. 26 6
      examples/jsm/physics/RapierPhysics.js
  2. BIN
      examples/screenshots/webxr_xr_ballshooter.jpg
  3. 73 99
      examples/webxr_xr_ballshooter.html

+ 26 - 6
examples/jsm/physics/RapierPhysics.js

@@ -113,7 +113,7 @@ async function RapierPhysics() {
 
 	}
 
-	const vector = { x: 0, y: 0, z: 0 };
+	const ZERO = { x: 0, y: 0, z: 0 };
 
 	function setMeshPosition( mesh, position, index = 0 ) {
 
@@ -122,22 +122,41 @@ async function RapierPhysics() {
 			const bodies = meshMap.get( mesh );
 			const body = bodies[ index ];
 
-			body.setAngvel( vector );
-			body.setLinvel( vector );
+			body.setAngvel( ZERO );
+			body.setLinvel( ZERO );
 			body.setTranslation( position );
 
 		} else if ( mesh.isMesh ) {
 
 			const body = meshMap.get( mesh );
 
-			body.setAngvel( vector );
-			body.setLinvel( vector );
+			body.setAngvel( ZERO );
+			body.setLinvel( ZERO );
 			body.setTranslation( position );
 
 		}
 
 	}
 
+	function setMeshVelocity( mesh, velocity, index = 0 ) {
+
+		if ( mesh.isInstancedMesh ) {
+
+			const bodies = meshMap.get( mesh );
+			const body = bodies[ index ];
+
+			body.setLinvel( velocity );
+
+		} else if ( mesh.isMesh ) {
+
+			const body = meshMap.get( mesh );
+
+			body.setLinvel( velocity );
+
+		}
+
+	}
+
 	//
 
 	let lastTime = 0;
@@ -201,7 +220,8 @@ async function RapierPhysics() {
 
 	return {
 		addMesh: addMesh,
-		setMeshPosition: setMeshPosition
+		setMeshPosition: setMeshPosition,
+		setMeshVelocity: setMeshVelocity
 	};
 
 }

BIN
examples/screenshots/webxr_xr_ballshooter.jpg


+ 73 - 99
examples/webxr_xr_ballshooter.html

@@ -32,31 +32,28 @@
 			import { BoxLineGeometry } from 'three/addons/geometries/BoxLineGeometry.js';
 			import { XRButton } from 'three/addons/webxr/XRButton.js';
 			import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js';
+			import { RapierPhysics } from 'three/addons/physics/RapierPhysics.js';
 
-			THREE.ColorManagement.enabled = false; // TODO: Consider enabling color management.
+			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 			let camera, scene, renderer;
 			let controller1, controller2;
 			let controllerGrip1, controllerGrip2;
 
-			let room;
+			let room, spheres;
+			let physics, velocity = new THREE.Vector3();
 
 			let count = 0;
-			const radius = 0.08;
-			let normal = new THREE.Vector3();
-			const relativeVelocity = new THREE.Vector3();
-
-			const clock = new THREE.Clock();
 
 			init();
-			animate();
+			await initPhysics();
 
 			function init() {
 
 				scene = new THREE.Scene();
 				scene.background = new THREE.Color( 0x505050 );
 
-				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 10 );
+				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 50 );
 				camera.position.set( 0, 1.6, 3 );
 
 				room = new THREE.LineSegments(
@@ -66,41 +63,28 @@
 				room.geometry.translate( 0, 3, 0 );
 				scene.add( room );
 
-				scene.add( new THREE.HemisphereLight( 0x606060, 0x404040 ) );
+				scene.add( new THREE.HemisphereLight( 0xbbbbbb, 0x888888 ) );
 
 				const light = new THREE.DirectionalLight( 0xffffff );
 				light.position.set( 1, 1, 1 ).normalize();
 				scene.add( light );
 
-				const geometry = new THREE.IcosahedronGeometry( radius, 3 );
-
-				for ( let i = 0; i < 200; i ++ ) {
-
-					const object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
-
-					object.position.x = Math.random() * 4 - 2;
-					object.position.y = Math.random() * 4;
-					object.position.z = Math.random() * 4 - 2;
-
-					object.userData.velocity = new THREE.Vector3();
-					object.userData.velocity.x = Math.random() * 0.01 - 0.005;
-					object.userData.velocity.y = Math.random() * 0.01 - 0.005;
-					object.userData.velocity.z = Math.random() * 0.01 - 0.005;
-
-					room.add( object );
-
-				}
-
 				//
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setAnimationLoop( render );
 				renderer.xr.enabled = true;
 				document.body.appendChild( renderer.domElement );
 
 				//
 
+				const controls = new OrbitControls( camera, renderer.domElement );
+				controls.maxDistance = 10;
+				controls.target.y = 1.6;
+				controls.update();
+
 				document.body.appendChild( XRButton.createButton( renderer ) );
 
 				// controllers
@@ -203,108 +187,98 @@
 
 			}
 
-			function handleController( controller ) {
-
-				if ( controller.userData.isSelecting ) {
-
-					const object = room.children[ count ++ ];
-
-					object.position.copy( controller.position );
-					object.userData.velocity.x = ( Math.random() - 0.5 ) * 3;
-					object.userData.velocity.y = ( Math.random() - 0.5 ) * 3;
-					object.userData.velocity.z = ( Math.random() - 9 );
-					object.userData.velocity.applyQuaternion( controller.quaternion );
-
-					if ( count === room.children.length ) count = 0;
-
-				}
-
-			}
-
-			//
-
-			function animate() {
-
-				renderer.setAnimationLoop( render );
-
-			}
-
-			function render() {
-
-				handleController( controller1 );
-				handleController( controller2 );
+			async function initPhysics() {
 
-				//
+				physics = await RapierPhysics();
 
-				const delta = clock.getDelta() * 0.8; // slow down simulation
+				{
 
-				const range = 3 - radius;
+					// Floor
 
-				for ( let i = 0; i < room.children.length; i ++ ) {
+					const geometry = new THREE.BoxGeometry( 6, 2, 6 );
+					const material = new THREE.MeshNormalMaterial();
 
-					const object = room.children[ i ];
+					const floor = new THREE.Mesh( geometry, material );
+					floor.position.y = - 1;
+					physics.addMesh( floor );
 
-					object.position.x += object.userData.velocity.x * delta;
-					object.position.y += object.userData.velocity.y * delta;
-					object.position.z += object.userData.velocity.z * delta;
+					// Walls
 
-					// keep objects inside room
+					const wallPX = new THREE.Mesh( geometry, material );
+					wallPX.position.set( 4, 3, 0 );
+					wallPX.rotation.z = Math.PI / 2;
+					physics.addMesh( wallPX );
 
-					if ( object.position.x < - range || object.position.x > range ) {
+					const wallNX = new THREE.Mesh( geometry, material );
+					wallNX.position.set( - 4, 3, 0 );
+					wallNX.rotation.z = Math.PI / 2;
+					physics.addMesh( wallNX );
 
-						object.position.x = THREE.MathUtils.clamp( object.position.x, - range, range );
-						object.userData.velocity.x = - object.userData.velocity.x;
+					const wallPZ = new THREE.Mesh( geometry, material );
+					wallPZ.position.set( 0, 3, 4 );
+					wallPZ.rotation.x = Math.PI / 2;
+					physics.addMesh( wallPZ );
 
-					}
+					const wallNZ = new THREE.Mesh( geometry, material );
+					wallNZ.position.set( 0, 3, - 4 );
+					wallNZ.rotation.x = Math.PI / 2;
+					physics.addMesh( wallNZ );
 
-					if ( object.position.y < radius || object.position.y > 6 ) {
+				}
 
-						object.position.y = Math.max( object.position.y, radius );
+				// Spheres
 
-						object.userData.velocity.x *= 0.98;
-						object.userData.velocity.y = - object.userData.velocity.y * 0.8;
-						object.userData.velocity.z *= 0.98;
+				const geometry = new THREE.IcosahedronGeometry( 0.08, 3 );
+				const material = new THREE.MeshLambertMaterial();
 
-					}
+				spheres = new THREE.InstancedMesh( geometry, material, 800 );
+				spheres.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
+				scene.add( spheres );
 
-					if ( object.position.z < - range || object.position.z > range ) {
+				const matrix = new THREE.Matrix4();
+				const color = new THREE.Color();
 
-						object.position.z = THREE.MathUtils.clamp( object.position.z, - range, range );
-						object.userData.velocity.z = - object.userData.velocity.z;
+				for ( let i = 0; i < spheres.count; i ++ ) {
 
-					}
+					const x = Math.random() * 4 - 2;
+					const y = Math.random() * 4;
+					const z = Math.random() * 4 - 2;
 
-					for ( let j = i + 1; j < room.children.length; j ++ ) {
+					matrix.setPosition( x, y, z );
+					spheres.setMatrixAt( i, matrix );
+					spheres.setColorAt( i, color.setHex( 0xffffff * Math.random() ) );
 
-						const object2 = room.children[ j ];
+				}
 
-						normal.copy( object.position ).sub( object2.position );
+				physics.addMesh( spheres, 1, 1.1 );
 
-						const distance = normal.length();
+			}
 
-						if ( distance < 2 * radius ) {
+			//
 
-							normal.multiplyScalar( 0.5 * distance - radius );
+			function handleController( controller ) {
 
-							object.position.sub( normal );
-							object2.position.add( normal );
+				if ( controller.userData.isSelecting ) {
 
-							normal.normalize();
+					physics.setMeshPosition( spheres, controller.position, count );
 
-							relativeVelocity.copy( object.userData.velocity ).sub( object2.userData.velocity );
+					velocity.x = ( Math.random() - 0.5 ) * 2;
+					velocity.y = ( Math.random() - 0.5 ) * 2;
+					velocity.z = ( Math.random() - 9 );
+					velocity.applyQuaternion( controller.quaternion );
 
-							normal = normal.multiplyScalar( relativeVelocity.dot( normal ) );
+					physics.setMeshVelocity( spheres, velocity, count );
 
-							object.userData.velocity.sub( normal );
-							object2.userData.velocity.add( normal );
+					if ( ++ count === spheres.count ) count = 0;
 
-						}
+				}
 
-					}
+			}
 
-					object.userData.velocity.y -= 9.8 * delta;
+			function render() {
 
-				}
+				handleController( controller1 );
+				handleController( controller2 );
 
 				renderer.render( scene, camera );