Feat: Gaussian Splatting - #2017
Merged
Merged
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The current implementation contains a confirmed chunked-upload corruption bug and multiple insecure temporary-file creation sites that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds end-to-end Gaussian Splatting support to WebODM: exporting COLMAP-style training data, uploading/processing splat models into .rad, and rendering splats in the 3D viewer alongside existing Potree tooling.
Changes:
- Added backend APIs + worker tasks for splats training export, model upload/delete, and
.radrange-enabled delivery. - Added frontend UI (task dialog + model-view integration) to guide download/train/upload and to display splats in 3D.
- Updated Potree shaders/renderer path to support WebGL2-focused rendering and added docs link plumbing.
File summaries
| File | Description |
|---|---|
| worker/tasks.py | Adds Celery tasks for exporting training data and converting uploaded splats via splat-tools. |
| webodm/settings.py | Introduces a dedicated docs link for Gaussian Splats. |
| package.json | Bumps app version to 3.3.0. |
| Dockerfile | Installs splat-tools into the runtime image. |
| app/views/app.py | Passes model-type from query param to the model display template. |
| app/tests/test_splats.py | Adds comprehensive API tests for splats export, upload/processing, delete, and range requests. |
| app/tests/test_api_task.py | Extends task API tests for splats asset presence and new /rtc endpoint. |
| app/templatetags/settings.py | Exposes SPLAT_DOCS_LINK as a template tag. |
| app/templates/app/base.html | Injects window.__splatDocsLink for frontend usage. |
| app/static/app/js/vendor/potree/build/potree/potree.js | Updates Potree to a WebGL2/GLSL300 shader path and related extension logic. |
| app/static/app/js/ModelView.jsx | Adds splats model type handling and integrates THREEdgs-based renderer into the 3D view. |
| app/static/app/js/css/SplatsDialog.scss | Adds styling for the new Splats dialog UI. |
| app/static/app/js/css/ManageMediaDialog.scss | Minor style tweak (removes opacity rule). |
| app/static/app/js/components/tests/SplatsDialog.test.jsx | Adds a smoke test for the Splats dialog component. |
| app/static/app/js/components/TaskListItem.jsx | Adds Splats dialog entry point and improves clipboard copy fallback for non-secure contexts. |
| app/static/app/js/components/SplatsDialog.jsx | Implements the full Splats UI flow (download training zip, upload model w/ progress, delete/view). |
| app/static/app/js/classes/AssetDownloads.js | Adds splats.rad to available asset downloads. |
| app/static/app/css/main.scss | Adds a .fa-splat icon mask definition. |
| app/splats.py | Implements training export generation (COLMAP bin files, image resizing, optional PDAL sampling, zip streaming). |
| app/models/task.py | Registers splats.rad in task assets map and tweaks image resize to use reducing_gap. |
| app/geoutils.py | Adds get_rtc_offset() helper for RTC coordinate offsets. |
| app/api/urls.py | Registers new /rtc and /splats/* API routes. |
| app/api/tasks.py | Adds range support for .rad assets and introduces TaskRtc API view. |
| app/api/splats.py | Adds splats download/upload/delete API endpoints and integrates worker tasks. |
Review details
Suppressed comments (1)
app/api/splats.py:156
- tmp_splats_file is created via tempfile.mktemp(), which is vulnerable to path-race attacks and can collide under concurrency. Use mkstemp/NamedTemporaryFile to reserve the filename securely before moving the uploaded file.
else:
tmp_splats_file = tempfile.mktemp('_splats' + ext, dir=settings.MEDIA_TMP)
shutil.move(uploaded_file, tmp_splats_file)
celery_task_id = process_splats.delay(task.id, tmp_splats_file).task_id
return Response({'success': True, 'celery_task_id': celery_task_id}, status=status.HTTP_200_OK)
- Files reviewed: 23/25 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+155
to
+156
| # Install splat-tools | ||
| curl -fsSL "https://github.com/uav4geo/Splat-Tools/releases/download/v1.0.3/splat-tools-1.0.3-$(uname -m)-linux.tar.gz" | tar -xz -C /usr/bin --strip-components=1 "splat-tools-1.0.3-$(uname -m)-linux/splat-tools" && /usr/bin/splat-tools --version |
Comment on lines
+263
to
+268
| def process_splats(self, task_id, splats_file): | ||
| if not os.path.isfile(splats_file): | ||
| raise Exception("Splats file not found") | ||
|
|
||
| tmp_out = tempfile.mktemp('_model.rad', dir=settings.MEDIA_TMP) | ||
| try: |
Comment on lines
+109
to
+120
| if chunk_info is not None: | ||
| if os.path.isfile(chunk_info['tmp_upload_file']) and chunk_info['chunk_index'] == 0: | ||
| os.unlink(chunk_info['tmp_upload_file']) | ||
|
|
||
| with open(chunk_info['tmp_upload_file'], 'ab') as fd: | ||
| fd.seek(chunk_info['byte_offset']) | ||
| if isinstance(file, InMemoryUploadedFile): | ||
| for chunk in file.chunks(): | ||
| fd.write(chunk) | ||
| else: | ||
| with open(file.temporary_file_path(), 'rb') as f: | ||
| shutil.copyfileobj(f, fd) |
Comment on lines
+506
to
+519
| range_match = re.match(r'^bytes=(\d+)-(\d*)$', request.META.get('HTTP_RANGE', '')) | ||
| if range_match: | ||
| start = int(range_match.group(1)) | ||
| end = int(range_match.group(2)) if range_match.group(2) else filesize - 1 | ||
|
|
||
| if start >= filesize: | ||
| file.close() | ||
| response = HttpResponse(status=416) | ||
| response['Content-Range'] = 'bytes */{}'.format(filesize) | ||
| return response | ||
|
|
||
| end = min(end, filesize - 1) | ||
| length = end - start + 1 | ||
| file.seek(start) |
Member
Author
|
We're good to go 👍 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds support for:
recording.webm