No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3d.js 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import * as THREE from 'three';
  2. import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
  3. import { STLLoader } from 'three/addons/loaders/STLLoader.js'
  4. import { VRMLLoader } from 'three/addons/loaders/VRMLLoader.js';
  5. export function init_3d(path, container, status, div_width, div_height) {
  6. const width = div_width;
  7. const height = div_height;
  8. const scene = new THREE.Scene();
  9. scene.add(new THREE.AxesHelper(1));
  10. const camera = new THREE.PerspectiveCamera( 75, width / height, 0.1, 1000 );
  11. const renderer = new THREE.WebGLRenderer();
  12. renderer.setSize( width, height );
  13. container.appendChild( renderer.domElement );
  14. const light = new THREE.DirectionalLight( 0xffffff, 0.5 );
  15. light.position.set(0, 1, 0);
  16. scene.add(light);
  17. const light42 = new THREE.DirectionalLight( 0xffffff, 0.5 );
  18. light42.position.set(1, 0, 0);
  19. scene.add(light42);
  20. const light23 = new THREE.DirectionalLight( 0xffffff, 0.5 );
  21. light23.position.set(0, 0, 1);
  22. scene.add(light23);
  23. const lightb = new THREE.DirectionalLight( 0xffffff, 0.5 );
  24. lightb.position.set(0, -1, 0);
  25. scene.add(lightb);
  26. const light42b = new THREE.DirectionalLight( 0xffffff, 0.5 );
  27. light42b.position.set(-1, 0, 0);
  28. scene.add(light42b);
  29. const light23b = new THREE.DirectionalLight( 0xffffff, 0.5 );
  30. light23b.position.set(0, 0, -1);
  31. scene.add(light23b);
  32. const light2 = new THREE.AmbientLight(0x101010);
  33. light2.position.set(100, 100, 100);
  34. scene.add(light2);
  35. const material = new THREE.MeshStandardMaterial();
  36. //material.roughness = 0.42;
  37. if (path.endsWith(".stl")) {
  38. const loader = new STLLoader();
  39. loader.load(
  40. //'plot/actuator_all.stl',
  41. path,
  42. function (geometry) {
  43. const mesh = new THREE.Mesh(geometry, material);
  44. scene.add(mesh);
  45. },
  46. (xhr) => {
  47. const s = (xhr.loaded / xhr.total) * 100 + '% loaded';
  48. console.log(s);
  49. status.textContent = s;
  50. },
  51. (error) => {
  52. console.log(error);
  53. status.textContent = error;
  54. }
  55. );
  56. } else if (path.endsWith(".wrl")) {
  57. const loader = new VRMLLoader();
  58. loader.load(
  59. //'plot/drumkit.kicad_pcb.wrl',
  60. //'plot/dispensy.wrl',
  61. path,
  62. function (object) {
  63. scene.add(object);
  64. });
  65. } else {
  66. const s = "error: unknown filetype for " + path;
  67. console.log(s);
  68. status.textContent = s;
  69. }
  70. const controls = new OrbitControls( camera, renderer.domElement );
  71. controls.enableDamping = true;
  72. // https://wejn.org/2020/12/cracking-the-threejs-object-fitting-nut/
  73. const fitCameraToCenteredObject = function (camera, object, offset, orbitControls ) {
  74. const boundingBox = new THREE.Box3();
  75. boundingBox.setFromObject( object );
  76. var middle = new THREE.Vector3();
  77. var size = new THREE.Vector3();
  78. boundingBox.getSize(size);
  79. // figure out how to fit the box in the view:
  80. // 1. figure out horizontal FOV (on non-1.0 aspects)
  81. // 2. figure out distance from the object in X and Y planes
  82. // 3. select the max distance (to fit both sides in)
  83. //
  84. // The reason is as follows:
  85. //
  86. // Imagine a bounding box (BB) is centered at (0,0,0).
  87. // Camera has vertical FOV (camera.fov) and horizontal FOV
  88. // (camera.fov scaled by aspect, see fovh below)
  89. //
  90. // Therefore if you want to put the entire object into the field of view,
  91. // you have to compute the distance as: z/2 (half of Z size of the BB
  92. // protruding towards us) plus for both X and Y size of BB you have to
  93. // figure out the distance created by the appropriate FOV.
  94. //
  95. // The FOV is always a triangle:
  96. //
  97. // (size/2)
  98. // +--------+
  99. // | /
  100. // | /
  101. // | /
  102. // | F° /
  103. // | /
  104. // | /
  105. // | /
  106. // |/
  107. //
  108. // F° is half of respective FOV, so to compute the distance (the length
  109. // of the straight line) one has to: `size/2 / Math.tan(F)`.
  110. //
  111. // FTR, from https://threejs.org/docs/#api/en/cameras/PerspectiveCamera
  112. // the camera.fov is the vertical FOV.
  113. const fov = camera.fov * ( Math.PI / 180 );
  114. const fovh = 2*Math.atan(Math.tan(fov/2) * camera.aspect);
  115. let dx = size.z / 2 + Math.abs( size.x / 2 / Math.tan( fovh / 2 ) );
  116. let dy = size.z / 2 + Math.abs( size.y / 2 / Math.tan( fov / 2 ) );
  117. let cameraZ = Math.max(dx, dy);
  118. // offset the camera, if desired (to avoid filling the whole canvas)
  119. if( offset !== undefined && offset !== 0 ) cameraZ *= offset;
  120. camera.position.set( 0, 0, cameraZ );
  121. // set the far plane of the camera so that it easily encompasses the whole object
  122. const minZ = boundingBox.min.z;
  123. const cameraToFarEdge = ( minZ < 0 ) ? -minZ + cameraZ : cameraZ - minZ;
  124. camera.far = cameraToFarEdge * 3;
  125. camera.updateProjectionMatrix();
  126. if ( orbitControls !== undefined ) {
  127. // set camera to rotate around the center
  128. orbitControls.target = new THREE.Vector3(0, 0, 0);
  129. // prevent camera from zooming out far enough to create far plane cutoff
  130. orbitControls.maxDistance = cameraToFarEdge * 2;
  131. }
  132. };
  133. //camera.position.z = 50;
  134. fitCameraToCenteredObject(camera, scene, 0, controls)
  135. function render() {
  136. renderer.render(scene, camera);
  137. }
  138. function animate() {
  139. requestAnimationFrame(animate);
  140. controls.update();
  141. render();
  142. }
  143. animate();
  144. status.textContent = "3D model ready!";
  145. }