physics_oimo_instancing.html 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js physics - OimoPhysics instancing</title>
  5. <meta charset="utf-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  7. <link type="text/css" rel="stylesheet" href="main.css">
  8. </head>
  9. <body>
  10. <div id="info">
  11. <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> physics - OimoPhysics instancing
  12. </div>
  13. <script type="module">
  14. import * as THREE from '../build/three.module.js';
  15. import { OrbitControls } from './jsm/controls/OrbitControls.js';
  16. import Stats from './jsm/libs/stats.module.js';
  17. // Or use latest version from NPM `oimophysics`
  18. import {oimo} from './jsm/libs/OimoPhysics.js';
  19. const Vec3 = oimo.common.Vec3;
  20. const World = oimo.dynamics.World;
  21. const RigidBodyType = oimo.dynamics.rigidbody.RigidBodyType;
  22. const RigidBodyConfig = oimo.dynamics.rigidbody.RigidBodyConfig;
  23. const ShapeConfig = oimo.dynamics.rigidbody.ShapeConfig;
  24. const RigidBody = oimo.dynamics.rigidbody.RigidBody;
  25. const Shape = oimo.dynamics.rigidbody.Shape;
  26. const OBoxGeometry = oimo.collision.geometry.BoxGeometry;
  27. const OSphereGeometry = oimo.collision.geometry.SphereGeometry;
  28. let camera, scene, renderer, stats;
  29. let physics, position;
  30. let world;
  31. let boxes, spheres;
  32. let boxesPhys, spheresPhys;
  33. const dummy = new THREE.Object3D();
  34. init();
  35. async function init() {
  36. world = new World(2, new Vec3(0, -9.8, 0));
  37. boxesPhys = [];
  38. spheresPhys = [];
  39. position = new THREE.Vector3();
  40. camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 100 );
  41. camera.position.set( - 1, 1.5, 2 );
  42. camera.lookAt( 0, 0.5, 0 );
  43. scene = new THREE.Scene();
  44. scene.background = new THREE.Color( 0x666666 );
  45. const hemiLight = new THREE.HemisphereLight();
  46. hemiLight.intensity = 0.35;
  47. scene.add( hemiLight );
  48. const dirLight = new THREE.DirectionalLight();
  49. dirLight.position.set( 5, 5, 5 );
  50. dirLight.castShadow = true;
  51. dirLight.shadow.camera.zoom = 2;
  52. scene.add( dirLight );
  53. const floor = new THREE.Mesh(
  54. new THREE.BoxGeometry( 10, 5, 10 ),
  55. new THREE.ShadowMaterial( { color: 0x111111 } )
  56. );
  57. floor.position.y = - 2.5;
  58. floor.receiveShadow = true;
  59. floor.userData.physics = addRigidBody(world, vec3FromVector3(floor.position), new OBoxGeometry(new Vec3(10 / 2, 5 / 2, 10 / 2)), true);
  60. scene.add( floor );
  61. const material = new THREE.MeshLambertMaterial();
  62. const matrix = new THREE.Matrix4();
  63. const color = new THREE.Color();
  64. // Boxes
  65. const boxSideSize = 0.1;
  66. const geometryBox = new THREE.BoxGeometry( boxSideSize, boxSideSize, boxSideSize );
  67. boxes = new THREE.InstancedMesh( geometryBox, material, 100 );
  68. boxes.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
  69. boxes.castShadow = true;
  70. boxes.receiveShadow = true;
  71. scene.add( boxes );
  72. for ( let i = 0; i < boxes.count; i ++ ) {
  73. position.set(Math.random() - 0.5, Math.random() * 10, Math.random() - 0.5);
  74. matrix.setPosition( position.x, position.y, position.z );
  75. boxes.setMatrixAt( i, matrix );
  76. boxes.setColorAt( i, color.setHex( 0xffffff * Math.random() ) );
  77. // size of the side of the cube should be 2 times smaller
  78. boxesPhys.push(addRigidBody(world, vec3FromVector3(position), new OBoxGeometry(new Vec3(boxSideSize / 2, boxSideSize / 2, boxSideSize / 2)), false));
  79. }
  80. // Spheres
  81. const geometrySphere = new THREE.IcosahedronGeometry( 0.075, 3 );
  82. spheres = new THREE.InstancedMesh( geometrySphere, material, 100 );
  83. spheres.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
  84. spheres.castShadow = true;
  85. spheres.receiveShadow = true;
  86. scene.add( spheres );
  87. for ( let i = 0; i < spheres.count; i ++ ) {
  88. position.set(Math.random() - 0.5, Math.random() * 10, Math.random() - 0.5);
  89. matrix.setPosition( position.x, position.y, position.z );
  90. spheres.setMatrixAt( i, matrix );
  91. spheres.setColorAt( i, color.setHex( 0xffffff * Math.random() ) );
  92. spheresPhys.push(addRigidBody(world, vec3FromVector3(position), new OSphereGeometry(0.075), false));
  93. }
  94. //
  95. renderer = new THREE.WebGLRenderer( { antialias: true } );
  96. renderer.setPixelRatio( window.devicePixelRatio );
  97. renderer.setSize( window.innerWidth, window.innerHeight );
  98. renderer.shadowMap.enabled = true;
  99. renderer.outputEncoding = THREE.sRGBEncoding;
  100. document.body.appendChild( renderer.domElement );
  101. stats = new Stats();
  102. document.body.appendChild( stats.dom );
  103. //
  104. const controls = new OrbitControls( camera, renderer.domElement );
  105. controls.target.y = 0.5;
  106. controls.update();
  107. window.addEventListener('resize', onWindowResize);
  108. animate();
  109. }
  110. function onWindowResize() {
  111. camera.aspect = document.body.clientWidth / document.body.clientHeight;
  112. camera.updateProjectionMatrix();
  113. renderer.setSize(document.body.clientWidth, document.body.clientHeight);
  114. }
  115. function animate() {
  116. requestAnimationFrame( animate );
  117. world.step(1 / 60);
  118. // updating data of visual objects from physical objects
  119. // BOXES
  120. boxesPhys.forEach((elPhys, index) => {
  121. const posVec3 = elPhys.getPosition();
  122. dummy.position.set(posVec3.x, posVec3.y, posVec3.z);
  123. dummy.setRotationFromQuaternion(quaternionFromQuat(elPhys.getOrientation()));
  124. dummy.updateMatrix();
  125. boxes.setMatrixAt( index, dummy.matrix );
  126. });
  127. let index = Math.floor( Math.random() * boxes.count );
  128. boxesPhys[index].setPosition( new Vec3(0, Math.random() + 1, 0) );
  129. boxes.instanceMatrix.needsUpdate = true;
  130. // SPHERES
  131. spheresPhys.forEach((elPhys, index) => {
  132. const posVec3 = elPhys.getPosition();
  133. dummy.position.set(posVec3.x, posVec3.y, posVec3.z);
  134. dummy.setRotationFromQuaternion(quaternionFromQuat(elPhys.getOrientation()));
  135. dummy.updateMatrix();
  136. spheres.setMatrixAt( index, dummy.matrix );
  137. });
  138. index = Math.floor( Math.random() * spheres.count );
  139. spheresPhys[index].setPosition( new Vec3(0, Math.random() + 1, 0) );
  140. spheres.instanceMatrix.needsUpdate = true;
  141. renderer.render( scene, camera );
  142. stats.update();
  143. }
  144. // adding a physical object to the world of physics
  145. function addRigidBody(w, center, geom, wall) {
  146. const shapeConfig = new ShapeConfig();
  147. shapeConfig.geometry = geom;
  148. const bodyConfig = new RigidBodyConfig();
  149. bodyConfig.type = wall ? RigidBodyType.STATIC : RigidBodyType.DYNAMIC;
  150. bodyConfig.position = center;
  151. let body = new RigidBody(bodyConfig);
  152. body.addShape(new Shape(shapeConfig));
  153. w.addRigidBody(body);
  154. return body;
  155. }
  156. // convert threejs Vector3 to oimo Vec3
  157. function vec3FromVector3(position) {
  158. return new Vec3(...position.toArray());
  159. }
  160. // convert oimo Quat to threejs quaternion
  161. function quaternionFromQuat(quat) {
  162. return new THREE.Quaternion(quat.x, quat.y, quat.z, quat.w);
  163. }
  164. </script>
  165. </body>
  166. </html>