mirror of
https://github.com/thunderheronight/splat-workshop.git
synced 2026-10-17 20:01:31 +02:00
- The watcher reports the next part (or putting the parts together) as running in the tick that starts it: no false standby notice between parts. - Deleting an unfinished part deletes its piece of video in runs/.parts too. - combine.sh keeps the floor plan's labels (plan.json). - Tests: the chain through the watcher's tick (twice), one standby notice per chain, the own lock released before suspending, rooms of the same name, view-dependent colour matched, the preview plan of a home named by rooms; notifications are awaited instead of checked too early. - 0.3.0: version, changelog, READMEs without the preview notice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
123 lines
5.3 KiB
Bash
Executable File
123 lines
5.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# Put the scenes of one recording session together into one big scene ("tour"):
|
|
# all splats for the PC, a smaller version for the Steam Frame.
|
|
#
|
|
# Usage: scripts/combine.sh <folder name> "<display name>" <run folder>=<label> <run folder>=<label> ...
|
|
#
|
|
# Environment:
|
|
# ALIGN=frame|images|shift|rigid how the rooms are fitted together (default: images, see combine.py)
|
|
# PARTITION=view|nearest where the borders between the recordings run (default: view)
|
|
# COLOUR=match|keep bring all recordings to one brightness (default: match)
|
|
# ROOMS='["Kitchen","Kitchen","Hallway"]' the room of every recording, in order: a room can be made of
|
|
# several recordings (default: every recording is a room of its own)
|
|
# FRAME_SPLATS=1000000 splats in the Frame version (the full version keeps all)
|
|
# FULL=0 skip the full SOG for the PC (the step that needs the most memory)
|
|
# FULL_NAME="..." name plate of the full version (default: "<name> (full)")
|
|
# PLAN_COMMA=1 decimal comma on the floor plan used as preview
|
|
# NO_UPLOAD=1 only compute, don't copy to the Frame
|
|
# WORLD_SCALE=87 show a model in Gaussian XR in the size of the original (1:87)
|
|
# A previous result of the same name stays until the new one is done.
|
|
#
|
|
# Lines starting with "@@" are machine-readable progress markers for the web interface.
|
|
set -euo pipefail
|
|
# Everything in one block: bash reads it completely before it starts, so updating this file
|
|
# (git pull, editing) does not affect a run that is already going.
|
|
{
|
|
|
|
HERE=$(cd "$(dirname "$(readlink -f "$0")")" && pwd)
|
|
ROOT=$(dirname "$HERE")
|
|
eval "$(cd "$ROOT" && python3 -m splat_workshop.config --shell)"
|
|
|
|
slug=${1:?Give a folder name}
|
|
name=${2:?Give a display name}
|
|
shift 2
|
|
[ $# -ge 2 ] || { echo "Give at least two scenes (run folder=label)" >&2; exit 1; }
|
|
case "$slug" in ''|.*|*/*) echo "Unusable folder name: $slug" >&2; exit 1 ;; esac
|
|
[ -n "$SPLAT_TRANSFORM" ] || { echo "splat-transform not found (npm install -g @playcanvas/splat-transform)" >&2; exit 1; }
|
|
|
|
out=$RUNS_DIR/$slug
|
|
log=$RUNS_DIR/$slug.log
|
|
work=$RUNS_DIR/.building
|
|
tmp=$work/$slug
|
|
stem=$(printf '%s' "$slug" | tr 'A-Z' 'a-z')
|
|
frame_splats=${FRAME_SPLATS:-1000000}
|
|
|
|
# Gaussian XR's worldScale in a scene's transform file, when WORLD_SCALE is set (a model shown in the
|
|
# size of the original, e.g. 87 for H0)
|
|
world_scale() {
|
|
[ -n "${WORLD_SCALE:-}" ] || return 0
|
|
python3 - "$1" "$WORLD_SCALE" <<'PY'
|
|
import json, sys
|
|
path, scale = sys.argv[1], float(sys.argv[2])
|
|
data = json.load(open(path))
|
|
data["worldScale"] = scale
|
|
json.dump(data, open(path, "w"), indent=2)
|
|
PY
|
|
}
|
|
|
|
main() {
|
|
rm -rf "$tmp"
|
|
mkdir -p "$tmp"
|
|
trap 'rm -rf "$tmp" "$tmp.old"; rmdir "$work" 2>/dev/null || true' EXIT
|
|
trap 'exit 143' TERM; trap 'exit 130' INT; trap 'exit 129' HUP
|
|
|
|
echo "Putting $# scenes together as \"$name\" (alignment ${ALIGN:-images}, borders ${PARTITION:-view})"
|
|
uv run -q "$HERE/combine.py" "$tmp" "$@" --align "${ALIGN:-images}" --partition "${PARTITION:-view}" --colour "${COLOUR:-match}" \
|
|
${ROOMS:+--rooms "$ROOMS"}
|
|
total=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["splats"])' "$tmp/combine.json")
|
|
|
|
# Frame version: fewer splats
|
|
echo "@@ cphase 2"
|
|
src=$tmp/spirula/scene.ply
|
|
if [ "$total" -gt "$frame_splats" ]; then
|
|
echo "Reducing $total splats to $frame_splats for the Frame ..."
|
|
"$SPLAT_TRANSFORM" -w "$src" --decimate "$frame_splats" "$tmp/frame.ply"
|
|
src=$tmp/frame.ply
|
|
fi
|
|
|
|
echo "@@ cphase 3"
|
|
"$SPLAT_TRANSFORM" -w "$src" "$tmp/scene.sog"
|
|
rm -f "$tmp/frame.ply"
|
|
if [ "${FULL:-1}" = 1 ]; then
|
|
echo "Full version ($total splats) ..."
|
|
mkdir -p "$tmp/full"
|
|
"$SPLAT_TRANSFORM" -w "$tmp/spirula/scene.ply" "$tmp/full/scene.sog"
|
|
cp "$tmp/scene.xrSceneTransform.json" "$tmp/full/scene.xrSceneTransform.json"
|
|
fi
|
|
|
|
# Preview for the gallery: the floor plan of all rooms (labelled by room, not by recording)
|
|
plan_args=("$@")
|
|
if [ -n "${ROOMS:-}" ]; then
|
|
mapfile -t plan_args < <(python3 -c '
|
|
import json, sys
|
|
for arg, room in zip(sys.argv[2:], json.loads(sys.argv[1])):
|
|
print(arg.partition("=")[0] + "=" + room)' "$ROOMS" "$@")
|
|
fi
|
|
uv run -q "$HERE/floorplan.py" "$tmp/plan.png" "${plan_args[@]}" ${PLAN_COMMA:+--comma} > "$tmp/plan.json"
|
|
uv run -q "$HERE/make_gallery.py" --plan "$tmp/plan.png" "$tmp" "$name" "$stem"
|
|
if [ -d "$tmp/full" ]; then
|
|
uv run -q "$HERE/make_gallery.py" --plan "$tmp/plan.png" "$tmp/full" "${FULL_NAME:-$name (full)}" "$stem-full"
|
|
cp "$tmp/full/scene.sog" "$tmp/full/$stem-full.sog"
|
|
cp "$tmp/full/scene.xrSceneTransform.json" "$tmp/full/$stem-full.xrSceneTransform.json"
|
|
world_scale "$tmp/full/$stem-full.xrSceneTransform.json"
|
|
fi
|
|
|
|
# Replace the previous result only now
|
|
if [ -e "$out" ]; then mv "$out" "$tmp.old"; fi
|
|
mv "$tmp" "$out"
|
|
rm -rf "$tmp.old"
|
|
|
|
if [ "${NO_UPLOAD:-0}" = 1 ] || [ -z "$FRAME_HOST" ]; then
|
|
GALLERY_ONLY=1 LOG="$log" "$HERE/to-frame.sh" "$out" "$name"
|
|
echo "@@ done local"
|
|
echo "Done: $out"
|
|
else
|
|
LOG="$log" "$HERE/to-frame.sh" "$out" "$name"
|
|
fi
|
|
}
|
|
|
|
mkdir -p "$RUNS_DIR"
|
|
main "$@" 2>&1 | tee -a "$log"
|
|
exit
|
|
}
|