-
Convert the source USDZ to a raw GLB (do NOT hand-edit; this reproduces the server GLB):
cd ~/dev/gvsucis/ar_models
mkdir -p /tmp/ar_in /tmp/ar_out && cp usdz/<id>_*.usdz /tmp/ar_in/
/Applications/Blender.app/Contents/MacOS/Blender --background --factory-startup \
--python script/convert_usdz_to_glb.py -- /tmp/ar_in /tmp/ar_out
Inspect the result (mesh/anim/material counts, geometry-vs-texture byte split) to anticipate
heaviness. Whole-diorama models with 200+ meshes or 200+ skin joints can ANR on load — plan to
compress (step 6).
-
Bundle for on-device testing: cp /tmp/ar_out/<file>.glb art-at-gvsu-android/app/src/main/assets/ar/<id>.glb.
-
Enable the tuner by re-wiring ARExperienceScreen.kt per docs/ar-debug-placement.md
(BUNDLED_MODELS entry, tuner state, double-tap catcher, panel, and the single ModelNode
whose transform is driven by the sliders). Then build + install:
cd ~/dev/gvsucis/art-at-gvsu-android && ./gradlew :app:installDebug -q
adb shell monkey -p edu.gvsu.artmuseum -c android.intent.category.LAUNCHER 1
-
Hand off to the user to tune on-device: walk to the painting, double-tap for the panel,
dial rotX (snaps 15°; start −90) / scale / tx-ty-tz, then tap "Log values (Bake)". Pull it:
adb logcat -d | grep AR_BAKE
-
Bake the tuned transform into the GLB — transform-only, so meshes/materials/animation
(incl. KHR_materials_clearcoat, which Filament renders fine) are untouched:
python3 ~/dev/gvsucis/ar_models/script/refit_glb_scale.py \
/tmp/ar_out/<file>.glb ~/dev/gvsucis/ar_models/converted/glb/<id>_<slug>.glb \
<scale> <tx> <ty> <tz> <rotx>
(Only use glb_json_refit.py instead if the model also needs material fixes, e.g. Sketchfab
spec-gloss — see ar_models/README.md.)
-
Compress if over ~10 MB — geometry only, with meshopt (NOT Draco, which broke rendering
in gltfio). Keep all mesh-destroying passes off (these are skinned + per-node-animated):
npx @gltf-transform/cli optimize in.glb out.glb --compress meshopt \
--flatten false --join false --instance false --palette false --simplify false \
--texture-compress false
-
Validate: re-bundle the baked GLB and confirm it renders correctly with the tuner off
(identity transform reproduces the tuned placement because it's now baked in).
-
Upload (the user does this in CollectiveAccess) as the object's ar_3d_file, then verify
it's live by SHA-matching the server file against the local deliverable:
url=$(curl -s "https://artgallery.gvsu.edu/admin/service.php/simple/objectDetail?id=<id>&noCache=1" \
| python3 -c "import sys,json;print(json.load(sys.stdin)['ar_3d_file'])")
curl -s "$url" -o /tmp/live.glb
shasum -a256 /tmp/live.glb ~/dev/gvsucis/ar_models/converted/glb/<id>_<slug>.glb
-
Clean up: revert the tuner wiring in ARExperienceScreen.kt, empty BUNDLED_MODELS, delete
the bundled assets/ar/*.glb, and confirm a clean build. Commit the deliverable notes.