Files
Portfolio/scripts/blender/make-lite-car.py
LucaP 582bf6dc43 feat(scene): phone LOD car and clearcoat coachwork on desktop
Phones and the low tier load a decimated grand tourer built by a headless
Blender script (31k to 11k faces, same nodes and materials). Desktop gets
clearcoat paint and a soft halo parented to the tail bar.
2026-10-10 22:41:12 +03:00

64 lines
2.1 KiB
Python

"""Builds the phone LOD of the grand tourer. Headless only:
blender -b --python scripts/blender/make-lite-car.py -- \
src/assets/nightdrive-grand-tourer-chromatic.glb \
src/assets/nightdrive-grand-tourer-lite.glb
On a phone the car is about 200 px wide and seen from behind, so the wheel
machining, the tyre treads and the dense trim carry detail nobody can see.
They are collapsed; the silhouette parts (body, haunches, glass) are kept
as authored so the car reads the same. Node names and the hierarchy are
preserved: car.ts finds the wheels, the light bar and the underglow by name.
"""
import sys
import bpy
source, target = sys.argv[sys.argv.index("--") + 1 :][:2]
# Fraction of faces kept, by node name prefix (after the "evolution-" prefix).
RATIOS = {
"wheel-machining": 0.22,
"tires": 0.25,
"body-trim": 0.35,
"rear-light-bar": 0.4,
"car-underglow-source": 0.35,
}
bpy.ops.wm.read_factory_settings(use_empty=True)
bpy.ops.import_scene.gltf(filepath=source)
before = after = 0
for obj in bpy.data.objects:
if obj.type != "MESH":
continue
name = obj.name.removeprefix("evolution-")
faces = len(obj.data.polygons)
before += faces
ratio = next((r for prefix, r in RATIOS.items() if name.startswith(prefix)), None)
if ratio is not None and faces > 200:
# Meshes can be shared between wheels; give each object its own data.
obj.data = obj.data.copy()
modifier = obj.modifiers.new("lod", "DECIMATE")
modifier.decimate_type = "COLLAPSE"
modifier.ratio = ratio
modifier.use_collapse_triangulate = True
bpy.context.view_layer.objects.active = obj
for other in bpy.context.view_layer.objects:
other.select_set(other is obj)
bpy.ops.object.modifier_apply(modifier=modifier.name)
after += len(obj.data.polygons)
bpy.ops.export_scene.gltf(
filepath=target,
export_format="GLB",
export_apply=True,
export_yup=True,
export_texcoords=False,
export_normals=True,
export_materials="EXPORT",
export_animations=False,
)
print(f"LITE faces {before} -> {after}")