Lane E round 5 (E1): bake 6 hero props to <=8k tris (288k->48k), live on depot
pipeline/bake_lowpoly.py — Blender headless: voxel-remesh -> decimate -> Cycles base-colour bake onto fresh UVs (R3 lesson: simplify-only floors on TRELLIS shell-soup; the re-bake is the point). drinks_fridge/milkshake_mixer/arcade_cabinet/ listening_booth/novelty_record/counter_till all 25-77k -> <=8k, ~0.9M each. Every prop eyeballed (docs/shots/laneE/props_baked.png) + verified loading in vendored GLTFLoader; footprints unchanged (no C re-map needed). Re-published; validate --depot 0 err. Originals gitignored in pipeline/.props_orig/. Unblocks C's interior re-measure + F's v1.1 tag. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1
.gitignore
vendored
@ -10,3 +10,4 @@ node_modules/
|
||||
pipeline/.genprops/
|
||||
web/assets/models/
|
||||
pipeline/.peds_orig/
|
||||
pipeline/.props_orig/
|
||||
|
||||
@ -4,6 +4,21 @@
|
||||
Reviewed against `docs/LANES/LANE_E_ASSETS.md` + `docs/LANES/ROUND3_INSTRUCTIONS.md`. Nothing in
|
||||
other lanes' files was touched.*
|
||||
|
||||
## Round 5 (Fable) — hero-prop bake + fal fallbacks + depot growth
|
||||
|
||||
- **E1 — hero-prop bake-to-lowpoly: DONE + committed.** New `pipeline/bake_lowpoly.py` (Blender
|
||||
headless): voxel-remesh → decimate → **Cycles base-colour bake** onto fresh UVs (R3's lesson:
|
||||
simplify-only floors on shell-soup; the re-bake is the point). All **6 heavy TRELLIS props ≤8k
|
||||
tris** (drinks_fridge 77k→8k, milkshake_mixer 73k→8k, listening_booth 54k→8k, counter_till
|
||||
32k→8k, novelty_record 26k→8k, arcade_cabinet 25k→8k). **Fleet 288k→48k tris, 18M→5.2M.** Each
|
||||
eyeballed (`docs/shots/laneE/props_baked.png` — fridge needed a coarser voxel re-bake, rest clean)
|
||||
+ verified loading in the vendored GLTFLoader. Re-published; `validate --depot` 0 err. Originals
|
||||
gitignored in `pipeline/.props_orig/`. → Lane C re-measures the record interior (was ~273k).
|
||||
- **E3 — fal.ai fallbacks (authorized, decision #4):** glass-case + bus-shelter (+ optional
|
||||
magazine-rack) via fal Hunyuan v2, ≤2 attempts each, costs logged in AUDIT. *(in progress)*
|
||||
- **E2 — depot growth for v2:** ~8–12 library props serving C's dig / D's roster / B's windows.
|
||||
*(in progress)*
|
||||
|
||||
## Round 4 (Fable) — ped decimation (gate-3 critical path) + asset fixes
|
||||
|
||||
- **E1 — ped decimation: DONE + committed** (`518678d`, ref `lane-e/round4-peds`). The 19 ped rigs
|
||||
|
||||
@ -1,4 +1,33 @@
|
||||
# LANE E — cross-lane notes (round 4)
|
||||
# LANE E — cross-lane notes
|
||||
|
||||
## Round 5
|
||||
|
||||
### → Lane C: hero props BAKED to ≤8k tris — re-measure the record interior
|
||||
The 6 heavy TRELLIS props are re-baked and **live on the depot** (same filenames, footprints
|
||||
unchanged, so **no re-map needed** — they upgrade in place):
|
||||
|
||||
| prop | tris before → after |
|
||||
|---|---|
|
||||
| drinks_fridge | 77k → 8.0k |
|
||||
| milkshake_mixer | 73k → 8.0k |
|
||||
| listening_booth | 54k → 8.0k |
|
||||
| counter_till | 32k → 8.0k |
|
||||
| novelty_record | 26k → 8.0k |
|
||||
| arcade_cabinet | 25k → 8.0k |
|
||||
|
||||
**Fleet 288k → 48k tris.** Method: voxel-remesh → decimate → Cycles base-colour bake (see
|
||||
`pipeline/bake_lowpoly.py`, AUDIT R5). Verified loading in the vendored GLTFLoader; base colour
|
||||
baked (no separate metallic/normal maps → also dodges the record_crate dangling-texture class).
|
||||
→ **Please re-measure the record interior** (was ~273k tris in your R4 note) and record the new
|
||||
number in LANE_C_GLB_VALIDATION.md — it should drop by ~most of the prop weight.
|
||||
|
||||
### → Fable: E1 (bake) status
|
||||
DONE + committed. 6 props ≤8k, published, `validate --depot` 0 err, qa gate green. Feeds C's
|
||||
re-measure + your v1.1 tag. E3 (fal glass-case/bus-shelter) + E2 (depot growth) next.
|
||||
|
||||
---
|
||||
|
||||
## Round 4
|
||||
|
||||
## → Lane D (task D2): decimated peds ready to validate
|
||||
|
||||
|
||||
BIN
docs/shots/laneE/props_baked.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
@ -194,3 +194,28 @@ re-measures gate 3 (~24-rig near cap × ≤3k ≈ ≤67k fleet contribution).
|
||||
props). **Provenance: 100% synthetic/on-device** (FLUX.2-klein-4B + TRELLIS.2 on the M3 Ultra), no
|
||||
third-party source — cleanest licence zone. Replaces the R3 4 m till-less counter for the interior
|
||||
counter slot (Lane C maps `counter` → `counter_till`); the balcao 4 m `counter` stays for long-bar use.
|
||||
|
||||
## Round 5 — E1: hero-prop bake-to-lowpoly (un-parked)
|
||||
|
||||
The 6 heavy TRELLIS hero props were **25k–77k tris** (shell-soup — simplify-only floors there,
|
||||
R3's lesson). Rebuilt topology + re-baked base colour via `pipeline/bake_lowpoly.py` (Blender
|
||||
headless): **voxel-remesh → triangulate → decimate ≤8k → smart-UV → Cycles DIFFUSE(COLOR) bake
|
||||
HP→LP → WebP export**. All **≤8k tris**, base colour baked onto fresh UVs, self-illuminated a
|
||||
touch (matches normalize). Originals backed up (gitignored) at `pipeline/.props_orig/`; batch spec
|
||||
`pipeline/batch_bake.json`; results `pipeline/_bake_results.json`.
|
||||
|
||||
| prop | tris before → after | voxel | size on disk | note |
|
||||
|---|---|---|---|---|
|
||||
| drinks_fridge | 77047 → 8000 | 0.03 | 5.3M → 0.9M | hollow glass-door box — needed a coarser voxel (0.012 grabbed the internal shelves into wireframe) |
|
||||
| milkshake_mixer | 73492 → 7991 | 0.005 | 4.7M → 0.9M | small part, fine voxel |
|
||||
| listening_booth | 53502 → 7986 | 0.012 | 3.4M → 0.9M | panel + stool |
|
||||
| counter_till | 32226 → 7999 | 0.012 | 1.9M → 0.9M | timber counter + till |
|
||||
| novelty_record | 26486 → 8000 | 0.014 | 1.8M → 0.9M | thick disc + base |
|
||||
| arcade_cabinet | 25142 → 8000 | 0.012 | 1.5M → 0.8M | boxy cabinet |
|
||||
|
||||
Fleet: **288k → 48k tris**, **18M → 5.2M**. Every one **eyeballed** (contact sheet
|
||||
`docs/shots/laneE/props_baked.png` — no melted labels/faces; the fridge re-bake was the only redo)
|
||||
and **verified loading in the vendored `GLTFLoader`** (tris ≤8k, baked texture present).
|
||||
Re-published to the depot (`validate --depot` 0 errors). **Provenance unchanged: 100% synthetic/
|
||||
on-device** (FLUX.2-klein-4B + TRELLIS.2 + Blender bake, no third-party source). → Lane C
|
||||
re-measures the record interior (was ~273k tris).
|
||||
|
||||
@ -5,16 +5,16 @@
|
||||
"file": "procity_fit_listening_booth_01.glb",
|
||||
"out": "pipeline/_normalized/procity_fit_listening_booth_01.glb",
|
||||
"thumb": "web/assets/thumbs/procity_fit_listening_booth_01.png",
|
||||
"tri_before": 146946,
|
||||
"tri_after": 53578,
|
||||
"tri_before": 53502,
|
||||
"tri_after": 7986,
|
||||
"size_m": [
|
||||
0.879,
|
||||
1.6,
|
||||
0.71
|
||||
0.876,
|
||||
1.595,
|
||||
0.703
|
||||
],
|
||||
"footprint": [
|
||||
0.88,
|
||||
0.71
|
||||
0.7
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -22,16 +22,16 @@
|
||||
"file": "procity_fit_drinks_fridge_01.glb",
|
||||
"out": "pipeline/_normalized/procity_fit_drinks_fridge_01.glb",
|
||||
"thumb": "web/assets/thumbs/procity_fit_drinks_fridge_01.png",
|
||||
"tri_before": 191640,
|
||||
"tri_after": 77412,
|
||||
"tri_before": 77047,
|
||||
"tri_after": 8000,
|
||||
"size_m": [
|
||||
0.849,
|
||||
1.6,
|
||||
0.962
|
||||
0.842,
|
||||
1.591,
|
||||
0.932
|
||||
],
|
||||
"footprint": [
|
||||
0.85,
|
||||
0.96
|
||||
0.84,
|
||||
0.93
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -39,12 +39,12 @@
|
||||
"file": "procity_fit_arcade_cabinet_01.glb",
|
||||
"out": "pipeline/_normalized/procity_fit_arcade_cabinet_01.glb",
|
||||
"thumb": "web/assets/thumbs/procity_fit_arcade_cabinet_01.png",
|
||||
"tri_before": 196336,
|
||||
"tri_after": 25143,
|
||||
"tri_before": 25142,
|
||||
"tri_after": 8000,
|
||||
"size_m": [
|
||||
0.75,
|
||||
1.7,
|
||||
0.853
|
||||
0.749,
|
||||
1.692,
|
||||
0.85
|
||||
],
|
||||
"footprint": [
|
||||
0.75,
|
||||
@ -56,12 +56,12 @@
|
||||
"file": "procity_fit_milkshake_mixer_01.glb",
|
||||
"out": "pipeline/_normalized/procity_fit_milkshake_mixer_01.glb",
|
||||
"thumb": "web/assets/thumbs/procity_fit_milkshake_mixer_01.png",
|
||||
"tri_before": 185106,
|
||||
"tri_after": 73498,
|
||||
"tri_before": 73492,
|
||||
"tri_after": 7991,
|
||||
"size_m": [
|
||||
0.381,
|
||||
0.5,
|
||||
0.271
|
||||
0.378,
|
||||
0.498,
|
||||
0.268
|
||||
],
|
||||
"footprint": [
|
||||
0.38,
|
||||
@ -73,15 +73,15 @@
|
||||
"file": "procity_street_novelty_record_01.glb",
|
||||
"out": "pipeline/_normalized/procity_street_novelty_record_01.glb",
|
||||
"thumb": "web/assets/thumbs/procity_street_novelty_record_01.png",
|
||||
"tri_before": 193253,
|
||||
"tri_after": 26506,
|
||||
"tri_before": 26486,
|
||||
"tri_after": 8000,
|
||||
"size_m": [
|
||||
1.909,
|
||||
2.0,
|
||||
0.934
|
||||
1.896,
|
||||
1.992,
|
||||
0.933
|
||||
],
|
||||
"footprint": [
|
||||
1.91,
|
||||
1.9,
|
||||
0.93
|
||||
]
|
||||
},
|
||||
@ -90,16 +90,16 @@
|
||||
"file": "procity_fit_counter_till_01.glb",
|
||||
"out": "/tmp/counter_norm/procity_fit_counter_till_01.glb",
|
||||
"thumb": "web/assets/thumbs/procity_fit_counter_till_01.png",
|
||||
"tri_before": 195285,
|
||||
"tri_after": 32234,
|
||||
"tri_before": 32226,
|
||||
"tri_after": 7999,
|
||||
"size_m": [
|
||||
1.609,
|
||||
1.15,
|
||||
0.642
|
||||
1.608,
|
||||
1.146,
|
||||
0.606
|
||||
],
|
||||
"footprint": [
|
||||
1.61,
|
||||
0.64
|
||||
0.61
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
200
pipeline/bake_lowpoly.py
Normal file
@ -0,0 +1,200 @@
|
||||
"""PROCITY hero-prop bake-to-lowpoly — turn a heavy TRELLIS shell-soup GLB into a game-ready
|
||||
≤8k-tri prop with its base colour BAKED onto fresh UVs.
|
||||
|
||||
Runs headless on this box's Blender:
|
||||
BL=/Applications/Blender.app/Contents/MacOS/Blender
|
||||
"$BL" --background --python bake_lowpoly.py -- BATCH.json OUT_DIR [THUMB_DIR]
|
||||
|
||||
Why bake (R3's lesson): raw TRELLIS meshes are dense multi-shell scans; plain decimate /
|
||||
meshopt-simplify floors at 25–77k because they can't merge across the shells. So we throw the
|
||||
topology away and rebuild it:
|
||||
1. import the normalized HP (already metres / +Y up / base-origin / textured) → bake SOURCE
|
||||
2. voxel-remesh a copy → one watertight manifold surface (no more shell-soup)
|
||||
3. decimate the remesh to the tri budget (≤8k) → LP
|
||||
4. smart-UV unwrap LP
|
||||
5. Cycles bake DIFFUSE(COLOR) HP → LP's new UVs → a single baked base-colour texture
|
||||
6. export LP GLB (WebP, embedded, self-illuminated a touch like normalize.py) + 256 thumbnail
|
||||
|
||||
BATCH.json: [ {"src":"pipeline/_normalized/procity_fit_drinks_fridge_01.glb",
|
||||
"id":"drinks_fridge", "category":"fit",
|
||||
"voxel":0.012, "tris":8000, "img":1024} , ... ]
|
||||
"""
|
||||
import bpy, sys, os, json, math
|
||||
from mathutils import Vector
|
||||
|
||||
ARGV = sys.argv[sys.argv.index("--") + 1:]
|
||||
BATCH, OUT_DIR = ARGV[0], (ARGV[1] if len(ARGV) > 1 else "/tmp/procity_bake")
|
||||
THUMB_DIR = ARGV[2] if len(ARGV) > 2 else os.path.join(OUT_DIR, "thumbs")
|
||||
os.makedirs(OUT_DIR, exist_ok=True); os.makedirs(THUMB_DIR, exist_ok=True)
|
||||
|
||||
|
||||
def wipe():
|
||||
for o in list(bpy.data.objects):
|
||||
bpy.data.objects.remove(o, do_unlink=True)
|
||||
for coll in (bpy.data.meshes, bpy.data.materials, bpy.data.images):
|
||||
for d in list(coll):
|
||||
if d.users == 0:
|
||||
coll.remove(d)
|
||||
|
||||
|
||||
def import_join(src):
|
||||
bpy.ops.import_scene.gltf(filepath=src)
|
||||
meshes = [o for o in bpy.data.objects if o.type == 'MESH']
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
for m in meshes:
|
||||
m.select_set(True)
|
||||
bpy.context.view_layer.objects.active = meshes[0]
|
||||
if len(meshes) > 1:
|
||||
bpy.ops.object.join()
|
||||
obj = bpy.context.view_layer.objects.active
|
||||
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
|
||||
return obj
|
||||
|
||||
|
||||
def bounds(obj):
|
||||
bb = [obj.matrix_world @ Vector(c) for c in obj.bound_box]
|
||||
mn = Vector((min(v.x for v in bb), min(v.y for v in bb), min(v.z for v in bb)))
|
||||
mx = Vector((max(v.x for v in bb), max(v.y for v in bb), max(v.z for v in bb)))
|
||||
return mn, mx
|
||||
|
||||
|
||||
def make_lowpoly(hp, voxel, tris):
|
||||
"""Duplicate HP → voxel remesh → decimate to budget → smart UV. Returns the LP object."""
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
hp.select_set(True); bpy.context.view_layer.objects.active = hp
|
||||
bpy.ops.object.duplicate()
|
||||
lp = bpy.context.view_layer.objects.active
|
||||
lp.name = "LP"
|
||||
# strip HP's materials off the LP — it gets one fresh baked material
|
||||
lp.data.materials.clear()
|
||||
rm = lp.modifiers.new("remesh", 'REMESH')
|
||||
rm.mode = 'VOXEL'; rm.voxel_size = voxel; rm.adaptivity = 0.0
|
||||
bpy.ops.object.modifier_apply(modifier=rm.name)
|
||||
# triangulate so len(polygons) == triangle count → the decimate ratio targets triangles honestly
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.select_all(action='SELECT')
|
||||
bpy.ops.mesh.quads_convert_to_tris()
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
n = len(lp.data.polygons)
|
||||
if n > tris:
|
||||
dm = lp.modifiers.new("dec", 'DECIMATE')
|
||||
dm.ratio = max(0.005, tris / n)
|
||||
bpy.ops.object.modifier_apply(modifier=dm.name)
|
||||
# UVs
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.select_all(action='SELECT')
|
||||
bpy.ops.uv.smart_project(island_margin=0.02, angle_limit=math.radians(66))
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
return lp
|
||||
|
||||
|
||||
def bake_color(hp, lp, img_size):
|
||||
img = bpy.data.images.new("baked", img_size, img_size)
|
||||
mat = bpy.data.materials.new("baked_mat"); mat.use_nodes = True
|
||||
nt = mat.node_tree
|
||||
bsdf = nt.nodes.get("Principled BSDF")
|
||||
tex = nt.nodes.new("ShaderNodeTexImage"); tex.image = img
|
||||
nt.links.new(tex.outputs["Color"], bsdf.inputs["Base Color"])
|
||||
lp.data.materials.clear(); lp.data.materials.append(mat)
|
||||
nt.nodes.active = tex # the active image node = bake target
|
||||
|
||||
scn = bpy.context.scene
|
||||
scn.render.engine = 'CYCLES'
|
||||
try:
|
||||
scn.cycles.device = 'GPU'
|
||||
except Exception:
|
||||
pass
|
||||
scn.cycles.samples = 4
|
||||
scn.render.bake.use_selected_to_active = True
|
||||
scn.render.bake.cage_extrusion = 0.06
|
||||
scn.render.bake.max_ray_distance = 0.12
|
||||
scn.render.bake.margin = max(4, img_size // 128)
|
||||
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
hp.select_set(True); lp.select_set(True)
|
||||
bpy.context.view_layer.objects.active = lp # active = bake TARGET
|
||||
bpy.ops.object.bake(type='DIFFUSE', pass_filter={'COLOR'}, use_clear=True)
|
||||
|
||||
# self-illuminate a touch so it reads in any viewer (matches normalize.py bright)
|
||||
ec = bsdf.inputs.get("Emission Color") or bsdf.inputs.get("Emission")
|
||||
if ec is not None:
|
||||
nt.links.new(tex.outputs["Color"], ec)
|
||||
es = bsdf.inputs.get("Emission Strength")
|
||||
if es is not None:
|
||||
es.default_value = 0.28
|
||||
return img
|
||||
|
||||
|
||||
def base_origin(obj):
|
||||
mn, mx = bounds(obj)
|
||||
obj.location -= Vector(((mn.x + mx.x) / 2, (mn.y + mx.y) / 2, mn.z))
|
||||
bpy.ops.object.transform_apply(location=True)
|
||||
|
||||
|
||||
def render_thumb(lp, png_name):
|
||||
scn = bpy.context.scene
|
||||
mn, mx = bounds(lp); ctr = (mn + mx) / 2
|
||||
size = max((mx - mn).x, (mx - mn).y, (mx - mn).z) or 1.0
|
||||
for o in list(bpy.data.objects):
|
||||
if o.type in ('CAMERA', 'LIGHT'):
|
||||
bpy.data.objects.remove(o, do_unlink=True)
|
||||
w = bpy.data.worlds.get("tw") or bpy.data.worlds.new("tw")
|
||||
scn.world = w; w.use_nodes = True
|
||||
w.node_tree.nodes["Background"].inputs[1].default_value = 1.05
|
||||
bpy.ops.object.light_add(type='AREA', location=(ctr.x + size, ctr.y - size, mx.z + size))
|
||||
bpy.context.object.data.energy = 800 * size; bpy.context.object.data.size = 6
|
||||
bpy.ops.object.camera_add(); cam = bpy.context.object; scn.camera = cam
|
||||
r = size * 1.9
|
||||
cam.location = Vector((ctr.x + r * 0.8, ctr.y - r, ctr.z + size * 0.6))
|
||||
cam.rotation_euler = (ctr - cam.location).to_track_quat('-Z', 'Y').to_euler()
|
||||
scn.render.engine = 'BLENDER_WORKBENCH'
|
||||
scn.display.shading.light = 'STUDIO'; scn.display.shading.color_type = 'TEXTURE'
|
||||
scn.display.shading.show_cavity = True
|
||||
scn.view_settings.view_transform = 'Standard'
|
||||
scn.render.film_transparent = True
|
||||
scn.render.resolution_x = scn.render.resolution_y = 256
|
||||
p = os.path.join(THUMB_DIR, png_name); scn.render.filepath = p
|
||||
bpy.ops.render.render(write_still=True)
|
||||
return p
|
||||
|
||||
|
||||
def bake_one(spec):
|
||||
wipe()
|
||||
src = spec["src"] if os.path.isabs(spec["src"]) else os.path.join(os.getcwd(), spec["src"])
|
||||
hp = import_join(src)
|
||||
tri_before = len(hp.data.polygons)
|
||||
lp = make_lowpoly(hp, spec.get("voxel", 0.02), spec.get("tris", 8000))
|
||||
bake_color(hp, lp, spec.get("img", 1024))
|
||||
bpy.data.objects.remove(hp, do_unlink=True) # HP done; export LP only
|
||||
base_origin(lp)
|
||||
lp.select_set(True); bpy.context.view_layer.objects.active = lp
|
||||
name = f"procity_{spec['category']}_{spec['id']}_01.glb"
|
||||
out = os.path.join(OUT_DIR, name)
|
||||
bpy.ops.export_scene.gltf(filepath=out, export_format='GLB', export_yup=True,
|
||||
use_selection=True, export_image_format='WEBP', export_image_quality=88)
|
||||
thumb = render_thumb(lp, name.replace(".glb", ".png"))
|
||||
mn, mx = bounds(lp)
|
||||
return {"file": name, "tri_before": tri_before, "tri_after": len(lp.data.polygons),
|
||||
"size_m": [round(mx.x - mn.x, 3), round(mx.z - mn.z, 3), round(mx.y - mn.y, 3)],
|
||||
"footprint": [round(mx.x - mn.x, 2), round(mx.y - mn.y, 2)], "thumb": thumb, "out": out}
|
||||
|
||||
|
||||
def main():
|
||||
specs = json.load(open(BATCH))
|
||||
results, errors = [], []
|
||||
for spec in specs:
|
||||
try:
|
||||
r = bake_one(spec)
|
||||
results.append(r)
|
||||
print(f"OK {r['file']:36} {r['tri_before']:>6}→{r['tri_after']:>5} tris "
|
||||
f"footprint {r['footprint']} h {r['size_m'][1]}")
|
||||
except Exception as e:
|
||||
import traceback; traceback.print_exc()
|
||||
errors.append({"id": spec.get("id"), "error": str(e)})
|
||||
print(f"ERR {spec.get('id')}: {e}")
|
||||
json.dump({"results": results, "errors": errors},
|
||||
open(os.path.join(OUT_DIR, "_bake_results.json"), "w"), indent=2)
|
||||
print(f"\nBAKE_DONE ok={len(results)} err={len(errors)} → {OUT_DIR}")
|
||||
|
||||
|
||||
main()
|
||||
50
pipeline/batch_bake.json
Normal file
@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"src": "pipeline/_normalized/procity_fit_drinks_fridge_01.glb",
|
||||
"id": "drinks_fridge",
|
||||
"category": "fit",
|
||||
"voxel": 0.03,
|
||||
"tris": 8000,
|
||||
"img": 1024
|
||||
},
|
||||
{
|
||||
"src": "pipeline/_normalized/procity_fit_milkshake_mixer_01.glb",
|
||||
"id": "milkshake_mixer",
|
||||
"category": "fit",
|
||||
"voxel": 0.005,
|
||||
"tris": 8000,
|
||||
"img": 1024
|
||||
},
|
||||
{
|
||||
"src": "pipeline/_normalized/procity_fit_arcade_cabinet_01.glb",
|
||||
"id": "arcade_cabinet",
|
||||
"category": "fit",
|
||||
"voxel": 0.012,
|
||||
"tris": 8000,
|
||||
"img": 1024
|
||||
},
|
||||
{
|
||||
"src": "pipeline/_normalized/procity_fit_listening_booth_01.glb",
|
||||
"id": "listening_booth",
|
||||
"category": "fit",
|
||||
"voxel": 0.012,
|
||||
"tris": 8000,
|
||||
"img": 1024
|
||||
},
|
||||
{
|
||||
"src": "pipeline/_normalized/procity_street_novelty_record_01.glb",
|
||||
"id": "novelty_record",
|
||||
"category": "street",
|
||||
"voxel": 0.014,
|
||||
"tris": 8000,
|
||||
"img": 1024
|
||||
},
|
||||
{
|
||||
"src": "pipeline/_normalized/procity_fit_counter_till_01.glb",
|
||||
"id": "counter_till",
|
||||
"category": "fit",
|
||||
"voxel": 0.012,
|
||||
"tris": 8000,
|
||||
"img": 1024
|
||||
}
|
||||
]
|
||||
@ -652,18 +652,18 @@
|
||||
"file": "procity_fit_listening_booth_01.glb",
|
||||
"footprint": [
|
||||
0.88,
|
||||
0.71
|
||||
0.7
|
||||
],
|
||||
"height": 1.6,
|
||||
"height": 1.595,
|
||||
"thumb": "thumbs/procity_fit_listening_booth_01.png"
|
||||
},
|
||||
"drinks_fridge": {
|
||||
"file": "procity_fit_drinks_fridge_01.glb",
|
||||
"footprint": [
|
||||
0.85,
|
||||
0.96
|
||||
0.84,
|
||||
0.93
|
||||
],
|
||||
"height": 1.6,
|
||||
"height": 1.591,
|
||||
"thumb": "thumbs/procity_fit_drinks_fridge_01.png"
|
||||
},
|
||||
"arcade_cabinet": {
|
||||
@ -672,7 +672,7 @@
|
||||
0.75,
|
||||
0.85
|
||||
],
|
||||
"height": 1.7,
|
||||
"height": 1.692,
|
||||
"thumb": "thumbs/procity_fit_arcade_cabinet_01.png"
|
||||
},
|
||||
"milkshake_mixer": {
|
||||
@ -681,16 +681,16 @@
|
||||
0.38,
|
||||
0.27
|
||||
],
|
||||
"height": 0.5,
|
||||
"height": 0.498,
|
||||
"thumb": "thumbs/procity_fit_milkshake_mixer_01.png"
|
||||
},
|
||||
"counter_till": {
|
||||
"file": "procity_fit_counter_till_01.glb",
|
||||
"footprint": [
|
||||
1.61,
|
||||
0.64
|
||||
0.61
|
||||
],
|
||||
"height": 1.15,
|
||||
"height": 1.146,
|
||||
"thumb": "thumbs/procity_fit_counter_till_01.png"
|
||||
},
|
||||
"cash_register": {
|
||||
@ -769,10 +769,10 @@
|
||||
"novelty_record": {
|
||||
"file": "procity_street_novelty_record_01.glb",
|
||||
"footprint": [
|
||||
1.91,
|
||||
1.9,
|
||||
0.93
|
||||
],
|
||||
"height": 2.0,
|
||||
"height": 1.992,
|
||||
"thumb": "thumbs/procity_street_novelty_record_01.png"
|
||||
}
|
||||
},
|
||||
|
||||
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 41 KiB |