From 0e2089bf4d9e7b01b85062955b3a5915262a5301 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 17 Sep 2025 20:00:25 -0400 Subject: [PATCH] LODs load --- app/api/tasks.py | 2 + app/models/task.py | 2 +- app/static/app/js/ModelView.jsx | 80 +++++++++++++++++++++++---------- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/app/api/tasks.py b/app/api/tasks.py index 12b1a3e4..a90d829f 100644 --- a/app/api/tasks.py +++ b/app/api/tasks.py @@ -762,6 +762,8 @@ class TaskTexturedModelLOD(TaskNestedView): try: lod_file = task.get_textured_model_lod(lod) + import time + time.sleep(3) return download_file_response(request, lod_file, 'attachment') except FileNotFoundError: raise exceptions.NotFound(_("Asset does not exist")) diff --git a/app/models/task.py b/app/models/task.py index ca29657f..e1c481fd 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -1535,7 +1535,7 @@ class Task(models.Model): "--input", quote(input_glb), "--output", quote(output_glb_tmp), "--texture-size", str(tex_size), - "--simplify-ratio", str(simplify_ratio)]) + "--simplify-ratio", str(simplify_ratio)], timeout=180) if not os.path.isfile(output_glb_tmp): raise FileNotFoundError("LOD generation failed") diff --git a/app/static/app/js/ModelView.jsx b/app/static/app/js/ModelView.jsx index 7b932298..b765dad2 100644 --- a/app/static/app/js/ModelView.jsx +++ b/app/static/app/js/ModelView.jsx @@ -152,10 +152,11 @@ class ModelView extends React.Component { error: "", showingTexturedModel: false, initializingModel: false, + currentLod: 3, + currentLodSize: -1, selectedCamera: null, modalOpen: false }; - this.pointCloud = null; this.modelReference = null; @@ -683,10 +684,11 @@ class ModelView extends React.Component { this.initGltfLoader(); // Load a glTF resource + let bytesSize = -1; this.gltfLoader.load(url, - gltf => { cb(null, gltf) }, + gltf => { cb(null, gltf, bytesSize) }, xhr => { - console.log(xhr.target.getAllResponseHeaders()); + bytesSize = xhr.total; }, error => { cb(error); }, {crop: this.getCropCoordinates()} @@ -697,28 +699,38 @@ class ModelView extends React.Component { const value = e.target.checked; if (value){ - // Need to load model for the first time? - if (this.modelReference === null && !this.state.initializingModel){ + this.setState({showingTexturedModel: true}); + this.state.showingTexturedModel = true; // Don't wait for react - this.setState({initializingModel: true}); + const addReplaceObject = (object, offset) => { + object.translateX(offset.x); + object.translateY(offset.y); - const addObject = (object, offset) => { - object.translateX(offset.x); - object.translateY(offset.y); - - viewer.scene.scene.add(object); - - this.modelReference = object; + // Swap if needed + if (this.modelReference !== null){ + viewer.scene.scene.remove(this.modelReference); + } + this.modelReference = object; + viewer.scene.scene.add(object); + + if (this.state.showingTexturedModel){ this.setPointCloudsVisible(false); - - this.setState({ - initializingModel: false, - showingTexturedModel: true - }); + object.visible = true; + }else{ + this.setPointCloudsVisible(true); + object.visible = false; } - if (this.getTexturedModelType() === 'gltf'){ - this.loadProgressiveGltf(this.glbFilePath(3), (err, gltf) => { + this.setState({ + initializingModel: false + }); + } + + const loadLOD = (lod) => { + const LOD_MAX_SIZE = 1024 * 1024 * 90; // MB + if (lod >= 0 && (this.state.currentLodSize === -1 || this.state.currentLodSize < LOD_MAX_SIZE) && this.state.showingTexturedModel){ + // console.log("Loading LOD ", lod) + this.loadProgressiveGltf(this.glbFilePath(lod), (err, gltf, bytesSize) => { if (err){ this.setState({initializingModel: false, error: err}); return; @@ -730,8 +742,26 @@ class ModelView extends React.Component { offset.y = gltf.scene.CESIUM_RTC.center[1]; } - addObject(gltf.scene, offset); + addReplaceObject(gltf.scene, offset); + + this.setState({currentLod: lod, currentLodSize: bytesSize}); + + // Load next LOD if needed + loadLOD(lod - 1); }); + }else{ + // console.log("Done loading LODs"); + } + }; + + const isGltf = this.getTexturedModelType() === 'gltf'; + + // Need to load model for the first time? + if (this.modelReference === null && !this.state.initializingModel){ + this.setState({initializingModel: true}); + + if (isGltf){ + loadLOD(this.state.currentLod); }else{ // Legacy OBJ @@ -747,7 +777,7 @@ class ModelView extends React.Component { this.objFilePath(filePath => { objLoader.load(filePath, (object) => { this.loadGeoreferencingOffset((offset) => { - addObject(object, offset); + addReplaceObject(object, offset); }); }); }); @@ -758,7 +788,11 @@ class ModelView extends React.Component { // Already initialized this.modelReference.visible = true; this.setPointCloudsVisible(false); - this.setState({showingTexturedModel: true}); + + if (isGltf){ + // Load next LOD if needed + loadLOD(this.state.currentLod - 1); + } } }else{ this.modelReference.visible = false;