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.
64 lines
2.1 KiB
Python
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}")
|