66 < meta charset ="utf-8 ">
77 < meta name ="viewport " content ="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0 ">
88 <!-- <link type="text/css" rel="stylesheet" href="main.css"> -->
9+ < style >
10+ html , body {
11+ margin : 0 ;
12+ }
13+ # overlay {
14+ position : absolute;
15+ top : 0 ;
16+ left : 0 ;
17+ width : 100% ;
18+ color : # FFFFFF ;
19+ padding : 0 1em ;
20+ }
21+ </ style >
922</ head >
1023
1124< body >
12- < div >
13- < h1 > Prototype Viewer MediaWiki 3D GLTF Data, STL data is already available </ h1 >
14- < select id ="selection " onchange ="loadSelection() ">
15- < option value =""> Please choose a model</ option >
16- < option value ="3Ddata.glb "> GLB Lion Cologne Zoo - https://codeforcologne.github.io/Denkmal-4D-Koeln/
17- </ option >
18- < option value ="stl_lion.stl "> STL Lion Cologne Zoo - https://codeforcologne.github.io/Denkmal-4D-Koeln/
19- </ option >
20- < option value ="ganesha.glb "> GLB Ganesha Cologne Zoo - https://codeforcologne.github.io/Denkmal-4D-Koeln/
21- </ option >
22- < option value ="ganesha_stl.stl "> STL Ganesha Cologne Zoo - https://codeforcologne.github.io/Denkmal-4D-Koeln/
23- </ option >
24- < option value ="3D_Model_Hydria.stl "> STL Hydria -https://commons.wikimedia.org/wiki/File:3D_Model_Hydria.stl
25- </ option >
26- < option value ="3D_model_of_an_African_elephant.stl "> STL African_elephant
27- -https://commons.wikimedia.org/wiki/File:3D_model_of_an_African_elephant.stl</ option >
28- < option value ="Avocado.glb "> GLB Avocado - KhronosGroup Models Testing</ option >
29- < option value ="BarramundiFish.glb "> GLB BarramundiFish - KhronosGroup Models Testing</ option >
30- < option value ="LightsPunctualLamp.glb "> LightsPunctualLamp - KhronosGroup Models Testing</ option >
31- < option value ="Duck.glb "> GLB Duck - KhronosGroup Models Testing</ option >
32- < option value ="NodePerformanceTest.glb "> Wait a little bit! NodePerformanceTest - KhronosGroup Models Testing
33- </ option >
34- < option value ="NodePerformanceTest_opt.glb "> Wait a little bit! NodePerformanceTest - Optimized with
35- gltf-transform -
36- KhronosGroup Models Testing
37- </ option >
38- < option value ="grinkopf.glb "> Wait a little bit! Grinkopf Cologne -
39- https://codeforcologne.github.io/Denkmal-4D-Koeln/</ option >
40- < option value ="grinkopf_opt.glb "> Grinkopf Cologne - Optimized with gltf-transform
41- https://codeforcologne.github.io/Denkmal-4D-Koeln/</ option >
42- < option value ="coffeemat.glb "> GLB coffeemat with KTX2 cpmpression - KhronosGroup Models Testing</ option >
25+ < div id ="overlay ">
26+ < h1 > Prototype Viewer MediaWiki 3D</ h1 >
27+ < p > GLTF and STL formats are supported</ p >
28+ < select id ="selection " onchange ="loadSelection() " placeholder ="Please choose a model ">
29+ < option value ="" disabled selected > Please choose a model</ option >
30+ < optgroup label ="STL ">
31+ < option value ="stl_lion.stl "> Lion Cologne Zoo - https://codeforcologne.github.io/Denkmal-4D-Koeln/
32+ </ option >
33+ < option value ="ganesha_stl.stl "> Ganesha Cologne Zoo - https://codeforcologne.github.io/Denkmal-4D-Koeln/
34+ </ option >
35+ < option value ="3D_Model_Hydria.stl "> Hydria -https://commons.wikimedia.org/wiki/File:3D_Model_Hydria.stl
36+ </ option >
37+ < option value ="3D_model_of_an_African_elephant.stl "> African_elephant
38+ -https://commons.wikimedia.org/wiki/File:3D_model_of_an_African_elephant.stl
39+ </ option >
40+ </ optgroup >
41+ < optgroup label ="GLB ">
42+ < option value ="3Ddata.glb "> Lion Cologne Zoo - https://codeforcologne.github.io/Denkmal-4D-Koeln/
43+ </ option >
44+ < option value ="ganesha.glb "> Ganesha Cologne Zoo - https://codeforcologne.github.io/Denkmal-4D-Koeln/
45+ </ option >
46+ < option value ="Avocado.glb "> Avocado - KhronosGroup Models Testing</ option >
47+ < option value ="BarramundiFish.glb "> BarramundiFish - KhronosGroup Models Testing</ option >
48+ < option value ="LightsPunctualLamp.glb "> LightsPunctualLamp - KhronosGroup Models Testing</ option >
49+ < option value ="Duck.glb "> Duck - KhronosGroup Models Testing</ option >
50+ < option value ="NodePerformanceTest.glb "> Wait a little bit! NodePerformanceTest - KhronosGroup Models Testing
51+ </ option >
52+ < option value ="NodePerformanceTest_opt.glb "> Wait a little bit! NodePerformanceTest - Optimized with
53+ gltf-transform -
54+ KhronosGroup Models Testing
55+ </ option >
56+ < option value ="grinkopf.glb "> Wait a little bit! Grinkopf Cologne -
57+ https://codeforcologne.github.io/Denkmal-4D-Koeln/</ option >
58+ < option value ="grinkopf_opt.glb "> Grinkopf Cologne - Optimized with gltf-transform
59+ https://codeforcologne.github.io/Denkmal-4D-Koeln/</ option >
60+ < option value ="coffeemat.glb "> coffeemat with KTX2 cpmpression - KhronosGroup Models Testing</ option >
61+ </ optgroup >
4362 </ select >
4463 < button id ="uploadButton "> Upload a file</ button >
4564 < p > Only simple GLB Models and KTX2 commpersion is supported</ p >
@@ -57,10 +76,10 @@ <h1>Prototype Viewer MediaWiki 3D GLTF Data, STL data is already available </h1>
5776 loadFileViaFileAPI ( ( contents , fileName ) => {
5877 if ( fileName . toLowerCase ( ) . endsWith ( '.stl' ) ) {
5978 modeltype = 'stl' ;
60- TD . initSTL ( contents , 'browser' ) ;
79+ TD . init ( contents , 'browser' ) ;
6180 } else if ( fileName . toLowerCase ( ) . endsWith ( '.glb' ) ) {
6281 modeltype = 'glb' ;
63- TD . initGLB ( contents , 'browser' ) ;
82+ TD . init ( contents , 'browser' ) ;
6483 } else {
6584 console . error ( 'Unsupported file type' ) ;
6685 }
@@ -101,11 +120,11 @@ <h1>Prototype Viewer MediaWiki 3D GLTF Data, STL data is already available </h1>
101120 var selection = document . getElementById ( "selection" ) . value ;
102121 if ( selection . indexOf ( 'glb' ) > - 1 ) {
103122 modeltype = 'glb' ;
104- TD . initGLB ( selection , 'server' ) ;
123+ TD . init ( selection , 'server' ) ;
105124 }
106125 if ( selection . indexOf ( 'stl' ) > - 1 ) {
107126 modeltype = 'stl' ;
108- TD . initSTL ( selection , 'server' ) ;
127+ TD . init ( selection , 'server' ) ;
109128 }
110129 }
111130
@@ -125,47 +144,8 @@ <h1>Prototype Viewer MediaWiki 3D GLTF Data, STL data is already available </h1>
125144
126145 const TD = ThreeD . prototype ;
127146
128- TD . getBoxSizeCenter = function ( object ) {
129- // compute the box that contains the object (and objects in the graph below)
130- const box = new THREE . Box3 ( ) . setFromObject ( object ) ;
131- const size = box . getSize ( new THREE . Vector3 ( ) ) . length ( ) ;
132- const center = box . getCenter ( new THREE . Vector3 ( ) ) ;
133- console . log ( size ) ;
134- console . log ( center ) ;
135- return { size, center } ;
136-
137- } ;
138-
139- TD . moveCamera = function ( sizeToFitOnScreen , boxSize , boxCenter , camera ) {
140- const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5 ;
141- const halfFovY = THREE . MathUtils . degToRad ( camera . fov * 0.5 ) ;
142- const distance = halfSizeToFitOnScreen / Math . tan ( halfFovY ) ;
143147
144- // compute a unit vector that points in the direction the camera is now
145- // in hte xz plane from the center of the box
146- const direction = new THREE . Vector3 ( )
147- . subVectors ( camera . position , boxCenter )
148- . multiply ( new THREE . Vector3 ( 1 , 0 , 1 ) )
149- . normalize ( ) ;
150-
151- // move the camera to a position distance units way from the center
152- // in whatever direction the camera was from the center already
153- // for the screenshots, it is good not too be too far away
154- camera . position . copy ( direction . multiplyScalar ( distance + 3 ) . add ( boxCenter ) ) ;
155-
156- // pick some near and far values for the frustum that
157- // will contain the box.
158- camera . near = boxSize / 100 ; // eslint-disable-line no-param-reassign
159- camera . far = boxSize * 100 ; // eslint-disable-line no-param-reassign
160-
161- camera . updateProjectionMatrix ( ) ;
162-
163- // point the camera to look at the center of the box
164- camera . lookAt ( boxCenter . x , boxCenter . y , boxCenter . z ) ;
165- } ;
166-
167-
168- TD . initSTL = function ( model , source ) {
148+ TD . init = function ( model , source ) {
169149
170150 this . modeltype = modeltype ;
171151
@@ -187,8 +167,7 @@ <h1>Prototype Viewer MediaWiki 3D GLTF Data, STL data is already available </h1>
187167 document . getElementById ( 'container' ) . appendChild ( this . renderer . domElement ) ;
188168 this . manager = new THREE . LoadingManager ( ) ;
189169 // camera
190- this . camera = new THREE . PerspectiveCamera ( 60 , dimensions . ratio , 0.001 , 500000 ) ;
191- this . camera . up . set ( 0 , 0 , 1 ) ;
170+ this . camera = new THREE . PerspectiveCamera ( 60 , dimensions . ratio ) ;
192171 // controls
193172 this . controls = new THREE . TrackballControls ( this . camera , this . renderer . domElement ) ;
194173 this . controls . rotateSpeed = 2 ;
@@ -202,82 +181,65 @@ <h1>Prototype Viewer MediaWiki 3D GLTF Data, STL data is already available </h1>
202181 const environment = new THREE . RoomEnvironment ( this . renderer ) ;
203182 const pmremGenerator = new THREE . PMREMGenerator ( this . renderer ) ;
204183 this . scene = new THREE . Scene ( ) ;
205- //this.scene.background = new THREE.Color(0xbbbbbb);
206- this . scene . background = new THREE . Color ( 0x0000000 ) ;
207184 this . scene . environment = pmremGenerator . fromScene ( environment ) . texture ;
208185 environment . dispose ( ) ;
209- TD . load ( 'stl' , model , source ) ;
186+ TD . load ( this . modeltype , model , source ) ;
210187
211188 } ;
212189
190+ TD . stageContent = function ( object ) {
191+ // Ensure all transform matrices are up to date.
192+ object . updateMatrixWorld ( ) ;
213193
214- TD . initGLB = function ( model , source ) {
215- this . modeltype = modeltype ;
216- if ( document . getElementById ( 'container' ) ) {
194+ // Compute axis-aligned bounding box (AABB) and center (x, y, z) in
195+ // world space. Size, defined here as a cheap approximation of
196+ // model's maximum span in any direction, is computed from the AABB.
197+ const box = new THREE . Box3 ( ) . setFromObject ( object ) ;
198+ const center = box . getCenter ( new THREE . Vector3 ( ) ) ;
199+ const size = box . getSize ( new THREE . Vector3 ( ) ) . length ( ) ;
217200
218- this . scene . clear ( ) ;
219- const child = document . getElementById ( 'container' ) ;
220- document . body . removeChild ( child ) ;
201+ // Center content at the origin, (0, 0, 0).
202+ object . position . x -= center . x ;
203+ object . position . y -= center . y ;
204+ object . position . z -= center . z ;
205+
206+ // In glTF, +Y=Up is required. In STL it's unclear, but for backward-
207+ // compatibility we keep +Z=Up. Because some three.js features assume
208+ // +Y=Up, apply a +Z to +Y conversion for STL.
209+ if ( this . modeltype === 'stl' ) {
210+ const parent = new THREE . Object3D ( ) ;
211+ parent . rotation . set ( - Math . PI / 2 , 0 , 0 ) ;
212+ parent . add ( object ) ;
213+ object = parent ;
221214 }
222- container = document . createElement ( 'div' ) ;
223- container . id = 'container' ;
224- document . body . appendChild ( container ) ;
225- const dimensions = this . getDimensions ( ) ;
226- // renderer
227- this . renderer = new THREE . WebGLRenderer ( { antialias : true } ) ;
228- // this.renderer.setClearColor(0x222222);
229- this . renderer . setPixelRatio ( window . devicePixelRatio ) ;
230- this . renderer . setSize ( dimensions . width , dimensions . height ) ;
231- this . renderer . shadowMap . enabled = true ;
232- document . getElementById ( 'container' ) . appendChild ( this . renderer . domElement ) ;
233- // camera
234- this . camera = new THREE . PerspectiveCamera ( 60 , dimensions . ratio , 0.001 , 500000 ) ;
235- //this.camera.up.set(0, 0, 1);
236- // controls
237- this . controls = new THREE . TrackballControls ( this . camera , this . renderer . domElement ) ;
238- this . controls . rotateSpeed = 2 ;
239- this . controls . zoomSpeed = 2 ;
240- this . controls . panSpeed = 0.5 ;
241- this . controls . addEventListener ( 'change' , this . render . bind ( this ) ) ;
242- this . controls . addEventListener ( 'start' , this . controlsStart . bind ( this ) ) ;
243- this . controls . addEventListener ( 'end' , this . controlsEnd . bind ( this ) ) ;
244- // Scene and RoomEnvironment
245- const environment = new THREE . RoomEnvironment ( this . renderer ) ;
246- const pmremGenerator = new THREE . PMREMGenerator ( this . renderer ) ;
247- this . scene = new THREE . Scene ( ) ;
248- this . scene . background = new THREE . Color ( 0xbbbbbb ) ;
249- //this.scene.background = new THREE.Color(0x0000000);
250- this . scene . environment = pmremGenerator . fromScene ( environment ) . texture ;
251- environment . dispose ( ) ;
252- TD . load ( 'glb' , model , source ) ;
253- } ;
254215
216+ // Prevent controls from dollying out farther than 10x size.
217+ this . controls . maxDistance = size * 10 ;
255218
256- TD . center = function ( object , modeltype ) {
257-
258- if ( modeltype === 'stl' ) {
259- if ( object . type === 'Group' ) {
260- this . center ( object . children [ 0 ] , 'stl' ) ;
261- } else if ( object . type === 'Mesh' ) {
262- object . geometry . center ( ) ;
263- object . geometry . computeBoundingSphere ( ) ;
264-
265- const radius = object . geometry . boundingSphere . radius ;
266-
267- // `radius` is the edge of the object's sphere
268- // We want to position our camera outside of that sphere.
269- // We'll move `radius` (or more) in all directions (x, y, z), so that we're
270- // looking at the object somewhat diagonally, which should always show something
271- // useful (instead of possibly an uninteresting side or top...)
272- // The exact position of the camera was arbitrarily decided by what looked
273- // alright-ish for a few files I was testing with.
274- // sketchfab.com has this at ( 0, -distance, 0 )
275- // viewstl.com has this at ( 0, 0 distance )
276- // openjscad.org has this at ( 0, -distance, distance )
277- // thingiverse.com has this at ( -distance, -distance, distance )
278- this . camera . position . set ( - radius * 1.5 , - radius * 1.5 , radius ) ;
279- }
280- }
219+ // Constrain camera near and far planes to factors of size. Planes
220+ // should fit the content tightly enough that depth buffer
221+ // precision is utilized well, but not so tight that the model
222+ // clips the near/far planes easily while interacting with controls.
223+ this . camera . near = size / 100 ;
224+ this . camera . far = size * 100 ;
225+ this . camera . updateProjectionMatrix ( ) ;
226+
227+ // Default viewing angle is arbitrary and subjective, some models
228+ // may benefit from a more top-down or front-facing perspective. To
229+ // split the difference somewhat, we use a diagonal. Comparisons:
230+ // sketchfab.com: ( 0, -distance, 0 )
231+ // viewstl.com: ( 0, 0 distance )
232+ // openjscad.org: ( 0, -distance, distance )
233+ // thingiverse.com: ( -distance, -distance, distance )
234+ this . camera . position . x += size * 0.75 ;
235+ this . camera . position . y += size * 0.5 ;
236+ this . camera . position . z += size * 0.75 ;
237+
238+ // Rotate the camera to look at the object's center, (0, 0, 0).
239+ this . camera . lookAt ( object . position ) ;
240+
241+ // Add content to scene.
242+ this . scene . add ( object ) ;
281243 } ;
282244
283245
@@ -338,42 +300,25 @@ <h1>Prototype Viewer MediaWiki 3D GLTF Data, STL data is already available </h1>
338300 // this.progressBar.animateTo(5);
339301 this . promise . then ( ( object ) => {
340302 delete this . promise ;
341- // check for GLB
342- if ( this . modeltype === 'glb' ) {
343-
344- object . scene . traverse ( function ( node ) {
345- console . log ( node ) ;
346- if ( node . material ) {
347- node . material . side = THREE . DoubleSide ;
348- }
349- if ( node . mesh ) {
350- node . castShadow = true ;
351- node . receiveShadow = true ;
352- }
353-
354- } ) ;
355- // Add the model to the scene
356- this . scene . add ( object . scene ) ;
357- // move camera
358- let box = this . getBoxSizeCenter ( object . scene ) ;
359- this . moveCamera ( box . size * 0.5 , box . size , box . center , this . camera ) ;
360- this . controls . maxDistance = box . size * 10 ;
361- this . controls . target . copy ( box . center ) ;
362- this . controls . update ( ) ;
363- }
364303
365- if ( this . modeltype === 'stl' ) {
366- // this.progressBar.hide();
367- object . castShadow = true ;
368- object . receiveShadow = true ;
369- this . center ( object , 'stl' ) ;
370- this . scene . add ( object ) ;
371- this . camera . lookAt ( this . scene . position ) ;
372- }
304+ // this.progressBar.hide();
305+
306+ const content = this . modeltype === 'glb' ? object . scene : object ;
307+
308+ // STL contains a single mesh, GLB may contain more. Traverse
309+ // to handle both cases.
310+ content . traverse ( function ( node ) {
311+ if ( node . isMesh ) {
312+ node . castShadow = true ;
313+ node . receiveShadow = true ;
314+ }
315+ } ) ;
316+
317+ this . stageContent ( content ) ;
318+
373319 container . appendChild ( this . renderer . domElement ) ;
374320 TD . animate ( ) ;
375321
376-
377322 // mw.threed.base.wrap(this.$container);
378323 } ) . progress ( ( progress ) => {
379324 // this.progressBar.animateTo(progress);
@@ -479,10 +424,10 @@ <h1>Prototype Viewer MediaWiki 3D GLTF Data, STL data is already available </h1>
479424
480425
481426 if ( modeltype === 'glb' ) {
482- TD . initGLB ( 'ganesha.glb' , 'server' ) ;
427+ TD . init ( 'ganesha.glb' , 'server' ) ;
483428 }
484429 if ( modeltype === 'stl' ) {
485- TD . initSTL ( '3D_Model_Hydria.stl' , 'server' ) ;
430+ TD . init ( '3D_Model_Hydria.stl' , 'server' ) ;
486431 }
487432
488433
0 commit comments