From d01571fadd7c8cd30a63db74e72e980adbdab9bb Mon Sep 17 00:00:00 2001 From: thunderheronight Date: Fri, 16 Oct 2026 22:52:02 +0200 Subject: [PATCH] 0.5: mesh dialog polish, changelog and READMEs; "1 version" in the job card Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 15 +++++++++++++++ README.de.md | 4 ++++ README.md | 4 ++++ web/i18n.js | 4 ++-- web/index.html | 3 ++- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57f128f..5512489 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to Splat Workshop. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versions follow [Semantic Versioning](https://semver.org/). +## [Unreleased] – 0.5 + +### Added + +- **Mesh export**: *Mesh …* on every scene and tour turns the splats into a surface with Spirula Studio (`spirula mesh`) – for Blender and other 3D programs, or for 3D printing. Formats: **GLB** (recommended: colours or texture in one file), **STL** (no colours, for slicers), **OBJ** (with a texture if possible, otherwise without colours) and **PLY** (colours per corner). + - **Stands upright, floor at height 0**: our scenes have Y pointing down like the Steam Frame's tracking, so a mesh used to lie on its side in Blender. Now OBJ, PLY and STL get Z up and GLB gets Y up, as the glTF standard wants (Blender turns that into Z up itself); the floor – found as for the floor plan – is moved to height 0. In metres. + - What lies well outside the room is left out before meshing (as the *Edges* clean-up does) – otherwise big blobs beyond the walls become lumps floating around the room. + - A **texture** from the training images when they are still there; after *clean up → training images*, colours per corner from the splats. + - The mesh lives in the scene's folder (`mesh/`); a new one replaces the old one. *Mesh ✓* shows which scenes have one. + - Also on the command line: `scripts/mesh.sh` and `scripts/upright.py`. + +### Fixed + +- A versions job with one version said "1 versions". + ## [0.4.2] – 2026-10-15 ### Fixed diff --git a/README.de.md b/README.de.md index 11ec51e..6c2cd39 100644 --- a/README.de.md +++ b/README.de.md @@ -22,6 +22,10 @@ Arcturus Vision stellt die Rekonstruktions-Skripte und einen Spirula-Studio-Fork 4. **In die Galerie**: Vorschaubild und Namensschild im Stil der Beispielszenen, kopiert in den Ordner für eigene Szenen von Gaussian XR auf der Frame (`Documents/GaussianXR`). 5. **Die Wohnung zusammensetzen**: Räume gruppieren – ein Raum darf aus mehreren Aufnahmen bestehen – und zu einem Rundgang machen, durch den du gehst, voll für den PC, kleiner für die Frame. +## Neu in 0.5 *(in Arbeit)* + +- 🧊 **Mesh-Export** – *Mesh …* macht aus einer Szene oder einem Rundgang eine Oberfläche für Blender und andere 3D-Programme (GLB, OBJ, PLY) oder für den 3D-Druck (STL). Sie steht aufrecht mit dem Boden auf Höhe 0, statt auf der Seite zu liegen; mit Textur, wenn die Trainingsbilder noch da sind. + ## Neu in 0.4 - 🧽 **Fassungen bereinigen** *(experimentell)* – vier Schieberegler im Fassungen-Dialog: **Decke** (eine weiße Decke wird zum dunklen Schleier – der Schleier kommt weg, die Decke wird in ihrer eigenen Farbe geschlossen), **Boden** (Löcher gefüllt), **Dunst** (große durchsichtige Wolken; dünne Gitter und Kabel bleiben), **Rand** (was außerhalb des Raums liegt). Die Szene selbst bleibt; die bereinigte Fassung neben einer ohne vergleichen. diff --git a/README.md b/README.md index b336ba2..0932c70 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,10 @@ Arcturus Vision publishes the reconstruction scripts and a Spirula Studio fork, 4. **Put it in the gallery**: preview image and name plate in the look of the bundled example scenes, copied into Gaussian XR's folder for personal scenes on the Frame (`Documents/GaussianXR`). 5. **Put your home together**: group the rooms – a room may be several recordings – and turn them into one tour you walk through, full size for the PC, smaller for the Frame. +## New in 0.5 *(in progress)* + +- 🧊 **Mesh export** – *Mesh …* turns a scene or tour into a surface for Blender and other 3D programs (GLB, OBJ, PLY) or for 3D printing (STL). It stands upright with the floor at height 0 instead of lying on its side; with a texture when the training images are still there. + ## New in 0.4 - 🧽 **Clean up a version** *(experimental)* – four sliders in the versions dialog: **Ceiling** (a white ceiling turns into a dark veil – the veil goes, the ceiling is closed in its own colour), **Floor** (holes filled), **Haze** (big transparent blobs; thin bars and cables stay), **Edges** (what lies outside the room). The scene itself stays; compare the cleaned version with one without. diff --git a/web/i18n.js b/web/i18n.js index 5cac33b..5ee5d29 100644 --- a/web/i18n.js +++ b/web/i18n.js @@ -249,7 +249,7 @@ const I18N = { "ver.pick": "Enter a size (at least 0.01 million)", "ver.started": "Making versions …", "ver.none": "No versions yet.", "ver.stale": "older than the scene", "ver.delete": "Delete version", "ver.confirm": "Move the version “{name}” ({size}) to the trash? A copy on the Frame is not touched.", - "job.sub.versions": "{n} versions · for {time}", "err.no_version": "This version does not exist", + "job.sub.versions": "{n} versions · for {time}", "job.sub.versions.1": "1 version · for {time}", "err.no_version": "This version does not exist", "err.no_versions": "Pick at least one size", "ver.unframe": "Off the Frame", "ver.unframe.title": "Remove this version from the Frame's gallery (it stays on the PC)", "ver.unframe.confirm": "Remove “{name}” from the Frame? Its folder in the gallery and the backup copy on the Frame are deleted; the version stays on this PC.", @@ -546,7 +546,7 @@ const I18N = { "ver.pick": "Eine Größe angeben (mindestens 0,01 Mio.)", "ver.started": "Erstelle Fassungen …", "ver.none": "Noch keine Fassungen.", "ver.stale": "älter als die Szene", "ver.delete": "Fassung löschen", "ver.confirm": "Fassung „{name}“ ({size}) in den Papierkorb verschieben? Eine Kopie auf der Frame bleibt unberührt.", - "job.sub.versions": "{n} Fassungen · seit {time}", "err.no_version": "Diese Fassung gibt es nicht", + "job.sub.versions": "{n} Fassungen · seit {time}", "job.sub.versions.1": "1 Fassung · seit {time}", "err.no_version": "Diese Fassung gibt es nicht", "err.no_versions": "Mindestens eine Größe wählen", "ver.unframe": "Von der Frame nehmen", "ver.unframe.title": "Diese Fassung aus der Galerie der Frame entfernen (auf dem PC bleibt sie)", "ver.unframe.confirm": "„{name}“ von der Frame nehmen? Ihr Ordner in der Galerie und die Sicherungskopie auf der Frame werden gelöscht; auf dem PC bleibt die Fassung.", diff --git a/web/index.html b/web/index.html index 8632fd0..d73d465 100644 --- a/web/index.html +++ b/web/index.html @@ -983,7 +983,7 @@ function renderJob() { const target = tr(j.upload ? "job.toFrame" : "job.pcOnly"), time = mins(Date.now() / 1000 - j.started); const versions = j.kind === "versions" || j.kind === "mesh"; $("#jobSub").textContent = j.kind === "mesh" ? tr("job.sub.mesh", {time}) - : versions ? tr("job.sub.versions", {n: (j.steps || []).length, time}) + : versions ? tr((j.steps || []).length === 1 ? "job.sub.versions.1" : "job.sub.versions", {n: (j.steps || []).length, time}) : combine ? tr(j.rooms === 1 && j.recordings > 1 ? "job.sub.combine.room" : "job.sub.combine", {n: j.rooms === 1 && j.recordings > 1 ? j.recordings : j.rooms, align: ALIGN_LETTER[j.quality] || "?", target, time}) : j.chain ? tr("job.sub.part", {i: j.chain.i + 1, n: j.chain.n, room: j.chain.room, q: tr("q." + qk), time}) @@ -1373,6 +1373,7 @@ async function openMesh(slug) { }; } $("#meshTex").disabled = !m.texture_possible; + $("#meshTex").classList.toggle("hidden", !m.texture_possible); // not possible: only the note $("#meshTex").checked = m.texture_possible; $("#meshTexText").textContent = tr(m.texture_possible ? "mesh.texture" : "mesh.texture.none"); };