|
@@ -10,7 +10,7 @@ import { STLLoader } from 'three/addons/loaders/STLLoader.js'
|
10
|
10
|
import { VRMLLoader } from 'three/addons/loaders/VRMLLoader.js';
|
11
|
11
|
|
12
|
12
|
// https://wejn.org/2020/12/cracking-the-threejs-object-fitting-nut/
|
13
|
|
-function fitCameraToCenteredObject(camera, object, offset, orbitControls ) {
|
|
13
|
+function fitCameraToCenteredObject(camera, object, offset, orbitControls, yOffset) {
|
14
|
14
|
const boundingBox = new THREE.Box3();
|
15
|
15
|
boundingBox.setFromObject( object );
|
16
|
16
|
|
|
@@ -61,7 +61,7 @@ function fitCameraToCenteredObject(camera, object, offset, orbitControls ) {
|
61
|
61
|
// offset the camera, if desired (to avoid filling the whole canvas)
|
62
|
62
|
if( offset !== undefined && offset !== 0 ) cameraZ *= offset;
|
63
|
63
|
|
64
|
|
- camera.position.set( 0, 0, cameraZ );
|
|
64
|
+ camera.position.set( 0, yOffset * cameraZ, cameraZ );
|
65
|
65
|
|
66
|
66
|
// set the far plane of the camera so that it easily encompasses the whole object
|
67
|
67
|
const minZ = boundingBox.min.z;
|
|
@@ -86,15 +86,14 @@ export function init_3d(path, container, status, div_width, div_height) {
|
86
|
86
|
const scene = new THREE.Scene();
|
87
|
87
|
scene.add(new THREE.AxesHelper(1));
|
88
|
88
|
|
89
|
|
- const camera = new THREE.PerspectiveCamera( 75, width / height, 0.1, 1000 );
|
|
89
|
+ const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
|
90
|
90
|
|
91
|
91
|
const renderer = new THREE.WebGLRenderer();
|
92
|
|
- renderer.setSize( width, height );
|
|
92
|
+ renderer.setSize(width, height);
|
93
|
93
|
|
94
|
|
- container.appendChild( renderer.domElement );
|
95
|
|
-
|
96
|
|
- const controls = new OrbitControls( camera, renderer.domElement );
|
|
94
|
+ const controls = new OrbitControls(camera, renderer.domElement);
|
97
|
95
|
controls.enableDamping = true;
|
|
96
|
+ controls.autoRotate = true;
|
98
|
97
|
|
99
|
98
|
if (path.endsWith(".stl")) {
|
100
|
99
|
const light_amb = new THREE.AmbientLight(0x424242);
|
|
@@ -119,7 +118,7 @@ export function init_3d(path, container, status, div_width, div_height) {
|
119
|
118
|
function (geometry) {
|
120
|
119
|
const mesh = new THREE.Mesh(geometry, material);
|
121
|
120
|
scene.add(mesh);
|
122
|
|
- fitCameraToCenteredObject(camera, scene, 0, controls);
|
|
121
|
+ fitCameraToCenteredObject(camera, scene, 0, controls, 0);
|
123
|
122
|
},
|
124
|
123
|
(xhr) => {
|
125
|
124
|
const s = (xhr.loaded / xhr.total) * 100 + '% loaded';
|
|
@@ -140,7 +139,7 @@ export function init_3d(path, container, status, div_width, div_height) {
|
140
|
139
|
path,
|
141
|
140
|
function (object) {
|
142
|
141
|
scene.add(object);
|
143
|
|
- fitCameraToCenteredObject(camera, scene, 0, controls);
|
|
142
|
+ fitCameraToCenteredObject(camera, scene, 0, controls, 0);
|
144
|
143
|
},
|
145
|
144
|
(xhr) => {
|
146
|
145
|
const s = (xhr.loaded / xhr.total) * 100 + '% loaded';
|
|
@@ -159,17 +158,47 @@ export function init_3d(path, container, status, div_width, div_height) {
|
159
|
158
|
}
|
160
|
159
|
|
161
|
160
|
camera.position.z = 50;
|
162
|
|
-
|
163
|
|
- function render() {
|
164
|
|
- renderer.render(scene, camera);
|
165
|
|
- }
|
|
161
|
+ controls.update();
|
166
|
162
|
|
167
|
163
|
function animate() {
|
168
|
164
|
requestAnimationFrame(animate);
|
169
|
165
|
controls.update();
|
170
|
|
- render();
|
|
166
|
+ renderer.render(scene, camera);
|
171
|
167
|
}
|
172
|
168
|
|
173
|
169
|
animate();
|
174
|
170
|
status.textContent = "3D model ready!";
|
|
171
|
+
|
|
172
|
+ container.appendChild(renderer.domElement);
|
|
173
|
+
|
|
174
|
+ const div = document.createElement("div");
|
|
175
|
+ div.style.position = "absolute";
|
|
176
|
+ div.style.left = "5px";
|
|
177
|
+ div.style.top = "5px";
|
|
178
|
+ div.style.background = "white";
|
|
179
|
+ div.style.color = "black";
|
|
180
|
+ container.appendChild(div);
|
|
181
|
+
|
|
182
|
+ const chk_ar = document.createElement("input");
|
|
183
|
+ chk_ar.type = "checkbox";
|
|
184
|
+ chk_ar.checked = true;
|
|
185
|
+ chk_ar.addEventListener('change', function() {
|
|
186
|
+ controls.autoRotate = this.checked;
|
|
187
|
+ });
|
|
188
|
+
|
|
189
|
+ const div_ar = document.createElement("div");
|
|
190
|
+ div_ar.appendChild(chk_ar);
|
|
191
|
+ div_ar.appendChild(document.createTextNode("Auto-Rotate"));
|
|
192
|
+ div.appendChild(div_ar);
|
|
193
|
+
|
|
194
|
+ const btn_rst = document.createElement("input");
|
|
195
|
+ btn_rst.type = "button";
|
|
196
|
+ btn_rst.value = "Reset Camera";
|
|
197
|
+ btn_rst.addEventListener('click', function() {
|
|
198
|
+ fitCameraToCenteredObject(camera, scene, 0, controls, 0);
|
|
199
|
+ });
|
|
200
|
+
|
|
201
|
+ const div_rst = document.createElement("div");
|
|
202
|
+ div_rst.appendChild(btn_rst);
|
|
203
|
+ div.appendChild(div_rst);
|
175
|
204
|
}
|