main.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import * as THREE from 'https://cdn.skypack.dev/[email protected]';
  2. import {OrbitControls} from 'https://cdn.skypack.dev/[email protected]/examples/jsm/controls/OrbitControls.js';
  3. const DEFAULT_MASS = 10;
  4. class RigidBody {
  5. constructor() {
  6. }
  7. setRestitution(val) {
  8. this.body_.setRestitution(val);
  9. }
  10. setFriction(val) {
  11. this.body_.setFriction(val);
  12. }
  13. setRollingFriction(val) {
  14. this.body_.setRollingFriction(val);
  15. }
  16. createBox(mass, pos, quat, size) {
  17. this.transform_ = new Ammo.btTransform();
  18. this.transform_.setIdentity();
  19. this.transform_.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z));
  20. this.transform_.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w));
  21. this.motionState_ = new Ammo.btDefaultMotionState(this.transform_);
  22. const btSize = new Ammo.btVector3(size.x * 0.5, size.y * 0.5, size.z * 0.5);
  23. this.shape_ = new Ammo.btBoxShape(btSize);
  24. this.shape_.setMargin(0.05);
  25. this.inertia_ = new Ammo.btVector3(0, 0, 0);
  26. if (mass > 0) {
  27. this.shape_.calculateLocalInertia(mass, this.inertia_);
  28. }
  29. this.info_ = new Ammo.btRigidBodyConstructionInfo(
  30. mass, this.motionState_, this.shape_, this.inertia_);
  31. this.body_ = new Ammo.btRigidBody(this.info_);
  32. Ammo.destroy(btSize);
  33. }
  34. createSphere(mass, pos, size) {
  35. this.transform_ = new Ammo.btTransform();
  36. this.transform_.setIdentity();
  37. this.transform_.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z));
  38. this.transform_.setRotation(new Ammo.btQuaternion(0, 0, 0, 1));
  39. this.motionState_ = new Ammo.btDefaultMotionState(this.transform_);
  40. this.shape_ = new Ammo.btSphereShape(size);
  41. this.shape_.setMargin(0.05);
  42. this.inertia_ = new Ammo.btVector3(0, 0, 0);
  43. if(mass > 0) {
  44. this.shape_.calculateLocalInertia(mass, this.inertia_);
  45. }
  46. this.info_ = new Ammo.btRigidBodyConstructionInfo(mass, this.motionState_, this.shape_, this.inertia_);
  47. this.body_ = new Ammo.btRigidBody(this.info_);
  48. }
  49. }
  50. class BasicWorldDemo {
  51. constructor() {
  52. }
  53. initialize() {
  54. this.collisionConfiguration_ = new Ammo.btDefaultCollisionConfiguration();
  55. this.dispatcher_ = new Ammo.btCollisionDispatcher(this.collisionConfiguration_);
  56. this.broadphase_ = new Ammo.btDbvtBroadphase();
  57. this.solver_ = new Ammo.btSequentialImpulseConstraintSolver();
  58. this.physicsWorld_ = new Ammo.btDiscreteDynamicsWorld(
  59. this.dispatcher_, this.broadphase_, this.solver_, this.collisionConfiguration_);
  60. this.physicsWorld_.setGravity(new Ammo.btVector3(0, -100, 0));
  61. this.threejs_ = new THREE.WebGLRenderer({
  62. antialias: true,
  63. });
  64. this.threejs_.shadowMap.enabled = true;
  65. this.threejs_.shadowMap.type = THREE.PCFSoftShadowMap;
  66. this.threejs_.setPixelRatio(window.devicePixelRatio);
  67. this.threejs_.setSize(window.innerWidth, window.innerHeight);
  68. document.body.appendChild(this.threejs_.domElement);
  69. window.addEventListener('resize', () => {
  70. this.onWindowResize_();
  71. }, false);
  72. const fov = 60;
  73. const aspect = 1920 / 1080;
  74. const near = 1.0;
  75. const far = 1000.0;
  76. this.camera_ = new THREE.PerspectiveCamera(fov, aspect, near, far);
  77. this.camera_.position.set(75, 20, 0);
  78. this.scene_ = new THREE.Scene();
  79. let light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
  80. light.position.set(20, 100, 10);
  81. light.target.position.set(0, 0, 0);
  82. light.castShadow = true;
  83. light.shadow.bias = -0.001;
  84. light.shadow.mapSize.width = 2048;
  85. light.shadow.mapSize.height = 2048;
  86. light.shadow.camera.near = 0.1;
  87. light.shadow.camera.far = 500.0;
  88. light.shadow.camera.near = 0.5;
  89. light.shadow.camera.far = 500.0;
  90. light.shadow.camera.left = 100;
  91. light.shadow.camera.right = -100;
  92. light.shadow.camera.top = 100;
  93. light.shadow.camera.bottom = -100;
  94. this.scene_.add(light);
  95. light = new THREE.AmbientLight(0x101010);
  96. this.scene_.add(light);
  97. const controls = new OrbitControls(
  98. this.camera_, this.threejs_.domElement);
  99. controls.target.set(0, 20, 0);
  100. controls.update();
  101. const loader = new THREE.CubeTextureLoader();
  102. const texture = loader.load([
  103. './resources/posx.jpg',
  104. './resources/negx.jpg',
  105. './resources/posy.jpg',
  106. './resources/negy.jpg',
  107. './resources/posz.jpg',
  108. './resources/negz.jpg',
  109. ]);
  110. this.scene_.background = texture;
  111. const ground = new THREE.Mesh(
  112. new THREE.BoxGeometry(100, 1, 100),
  113. new THREE.MeshStandardMaterial({color: 0x404040}));
  114. ground.castShadow = false;
  115. ground.receiveShadow = true;
  116. this.scene_.add(ground);
  117. const rbGround = new RigidBody();
  118. rbGround.createBox(0, ground.position, ground.quaternion, new THREE.Vector3(100, 1, 100));
  119. rbGround.setRestitution(0.99);
  120. this.physicsWorld_.addRigidBody(rbGround.body_);
  121. this.rigidBodies_ = [];
  122. // const box = new THREE.Mesh(
  123. // new THREE.BoxGeometry(4, 4, 4),
  124. // new THREE.MeshStandardMaterial({color: 0x808080}));
  125. // box.position.set(0, 40, 0);
  126. // box.castShadow = true;
  127. // box.receiveShadow = true;
  128. // this.scene_.add(box);
  129. // const rbBox = new RigidBody();
  130. // rbBox.createBox(1, box.position, box.quaternion, new THREE.Vector3(4, 4, 4));
  131. // rbBox.setRestitution(0.25);
  132. // rbBox.setFriction(1);
  133. // rbBox.setRollingFriction(5);
  134. // this.physicsWorld_.addRigidBody(rbBox.body_);
  135. // this.rigidBodies_.push({mesh: box, rigidBody: rbBox});
  136. let isSphere = true;
  137. for (let x = -4; x < 4; ++x) {
  138. for (let y = -4; y < 4; ++y) {
  139. if (isSphere) {
  140. const box = new THREE.Mesh(
  141. new THREE.SphereGeometry(4),
  142. new THREE.MeshStandardMaterial({color: 0x808080}));
  143. box.position.set(x * 10, Math.random() * 20 + 40, y * 10);
  144. box.castShadow = true;
  145. box.receiveShadow = true;
  146. this.scene_.add(box);
  147. const rbBox = new RigidBody();
  148. rbBox.createSphere(1, box.position, 4);
  149. rbBox.setRestitution(0.5);
  150. rbBox.setFriction(1);
  151. rbBox.setRollingFriction(1);
  152. this.physicsWorld_.addRigidBody(rbBox.body_);
  153. this.rigidBodies_.push({mesh: box, rigidBody: rbBox});
  154. } else {
  155. const box = new THREE.Mesh(
  156. new THREE.BoxGeometry(4, 4, 4),
  157. new THREE.MeshStandardMaterial({color: 0x808080}));
  158. box.position.set(x * 10, Math.random() * 5 + 40, y * 10);
  159. box.castShadow = true;
  160. box.receiveShadow = true;
  161. this.scene_.add(box);
  162. const rbBox = new RigidBody();
  163. rbBox.createBox(1, box.position, box.quaternion, new THREE.Vector3(4, 4, 4));
  164. rbBox.setRestitution(0.25);
  165. rbBox.setFriction(1);
  166. rbBox.setRollingFriction(5);
  167. this.physicsWorld_.addRigidBody(rbBox.body_);
  168. this.rigidBodies_.push({mesh: box, rigidBody: rbBox});
  169. }
  170. isSphere = !isSphere;
  171. }
  172. }
  173. this.tmpTransform_ = new Ammo.btTransform();
  174. this.countdown_ = 1.0;
  175. this.count_ = 0;
  176. this.previousRAF_ = null;
  177. this.raf_();
  178. }
  179. onWindowResize_() {
  180. this.camera_.aspect = window.innerWidth / window.innerHeight;
  181. this.camera_.updateProjectionMatrix();
  182. this.threejs_.setSize(window.innerWidth, window.innerHeight);
  183. }
  184. raf_() {
  185. requestAnimationFrame((t) => {
  186. if (this.previousRAF_ === null) {
  187. this.previousRAF_ = t;
  188. }
  189. this.step_(t - this.previousRAF_);
  190. this.threejs_.render(this.scene_, this.camera_);
  191. this.raf_();
  192. this.previousRAF_ = t;
  193. });
  194. }
  195. spawn_() {
  196. const scale = Math.random() * 4 + 4;
  197. const box = new THREE.Mesh(
  198. new THREE.BoxGeometry(scale, scale, scale),
  199. new THREE.MeshStandardMaterial({
  200. color: 0x808080,
  201. }));
  202. box.position.set(Math.random() * 2 - 1, 200.0, Math.random() * 2 - 1);
  203. box.quaternion.set(0, 0, 0, 1);
  204. box.castShadow = true;
  205. box.receiveShadow = true;
  206. const rb = new RigidBody();
  207. rb.createBox(DEFAULT_MASS, box.position, box.quaternion, new THREE.Vector3(scale, scale, scale), null);
  208. rb.setRestitution(0.125);
  209. rb.setFriction(1);
  210. rb.setRollingFriction(5);
  211. this.physicsWorld_.addRigidBody(rb.body_);
  212. this.rigidBodies_.push({mesh: box, rigidBody: rb});
  213. this.scene_.add(box);
  214. }
  215. step_(timeElapsed) {
  216. const timeElapsedS = timeElapsed * 0.001;
  217. this.countdown_ -= timeElapsedS;
  218. if (this.countdown_ < 0 && this.count_ < 10) {
  219. this.countdown_ = 0.25;
  220. this.count_ += 1;
  221. this.spawn_();
  222. }
  223. this.physicsWorld_.stepSimulation(timeElapsedS, 10);
  224. for (let i = 0; i < this.rigidBodies_.length; ++i) {
  225. this.rigidBodies_[i].rigidBody.motionState_.getWorldTransform(this.tmpTransform_);
  226. const pos = this.tmpTransform_.getOrigin();
  227. const quat = this.tmpTransform_.getRotation();
  228. const pos3 = new THREE.Vector3(pos.x(), pos.y(), pos.z());
  229. const quat3 = new THREE.Quaternion(quat.x(), quat.y(), quat.z(), quat.w());
  230. this.rigidBodies_[i].mesh.position.copy(pos3);
  231. this.rigidBodies_[i].mesh.quaternion.copy(quat3);
  232. }
  233. }
  234. }
  235. let APP_ = null;
  236. window.addEventListener('DOMContentLoaded', async () => {
  237. Ammo().then((lib) => {
  238. Ammo = lib;
  239. APP_ = new BasicWorldDemo();
  240. APP_.initialize();
  241. });
  242. });