Phase 4.7: in progress

This commit is contained in:
2026-10-11 22:23:43 +03:00
parent 00b2d5d1fe
commit d28fce7631
42 changed files with 3516 additions and 87 deletions
+31 -2
View File
@@ -32,7 +32,15 @@
# chassis frame). See assets/blender/vehicles/CAR_MODELING.md.
#
# Usage:
# blender <vehicle>.blend -b -Y -P gen_vehicle.py -- <out>.glb <out>.vehicle.json
# blender <vehicle>.blend -b -Y -P gen_vehicle.py -- <out>.glb \
# <out>.vehicle.json [downforce]
#
# downforce (optional, default 25): aerodynamic downforce coefficient
# (N per (m/s)^2, straight down at the COM while moving) — the
# speed-dependent grip lever: at speed it multiplies the tire normal
# load (and thus the lateral impulse budget) without adding inertia,
# which is exactly where plain tires start understeering. Higher =
# tighter turns at speed.
import os
import sys
@@ -58,6 +66,7 @@ except:
glb_file = argv[0]
json_file = argv[1]
downforce = float(argv[2]) if len(argv) > 2 else 25.0
outdir = os.path.dirname(glb_file)
base = os.path.splitext(os.path.basename(bpy.data.filepath))[0]
@@ -294,7 +303,9 @@ SUSP_MAX = 0.35
# Softer than the 1.8/0.7 starting point: gives the body some slack
# over bumps instead of pogo-stiff wheels (which also cost grip).
SUSP_FREQ = 1.3
SUSP_DAMP = 0.6
# Critical-ish damping: less and the body rocks for seconds after a
# bump (the "almost endlessly bouncy" report).
SUSP_DAMP = 1.0
SUSP_REST = SUSP_MAX - 9.81 / (2.0 * math.pi * SUSP_FREQ) ** 2
for w in sorted(wheel_info, key=lambda w: w["pos"].y):
front = w["pos"].y < axle_mid_y
@@ -320,6 +331,17 @@ for s in seat_info:
"driver": s["driver"],
})
# Center of mass: a box collider puts the COM at the box center — for
# a sedan that is ~1 m above the tire contact patches (twice the real
# value) and the car trips onto its side in hard corners (the taxi,
# with its taller box, tips even easier). Shift the COM to just above
# wheel-hub height instead (Jolt OffsetCenterOfMassShape: only the
# physics COM moves — geometry, wheel attachments and the render node
# stay put).
collider_center_ogre_y = (smx.z + smn.z) / 2.0
hub_ogre_y = sum(w["pos"].z for w in wheel_info) / len(wheel_info)
com_offset_y = round(hub_ogre_y + 0.1 - collider_center_ogre_y, 4)
driver_offset = ogre_vec3(driver_seats[0]["pos"])
children = []
@@ -410,6 +432,13 @@ vehicle = {
# soft 1.3 Hz springs a full-lock turn otherwise rolls the car past
# 45 deg onto two wheels.
"antiRollBarStiffness": 2000.0,
"centerOfMassOffset": {"x": 0.0, "y": com_offset_y, "z": 0.0},
# Aerodynamic downforce (N per (m/s)^2, straight down at the COM
# while moving): presses the car onto its suspension at speed —
# less bounce, and a bigger lateral impulse budget exactly where
# plain tires start understeering (turn radius stops growing with
# speed). Per-model value from the CMake invocation.
"downforceCoefficient": downforce,
}
if steering:
vehicle["steeringWheelMeshName"] = base + "-steering-wheel.mesh"