-
Notifications
You must be signed in to change notification settings - Fork 21
Feat/add gltf previewer #608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,115 @@ | ||
| // TODO-EV | ||
| import * as THREE from "three"; | ||
| import { OrbitControls } from "three/addons/controls/OrbitControls.js"; | ||
| import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js"; | ||
|
|
||
| document.addEventListener("DOMContentLoaded", () => { | ||
| class ThreeScene { | ||
| constructor(config) { | ||
| this.config = config; | ||
| this.container = config.container; | ||
|
|
||
| this.scene = null; | ||
| this.camera = null; | ||
| this.renderer = null; | ||
| this.controls = null; | ||
| } | ||
|
|
||
| init() { | ||
| this.initScene(); | ||
| this.initCamera(); | ||
| this.initRenderer(); | ||
| this.initControls(); | ||
| this.addEventListeners(); | ||
| this.loadModel(); | ||
| this.startRendering(); | ||
| } | ||
|
|
||
| initScene() { | ||
| this.scene = new THREE.Scene(); | ||
| } | ||
|
|
||
| initCamera() { | ||
| const { camera_x, camera_y, camera_z } = this.config; | ||
| const width = window.innerWidth; | ||
| const height = window.innerHeight; | ||
|
|
||
| this.camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 1000); | ||
| this.camera.position.set(camera_x, camera_y, camera_z); | ||
| } | ||
|
|
||
| initRenderer() { | ||
| this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); | ||
| this.renderer.setPixelRatio(window.devicePixelRatio || 1); | ||
| this.renderer.setClearColor(this.config.background, 1); | ||
| this.renderer.setSize(window.innerWidth, window.innerHeight); | ||
| this.container.appendChild(this.renderer.domElement); | ||
| } | ||
|
|
||
| initControls() { | ||
| this.controls = new OrbitControls(this.camera, this.renderer.domElement); | ||
| this.controls.zoomSpeed = 0.5; | ||
| } | ||
|
|
||
| addEventListeners() { | ||
| window.addEventListener("resize", () => { | ||
| const width = window.innerWidth; | ||
| const height = window.innerHeight; | ||
|
|
||
| this.camera.aspect = width / height; | ||
| this.camera.updateProjectionMatrix(); | ||
| this.renderer.setSize(width, height); | ||
| }); | ||
| } | ||
|
|
||
| loadModel() { | ||
| const loader = new GLTFLoader(); | ||
| const { fileURI } = this.config; | ||
|
|
||
| const progressBar = document.getElementById("progress"); | ||
| const percentText = document.getElementById("percent"); | ||
|
Comment on lines
+68
to
+69
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be slightly precarious in case we happen to have other elements with these IDs on the page as they're quite generic. Maybe we could use more specific names, e.g. |
||
|
|
||
| if (progressBar) progressBar.style.visibility = "visible"; | ||
|
|
||
| loader.load( | ||
| fileURI, | ||
| (gltf) => { | ||
| this.scene.add(gltf.scene); | ||
| if (progressBar) progressBar.style.visibility = "hidden"; | ||
| if (percentText) percentText.textContent = ""; | ||
| }, | ||
| (xhr) => { | ||
| if (percentText && xhr.total) { | ||
| const percentComplete = Math.round((xhr.loaded / xhr.total) * 100); | ||
| percentText.textContent = `${percentComplete}`; | ||
| console.debug(`${percentComplete}% loaded`); | ||
| } | ||
| }, | ||
| (error) => { | ||
| console.error("An error occurred loading the GLB file:", error); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this show a visible error to the user? E.g. if the user is on an unstable network it's quite likely that the load would fail so we should make sure it's communicated clearly |
||
| } | ||
| ); | ||
| } | ||
|
|
||
| startRendering() { | ||
| const renderLoop = () => { | ||
| requestAnimationFrame(renderLoop); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we move this to the end of |
||
| this.controls.update(); | ||
| this.renderer.render(this.scene, this.camera); | ||
| }; | ||
| renderLoop(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also the official recommendation is to use
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. e.g. see the "Rendering the scene" example: https://threejs.org/manual/#en/creating-a-scene |
||
| } | ||
| } | ||
|
|
||
| // Configuration | ||
| const config = { | ||
| container: document.getElementById("container"), | ||
| background: 0x000000, | ||
| camera_x: 5, | ||
| camera_y: 5, | ||
| camera_z: 10, | ||
| fileURI: document.getElementById("gltf-previewer").getAttribute("data-file-uri"), | ||
| }; | ||
|
|
||
| const app = new ThreeScene(config); | ||
| app.init(); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,17 @@ | ||
| // TODO-EV | ||
| #gltf-previewer { | ||
| canvas { | ||
| width: 100%; | ||
| height: 100%; | ||
| } | ||
|
|
||
| #progress { | ||
| border: none; | ||
| position: absolute; | ||
| text-align: center; | ||
| top: 50%; | ||
| width: 100%; | ||
| padding: 5px; | ||
| color: white; | ||
| visibility: hidden; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ | |
| from invenio_previewer.proxies import current_previewer | ||
| from invenio_previewer.utils import dotted_exts | ||
|
|
||
| previewable_extensions = ["gltf"] | ||
| previewable_extensions = ["glb", "gltf"] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to get all the possible extensions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a necessary addition. The GLTFLoader of three.js handles both transparently. |
||
|
|
||
|
|
||
| def can_preview(file): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,10 @@ | |
| "gltf_previewer_js": "./js/cds_rdm/previewers/gltf-previewer.js", | ||
| "gltf_previewer_css": "./less/cds_rdm/previewers/gltf-previewer.less", | ||
| }, | ||
| dependencies={ | ||
| "three": "^0.180.0", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was just updated to |
||
| "three-addons": "^1.2.0", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if there's any alternative but this was archived in 2021 and last publish 7 years ago. https://github.com/marcofugaro/three-addons.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I saw it, however, I am a big fan of code that does not change and it works :) |
||
| }, | ||
| ), | ||
| }, | ||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe could we declare the class outside of the event handler and call just create + init the app inside it? The class not being top-level looks a little unusual
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can, but I don't think it will make any difference: I really hope that
DOMContentLoadedis fired only once! I will move it.