Custom model sedan was integrated.
This commit is contained in:
@@ -197,7 +197,7 @@ cd build-vscode/src/features/editScene/demos/demo-taxi
|
||||
./demoTaxi --headless --test-switch # inherited scene contract
|
||||
```
|
||||
|
||||
### Phase 1 — Sedan vehicles
|
||||
### Phase 1 — Sedan vehicles — DONE
|
||||
|
||||
- New sedan meshes through the Blender asset pipeline (pattern:
|
||||
`gen_sokoban_assets.py`), using the reference models
|
||||
@@ -213,15 +213,149 @@ cd build-vscode/src/features/editScene/demos/demo-taxi
|
||||
in Phase 11.
|
||||
- Car-tuned `VehicleComponent`: front-wheel steering (no `rearSteer`),
|
||||
no fork, higher `maxTorque`/gearing than the forklift, sedan
|
||||
`cameraDistance`/`cameraHeight`, `seatOffset`.
|
||||
`cameraDistance`/`cameraHeight`, multi-seat `seats` list,
|
||||
`seatCharacterScale`.
|
||||
- Demo-owned `animation_tree.json` (copy demo-sokoban's — it carries
|
||||
the "driving" locomotion state).
|
||||
the "driving" locomotion state, here mapped to the `sitting-chair`
|
||||
animation which fits a car cabin much better than the stool-sit
|
||||
`sitting`).
|
||||
- Two player sedans parked in the exterior scene near the content
|
||||
site, enterable via the existing `vehicle_drive` actuator action.
|
||||
Only one of them is the taxi and starts the taxi loop; the other is
|
||||
for plain driving.
|
||||
site. Each has 4 seats (`VehicleComponent::seats`: driver
|
||||
front-left, passenger front-right, rl/rr); each door child entity
|
||||
carries an actuator running a generic `vehicle_seat_*` action
|
||||
(vehicleEnter Lua node -> "vehicle_enter" event with a `seat` param,
|
||||
the vehicle resolved by proximity), so the player sits at the seat
|
||||
whose door they used — driving only works from the driver seat
|
||||
(multi-seat support in `VehicleComponent`/`VehicleControllerSystem`:
|
||||
seat occupancy, passengers ride without controls).
|
||||
- Headless: `--test-vehicle-drive`-equivalent for the sedan (spawn,
|
||||
enter, drive, steer, brake, exit) on a flat test scene.
|
||||
enter, drive, steer, brake, exit — plus a passenger-seat leg: enter
|
||||
passenger seat, no `PlayerControlledComponent`, W does not drive) on
|
||||
a flat test scene.
|
||||
|
||||
**As built.** Generator `assets/blender/scripts/gen_taxi_assets.py`
|
||||
(registered in `assets/blender/vehicles/CMakeLists.txt`) produces
|
||||
`assets/blender/vehicles/sedan-a.blend` + `sedan-taxi.blend`; the
|
||||
vehicle export stages into `resources/vehicles/`. When hand-modeling
|
||||
replacement sedans (or any new car), follow
|
||||
`assets/blender/vehicles/CAR_MODELING.md` — it documents the full
|
||||
contract (axis/origin rules, required parts and hinge pivots, cabin
|
||||
dimensions matching the seated character, scene JSON wiring, glass
|
||||
material naming, multi-look strategy):
|
||||
|
||||
- Bodies: `sedan-a-blue/red/grey.mesh`, `sedan-taxi.mesh` (yellow,
|
||||
roof sign). Roof ended up 1.60 m above ground, not 1.2 m — a seated
|
||||
character's head clips through a 1.2 m roof. The side skirts
|
||||
(sills + front/rear side panels) reach 9 cm off the ground so the
|
||||
sit pose's feet (which dangle below the floor pan) stay hidden from
|
||||
side views.
|
||||
- Hinge-local part meshes per body: `-door-fl/-fr/-rl/-rr`, `-hood`,
|
||||
`-trunk`; shared `sedan-wheel.mesh` + `sedan-steering-wheel.mesh`.
|
||||
Hinge pivots in chassis space: doors FL/RL (left = +X) at
|
||||
(0.855, -0.10, 0.55) / (0.855, -0.10, -0.46), FR/RR mirrored at
|
||||
x = -0.855; hood (0, 0.17, 0.75); trunk (0, 0.27, -1.35). Scene
|
||||
entities hang the parts as children at those pivots.
|
||||
- Wheels at (±0.8, -0.25, ±1.5), r = 0.33, w = 0.22.
|
||||
|
||||
Demo side: `demo_scene_vehicletest.json` (flat 200 x 200 floor —
|
||||
sedans outrun the 60 x 60 interior floor; mesh
|
||||
`DemoFloorPlaneVehicleTest` created in `createDemoResources()`) with
|
||||
`sedan1` (blue), and `sedan_taxi` (id 600, (4006, 10.8, 3965)) +
|
||||
`sedan_plain` (id 601, (4018, 10.8, 3965)) in
|
||||
`demo_scene_exterior.json`. Each sedan has a 4-seat
|
||||
`VehicleComponent::seats` list (driver/passenger at
|
||||
(±0.35, -0.22, 0.25), rl/rr at (±0.35, -0.22, -0.35), driver =
|
||||
front-left) and `seatCharacterScale` 0.85 — the stock chair-sit pose
|
||||
is proportioned for a chair (butt-to-feet 0.76 m), so the seated
|
||||
character is scaled down a little to fit the cabin (head 4 cm under
|
||||
the headliner, feet above the skirts); the scale is applied on enter
|
||||
and restored on exit by `VehicleControllerSystem`. Each of the 4
|
||||
door children carries an actuator with a `vehicle_seat_driver` /
|
||||
`vehicle_seat_passenger` / `vehicle_seat_rl` / `vehicle_seat_rr`
|
||||
action (generic actions in `lua-scripts/data2.lua` sending
|
||||
"vehicle_enter" with a `seat` param; empty `vehicle` param = nearest
|
||||
vehicle to the player).
|
||||
`VehicleComponent`: maxTorque 300, engineBrake 0.5, front steering
|
||||
(35 deg), rear driven, handbrake 300, suspension 0.1/0.35/1.8/0.7,
|
||||
cameraDistance 6.0, cameraHeight 1.6, steering wheel at
|
||||
(0.35, 0.45, 0.2) tilt 25 deg ratio 4.
|
||||
|
||||
Window glass: the exported `sedan-glass` is plain opaque (hides the
|
||||
cabin completely). `fixupSedanGlassMaterial()` (demo_main.cpp) makes
|
||||
`sedan-glass` alpha-blended and clones an opaque
|
||||
`sedan-glass-opaque`; `SedanGlassLodListener` swaps every vehicle's
|
||||
glass submeshes between the two by camera distance (10 m threshold) —
|
||||
Ogre 14 no longer applies `Material::setLodLevels` to entities, so a
|
||||
real LOD material never switches.
|
||||
|
||||
**sedan-v2 (hand-modeled base sedan, current reference).** The
|
||||
hand-modeled `assets/blender/vehicles/sedan-v2.blend` replaced the
|
||||
procedural sedan as the base plain sedan (`sedan1` in
|
||||
`demo_scene_vehicletest.json`, `sedan_plain` in the exterior scene).
|
||||
It goes through the new convention-based generator
|
||||
`assets/blender/scripts/gen_vehicle.py` (`VEHICLES_GEN_SRC` in
|
||||
`assets/blender/vehicles/CMakeLists.txt`): names parts by convention
|
||||
(`* Tire`, `* Door`, `* hood`, `* trunk`, `* Steering`, `seat_*`
|
||||
empties — exactly one with "driver" in the name), normalizes
|
||||
wheel/steering mesh axes, renames mesh data/materials to
|
||||
`sedan-v2-*`, unpacks the color atlas to `sedan-v2-atlas.png`, and
|
||||
emits `sedan-v2.vehicle.json` — a complete scene entity (box collider
|
||||
from the shell bounds, wheels with suspension attach lifted by
|
||||
L_rest = maxLength - g/(2*pi*freq)^2 so the car rides at the modeled
|
||||
stance, seats from the empties, door/hood/trunk children with
|
||||
`vehicle_seat_*` actuators). Seat pins are the character ROOT
|
||||
position — the `driving` state now plays the new `sitting-vehicle`
|
||||
animation (authored so the base position is the seat point; no
|
||||
offsets, `seatCharacterScale` 1.0). `sedan-v2-glass` was added to
|
||||
`kGlassMaterialNames` for the near/far glass swap. The full contract
|
||||
is `assets/blender/vehicles/CAR_MODELING.md`; the taxi variant of
|
||||
sedan-v2 is next. One engine fix this exposed:
|
||||
`AnimationTreeSystem` now disables animations that fall out of the
|
||||
evaluated set in a single frame (a large-deltaTime fade-out step used
|
||||
to leave the old animation enabled at its last weight forever — the
|
||||
stuck `idle` lifted the seated pose through the roof).
|
||||
|
||||
Tuning after the first drives: the stock suspension (1.8 Hz / 0.7
|
||||
damping) was pogo-stiff, so gen_vehicle.py now emits 1.3 Hz / 0.6.
|
||||
And stock Jolt tire friction (peak 1.2 combined with ground via
|
||||
sqrt) drove like wet ice at speed, so `VehicleComponent` grew
|
||||
`tireFrictionLongitudinal` / `tireFrictionLateral` curve multipliers
|
||||
(1.0 = stock; sedans use 1.3 / 3.0 — measured with
|
||||
`--test-vehicle-turn`: full lock at 15.5 m/s turns 44 deg at stock
|
||||
grip, 88 deg at 3.0; editable in the Vehicle editor, serialized).
|
||||
The high grip made hard turns trip the car toward two wheels, so
|
||||
`antiRollBarStiffness` (Jolt VehicleAntiRollBar per axle pair, sedans
|
||||
use 2000) was added the same way, and VehicleSystem now applies a
|
||||
righting torque past ~35 deg of tilt (plus roll rocking damping past
|
||||
~5 deg) so a car stuck on two wheels recovers on its own —
|
||||
`--test-vehicle-righting` rolls sedan1 50 deg and requires it back
|
||||
near-upright. Exiting also got two fixes: the E/F/I/Space pressed
|
||||
edges now ignore SDL key repeats (holding E no longer re-fires the
|
||||
door actuators), and after an exit the E key must be released once
|
||||
before `vehicle_enter` is accepted again
|
||||
(VehicleControllerSystem::m_eReleaseRequired), and the exit spot is
|
||||
seat-aware: the character steps out beside the door of the seat it
|
||||
actually occupied (own side at the seat's chassis-space row first,
|
||||
then the opposite side of the same row, then behind/ahead of the car)
|
||||
instead of always beside the chassis center. The drive test's
|
||||
passenger leg asserts the exit lands on the seat's side. Wheel
|
||||
visuals: Jolt reports every wheel with the same axle direction, so a
|
||||
single shared wheel mesh had its inner face outward on the right side —
|
||||
`VehicleSystem::postPhysicsUpdate` now flips right-side (chassis -X)
|
||||
wheel visuals 180 deg about the local forward axis; no mirrored mesh
|
||||
needed.
|
||||
Note the scene JSONs hold a merged COPY of the
|
||||
generated entity — after editing the blend, run the single
|
||||
`update_vehicles` build target (assets/blender/vehicles/CMakeLists.txt):
|
||||
it re-exports changed blends, re-stages the editScene resources and
|
||||
re-merges both demo-taxi scenes via
|
||||
`demos/demo-taxi/merge_vehicle.py` (preserves id + transform).
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
./demoTaxi --headless --test-vehicle-drive demo_scene_vehicletest.json
|
||||
./demoTaxi --headless --test-vehicle-drive # exterior streaming terrain
|
||||
```
|
||||
|
||||
### Phase 2 — Road geometry & compliance improvements
|
||||
|
||||
@@ -375,8 +509,8 @@ taxi-specific):
|
||||
- Passenger NPCs waiting at curbs/POIs; hail interaction (E prompt via
|
||||
ActuatorSystem or proximity hail while driving slowly).
|
||||
- NPC boarding/alighting: walk to the car door, play sit state, ride
|
||||
as passenger (new passenger-seat support — vehicle carries extra
|
||||
seated NPCs; extends `VehicleComponent` with a seat list), walk away
|
||||
as passenger (the Phase 1 `VehicleComponent::seats` list tracks
|
||||
occupancy for the player; extend it to NPC occupants), walk away
|
||||
at dropoff.
|
||||
- Destination assignment: passenger names a POI/curb from the
|
||||
generated town (any settlement in the world); route distance
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,688 @@
|
||||
{
|
||||
"actionDatabase": {
|
||||
"actions": [
|
||||
{
|
||||
"behaviorTree": {
|
||||
"children": [
|
||||
{
|
||||
"name": "vehicleEnter",
|
||||
"params": "seat=driver",
|
||||
"type": "luaTask"
|
||||
}
|
||||
],
|
||||
"type": "sequence"
|
||||
},
|
||||
"cost": 1,
|
||||
"effects": {
|
||||
"bits": 0,
|
||||
"mask": 0
|
||||
},
|
||||
"name": "vehicle_seat_driver",
|
||||
"preconditions": {
|
||||
"bits": 0,
|
||||
"mask": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"behaviorTree": {
|
||||
"children": [
|
||||
{
|
||||
"name": "vehicleEnter",
|
||||
"params": "seat=passenger",
|
||||
"type": "luaTask"
|
||||
}
|
||||
],
|
||||
"type": "sequence"
|
||||
},
|
||||
"cost": 1,
|
||||
"effects": {
|
||||
"bits": 0,
|
||||
"mask": 0
|
||||
},
|
||||
"name": "vehicle_seat_passenger",
|
||||
"preconditions": {
|
||||
"bits": 0,
|
||||
"mask": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"behaviorTree": {
|
||||
"children": [
|
||||
{
|
||||
"name": "vehicleEnter",
|
||||
"params": "seat=rl",
|
||||
"type": "luaTask"
|
||||
}
|
||||
],
|
||||
"type": "sequence"
|
||||
},
|
||||
"cost": 1,
|
||||
"effects": {
|
||||
"bits": 0,
|
||||
"mask": 0
|
||||
},
|
||||
"name": "vehicle_seat_rl",
|
||||
"preconditions": {
|
||||
"bits": 0,
|
||||
"mask": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"behaviorTree": {
|
||||
"children": [
|
||||
{
|
||||
"name": "vehicleEnter",
|
||||
"params": "seat=rr",
|
||||
"type": "luaTask"
|
||||
}
|
||||
],
|
||||
"type": "sequence"
|
||||
},
|
||||
"cost": 1,
|
||||
"effects": {
|
||||
"bits": 0,
|
||||
"mask": 0
|
||||
},
|
||||
"name": "vehicle_seat_rr",
|
||||
"preconditions": {
|
||||
"bits": 0,
|
||||
"mask": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"bitNames": [
|
||||
{
|
||||
"index": 1,
|
||||
"name": "hungry"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "thirsty"
|
||||
}
|
||||
],
|
||||
"goals": []
|
||||
},
|
||||
"bookmarks": [],
|
||||
"entities": [
|
||||
{
|
||||
"children": [],
|
||||
"id": 4294967794,
|
||||
"light": {
|
||||
"castShadows": false,
|
||||
"constantAttenuation": 1.0,
|
||||
"diffuseColor": {
|
||||
"a": 1.0,
|
||||
"b": 1.0,
|
||||
"g": 1.0,
|
||||
"r": 1.0
|
||||
},
|
||||
"direction": {
|
||||
"x": 0.30000001192092896,
|
||||
"y": -1.0,
|
||||
"z": 0.20000000298023224
|
||||
},
|
||||
"intensity": 1.0,
|
||||
"lightType": "directional",
|
||||
"linearAttenuation": 0.0,
|
||||
"quadraticAttenuation": 0.0,
|
||||
"range": 100.0,
|
||||
"specularColor": {
|
||||
"a": 1.0,
|
||||
"b": 0.5,
|
||||
"g": 0.5,
|
||||
"r": 0.5
|
||||
},
|
||||
"spotlightFalloff": 1.0,
|
||||
"spotlightInnerAngle": 30.0,
|
||||
"spotlightOuterAngle": 45.0
|
||||
},
|
||||
"name": {
|
||||
"name": "demo_light"
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 10.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"children": [],
|
||||
"collider": {
|
||||
"halfHeight": 1.0,
|
||||
"meshName": "",
|
||||
"offset": {
|
||||
"x": 0.0,
|
||||
"y": -0.10000000149011612,
|
||||
"z": 0.0
|
||||
},
|
||||
"parameters": {
|
||||
"x": 100.0,
|
||||
"y": 0.10000000149011612,
|
||||
"z": 100.0
|
||||
},
|
||||
"radius": 0.5,
|
||||
"rotationOffset": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"shapeType": "box"
|
||||
},
|
||||
"id": 4294967792,
|
||||
"name": {
|
||||
"name": "demo_floor"
|
||||
},
|
||||
"renderable": {
|
||||
"meshName": "DemoFloorPlaneVehicleTest",
|
||||
"visible": true
|
||||
},
|
||||
"rigidBody": {
|
||||
"bodyType": "static",
|
||||
"enabled": true,
|
||||
"friction": 0.800000011920929,
|
||||
"isSensor": false,
|
||||
"mass": 1.0,
|
||||
"restitution": 0.0
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"characterSpawner": {
|
||||
"despawnDistance": 200.0,
|
||||
"registryId": 2,
|
||||
"spawnDistance": 100.0
|
||||
},
|
||||
"children": [],
|
||||
"id": 4294967790,
|
||||
"name": {
|
||||
"name": "s1"
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.10288965702056885,
|
||||
"z": -6.0
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"children": [],
|
||||
"id": 4294967789,
|
||||
"name": {
|
||||
"name": "player"
|
||||
},
|
||||
"playerController": {
|
||||
"actuatorColor": [
|
||||
0.0,
|
||||
0.4000000059604645,
|
||||
1.0
|
||||
],
|
||||
"actuatorCooldown": 1.5,
|
||||
"actuatorDistance": 25.0,
|
||||
"actuatorLabelFontSize": 12.0,
|
||||
"cameraMode": 0,
|
||||
"distantCircleRadius": 8.0,
|
||||
"fpsBoneName": "Head",
|
||||
"idleState": "idle",
|
||||
"locomotionStateMachine": "locomotion",
|
||||
"mouseSensitivity": 0.20000000298023224,
|
||||
"nearCircleRadius": 14.0,
|
||||
"runState": "running",
|
||||
"swimFastState": "swimming-fast",
|
||||
"swimIdleState": "swim-idle",
|
||||
"swimState": "swimming",
|
||||
"targetCharacterName": "s1",
|
||||
"tpsDistance": 3.0,
|
||||
"tpsHeight": 2.0,
|
||||
"walkState": "walking"
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [],
|
||||
"name": {
|
||||
"name": "sedan1_door_rl"
|
||||
},
|
||||
"renderable": {
|
||||
"meshName": "sedan-v2-door-rl.mesh",
|
||||
"visible": true
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": 0.9192,
|
||||
"y": -0.2869,
|
||||
"z": -0.132
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
},
|
||||
"actuator": {
|
||||
"actionNames": [
|
||||
"vehicle_seat_rl"
|
||||
],
|
||||
"height": 2.0,
|
||||
"radius": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"children": [],
|
||||
"name": {
|
||||
"name": "sedan1_door_rr"
|
||||
},
|
||||
"renderable": {
|
||||
"meshName": "sedan-v2-door-rr.mesh",
|
||||
"visible": true
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": -0.9192,
|
||||
"y": -0.2869,
|
||||
"z": -0.132
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
},
|
||||
"actuator": {
|
||||
"actionNames": [
|
||||
"vehicle_seat_rr"
|
||||
],
|
||||
"height": 2.0,
|
||||
"radius": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"children": [],
|
||||
"name": {
|
||||
"name": "sedan1_door_fl"
|
||||
},
|
||||
"renderable": {
|
||||
"meshName": "sedan-v2-door-fl.mesh",
|
||||
"visible": true
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": 0.9192,
|
||||
"y": -0.2868,
|
||||
"z": 0.801
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
},
|
||||
"actuator": {
|
||||
"actionNames": [
|
||||
"vehicle_seat_driver"
|
||||
],
|
||||
"height": 2.0,
|
||||
"radius": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"children": [],
|
||||
"name": {
|
||||
"name": "sedan1_door_fr"
|
||||
},
|
||||
"renderable": {
|
||||
"meshName": "sedan-v2-door-fr.mesh",
|
||||
"visible": true
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": -0.9192,
|
||||
"y": -0.2868,
|
||||
"z": 0.801
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
},
|
||||
"actuator": {
|
||||
"actionNames": [
|
||||
"vehicle_seat_passenger"
|
||||
],
|
||||
"height": 2.0,
|
||||
"radius": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"children": [],
|
||||
"name": {
|
||||
"name": "sedan1_hood"
|
||||
},
|
||||
"renderable": {
|
||||
"meshName": "sedan-v2-hood.mesh",
|
||||
"visible": true
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": -0.0,
|
||||
"y": 0.266,
|
||||
"z": 0.9992
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"children": [],
|
||||
"name": {
|
||||
"name": "sedan1_trunk"
|
||||
},
|
||||
"renderable": {
|
||||
"meshName": "sedan-v2-trunk.mesh",
|
||||
"visible": true
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.2744,
|
||||
"z": -1.446
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"halfHeight": 1.0,
|
||||
"meshName": "",
|
||||
"offset": {
|
||||
"x": 0.0,
|
||||
"y": 0.1535,
|
||||
"z": -0.0629
|
||||
},
|
||||
"parameters": {
|
||||
"x": 1.0107,
|
||||
"y": 0.6126,
|
||||
"z": 2.4834
|
||||
},
|
||||
"radius": 0.5,
|
||||
"rotationOffset": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"shapeType": "box"
|
||||
},
|
||||
"name": {
|
||||
"name": "sedan1"
|
||||
},
|
||||
"renderable": {
|
||||
"meshName": "sedan-v2.mesh",
|
||||
"visible": true
|
||||
},
|
||||
"rigidBody": {
|
||||
"bodyType": "dynamic",
|
||||
"enabled": true,
|
||||
"friction": 0.8,
|
||||
"isSensor": false,
|
||||
"mass": 1200.0,
|
||||
"restitution": 0.0
|
||||
},
|
||||
"transform": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 1.5,
|
||||
"z": 0.0
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0,
|
||||
"z": 1.0
|
||||
}
|
||||
},
|
||||
"vehicle": {
|
||||
"cameraDistance": 6.0,
|
||||
"cameraHeight": 1.6,
|
||||
"engineBrake": 0.5,
|
||||
"maxPitchRollAngleDeg": 60.0,
|
||||
"maxTorque": 300.0,
|
||||
"rearSteer": false,
|
||||
"seatOffset": {
|
||||
"x": 0.48,
|
||||
"y": -0.28,
|
||||
"z": 0.2012
|
||||
},
|
||||
"steeringRatio": 4.0,
|
||||
"steeringWheelMeshName": "sedan-v2-steering-wheel.mesh",
|
||||
"steeringWheelOffset": {
|
||||
"x": 0.4915,
|
||||
"y": 0.0807,
|
||||
"z": 0.601
|
||||
},
|
||||
"steeringWheelTiltDeg": 25.0,
|
||||
"wheelMeshName": "sedan-v2-wheel.mesh",
|
||||
"wheels": [
|
||||
{
|
||||
"driven": false,
|
||||
"maxHandBrakeTorque": 0.0,
|
||||
"maxSteerAngleDeg": 35.0,
|
||||
"position": {
|
||||
"x": 0.7805,
|
||||
"y": -0.2052,
|
||||
"z": 1.4806
|
||||
},
|
||||
"radius": 0.3918,
|
||||
"suspensionDamping": 0.6,
|
||||
"suspensionFrequency": 1.3,
|
||||
"suspensionMaxLength": 0.35,
|
||||
"suspensionMinLength": 0.1,
|
||||
"width": 0.3145
|
||||
},
|
||||
{
|
||||
"driven": false,
|
||||
"maxHandBrakeTorque": 0.0,
|
||||
"maxSteerAngleDeg": 35.0,
|
||||
"position": {
|
||||
"x": -0.7805,
|
||||
"y": -0.2052,
|
||||
"z": 1.4806
|
||||
},
|
||||
"radius": 0.3918,
|
||||
"suspensionDamping": 0.6,
|
||||
"suspensionFrequency": 1.3,
|
||||
"suspensionMaxLength": 0.35,
|
||||
"suspensionMinLength": 0.1,
|
||||
"width": 0.3145
|
||||
},
|
||||
{
|
||||
"driven": true,
|
||||
"maxHandBrakeTorque": 300.0,
|
||||
"maxSteerAngleDeg": 0.0,
|
||||
"position": {
|
||||
"x": 0.7805,
|
||||
"y": -0.2052,
|
||||
"z": -1.2806
|
||||
},
|
||||
"radius": 0.3918,
|
||||
"suspensionDamping": 0.6,
|
||||
"suspensionFrequency": 1.3,
|
||||
"suspensionMaxLength": 0.35,
|
||||
"suspensionMinLength": 0.1,
|
||||
"width": 0.3145
|
||||
},
|
||||
{
|
||||
"driven": true,
|
||||
"maxHandBrakeTorque": 300.0,
|
||||
"maxSteerAngleDeg": 0.0,
|
||||
"position": {
|
||||
"x": -0.7805,
|
||||
"y": -0.2052,
|
||||
"z": -1.2806
|
||||
},
|
||||
"radius": 0.3918,
|
||||
"suspensionDamping": 0.6,
|
||||
"suspensionFrequency": 1.3,
|
||||
"suspensionMaxLength": 0.35,
|
||||
"suspensionMinLength": 0.1,
|
||||
"width": 0.3145
|
||||
}
|
||||
],
|
||||
"seats": [
|
||||
{
|
||||
"name": "driver",
|
||||
"offset": {
|
||||
"x": 0.48,
|
||||
"y": -0.28,
|
||||
"z": 0.2012
|
||||
},
|
||||
"driver": true
|
||||
},
|
||||
{
|
||||
"name": "passenger",
|
||||
"offset": {
|
||||
"x": -0.48,
|
||||
"y": -0.28,
|
||||
"z": 0.2012
|
||||
},
|
||||
"driver": false
|
||||
},
|
||||
{
|
||||
"name": "rl",
|
||||
"offset": {
|
||||
"x": 0.48,
|
||||
"y": -0.28,
|
||||
"z": -0.6032
|
||||
},
|
||||
"driver": false
|
||||
},
|
||||
{
|
||||
"name": "rr",
|
||||
"offset": {
|
||||
"x": -0.48,
|
||||
"y": -0.28,
|
||||
"z": -0.6032
|
||||
},
|
||||
"driver": false
|
||||
}
|
||||
],
|
||||
"seatCharacterScale": 1.0,
|
||||
"tireFrictionLongitudinal": 1.3,
|
||||
"tireFrictionLateral": 3.0,
|
||||
"antiRollBarStiffness": 2000.0
|
||||
},
|
||||
"id": 500
|
||||
}
|
||||
],
|
||||
"version": "1.0"
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Merge a generated vehicle entity (<name>.vehicle.json, produced by
|
||||
# assets/blender/scripts/gen_vehicle.py) into a demo scene JSON,
|
||||
# replacing the entity with the given name. The scene entity keeps
|
||||
# its id, name and transform (position/rotation/scale); everything
|
||||
# else (collider, vehicle, renderable, children) is replaced by the
|
||||
# generated fragment, with child entity names prefixed accordingly.
|
||||
#
|
||||
# This is how blend tweaks (seat empties, suspension, wheels, ...)
|
||||
# propagate into the demo scenes after re-running import_vehicles:
|
||||
#
|
||||
# cmake --build build-vscode --target import_vehicles -j4
|
||||
# python3 merge_vehicle.py demo_scene_vehicletest.json \
|
||||
# ../../../../../../resources/vehicles/sedan-v2.vehicle.json sedan1
|
||||
#
|
||||
# (paths relative to the build demo dir; the build scene JSONs are
|
||||
# symlinks to the source dir, so merging there updates the source).
|
||||
#
|
||||
# Usage:
|
||||
# merge_vehicle.py <scene.json> <vehicle.json> <entityName>
|
||||
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 4:
|
||||
sys.exit("usage: merge_vehicle.py <scene.json> <vehicle.json> "
|
||||
"<entityName>")
|
||||
scene_path, vehicle_path, entity_name = sys.argv[1:4]
|
||||
|
||||
with open(scene_path) as f:
|
||||
scene = json.load(f)
|
||||
with open(vehicle_path) as f:
|
||||
generated = json.load(f)["entities"][0]
|
||||
gen_base = generated["name"]["name"]
|
||||
|
||||
target = None
|
||||
for e in scene["entities"]:
|
||||
if e.get("name", {}).get("name") == entity_name:
|
||||
target = e
|
||||
break
|
||||
if target is None:
|
||||
sys.exit("merge_vehicle: entity '%s' not found in %s" %
|
||||
(entity_name, scene_path))
|
||||
|
||||
# Rename the generated entity and its children to the target name.
|
||||
def rename(node):
|
||||
if "name" in node:
|
||||
node["name"]["name"] = node["name"]["name"].replace(
|
||||
gen_base, entity_name, 1)
|
||||
for c in node.get("children", []):
|
||||
rename(c)
|
||||
|
||||
rename(generated)
|
||||
|
||||
generated["id"] = target["id"]
|
||||
generated["transform"] = target["transform"]
|
||||
target.clear()
|
||||
target.update(generated)
|
||||
|
||||
with open(scene_path, "w") as f:
|
||||
json.dump(scene, f, indent=2)
|
||||
f.write("\n")
|
||||
print("merge_vehicle: replaced '%s' in %s from %s" %
|
||||
(entity_name, scene_path, vehicle_path))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -17,7 +17,8 @@
|
||||
file(COPY "${EDITSCENE_SRC}/resources.cfg" DESTINATION "${DEMO_DIR}")
|
||||
file(COPY "${SRC_DIR}/project.json" DESTINATION "${DEMO_DIR}")
|
||||
|
||||
foreach(f demo_scene_interior.json demo_scene_exterior.json)
|
||||
foreach(f demo_scene_interior.json demo_scene_exterior.json
|
||||
demo_scene_vehicletest.json)
|
||||
set(link "${DEMO_DIR}/${f}")
|
||||
if(EXISTS "${link}" OR IS_SYMLINK "${link}")
|
||||
file(REMOVE "${link}")
|
||||
@@ -52,14 +53,18 @@ endforeach()
|
||||
|
||||
# Runtime config JSONs loaded at startup relative to the CWD (game mode
|
||||
# reads startup_menu.json, the registries read the rest — the demo needs
|
||||
# character_registry.json for the spawner's registryId 2 and
|
||||
# animation_tree.json for the character's "male1_6" animation tree). They
|
||||
# character_registry.json for the spawner's registryId 2). They
|
||||
# only exist after the editor/game has run once; copy them when present so
|
||||
# the demo behaves the same as when run from the editor binary directory.
|
||||
foreach(f startup_menu.json character_registry.json character_class.json
|
||||
items.json item_state.json inventory_config.json
|
||||
animation_tree.json)
|
||||
items.json item_state.json inventory_config.json)
|
||||
if(EXISTS "${EDITSCENE_BIN}/${f}")
|
||||
file(COPY "${EDITSCENE_BIN}/${f}" DESTINATION "${DEMO_DIR}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# animation_tree.json is demo-owned (source tree, versioned with the demo;
|
||||
# it carries the "driving" locomotion state used by the sedan seats).
|
||||
# COPIED, not symlinked: AnimationTreeRegistry auto-saves on runtime tree
|
||||
# migrations and must not write through into the source tree.
|
||||
file(COPY "${SRC_DIR}/animation_tree.json" DESTINATION "${DEMO_DIR}")
|
||||
|
||||
Reference in New Issue
Block a user