Ride: proper 2/4 seating plus doors, dash, console, wheel

Two rows of two like a real car (2 riders: 2-seater; more: 4-seater with one seat left empty); riders sit on cushions against backrests with headrests, driver ahead of the wheel. Long painted doors with handles, full-width dashboard with dial strip, center console with shifter glow, torus steering wheel on a column. Fender arches fattened. Rng cadence preserved per rider so downstream draws don't move.
This commit is contained in:
Dejvino
2026-09-21 18:55:09 +02:00
parent 89f295532a
commit ac6654b0dd
+84 -7
View File
@@ -552,6 +552,10 @@ export const ride = {
const hood = add(new T.Mesh(new T.BoxGeometry(1.5, 0.24, 1.15), paintMat()));
hood.position.set(0, 0.18, -1.6);
hood.rotation.x = -0.07;
// Hood spine: breaks the flat table read.
const spine = add(new T.Mesh(new T.BoxGeometry(0.28, 0.07, 1.0), paintMat()));
spine.position.set(0, 0.3, -1.6);
spine.rotation.x = -0.07;
// Trunk deck behind the cabin, meeting its lower edge.
const trunk = add(new T.Mesh(new T.BoxGeometry(1.5, 0.2, 0.8), paintMat()));
trunk.position.set(0, 0.2, 1.15);
@@ -565,10 +569,10 @@ export const ride = {
const skirt = add(new T.Mesh(new T.BoxGeometry(0.12, 0.14, 2.0), trimMat));
skirt.position.set(side * 0.93, -0.5, -0.15);
}
// Fenders: half-torus arches over each wheel. Torus arc 0..π
// spans the upper half in XY; yawed 90° it arches across the
// wheel in the rolling plane.
const fenderGeo = new T.TorusGeometry(0.5, 0.1, 8, 12, Math.PI);
// Fenders: half-torus arches over each wheel. Torus arc 0..π
// spans the upper half in XY; yawed 90° it arches across the
// wheel in the rolling plane.
const fenderGeo = new T.TorusGeometry(0.5, 0.12, 8, 12, Math.PI);
for (const [wx, wz] of [[-0.95, 1.05], [0.95, 1.05], [-0.95, -1.35], [0.95, -1.35]]) {
const fender = add(new T.Mesh(fenderGeo, paintMat()));
fender.rotation.y = Math.PI / 2;
@@ -622,6 +626,48 @@ export const ride = {
const pipe = add(new T.Mesh(pipeGeo, pipeMat));
pipe.position.set(side * 0.35, -0.45, 1.7);
}
// Doors: long painted panels with handles. One pair, front
// and rear rows alike on a convertible — they flank the cabin
// and clear the arches vertically (door bottoms sit above the
// wheel tops).
for (const side of [-1, 1]) {
const door = add(new T.Mesh(new T.BoxGeometry(0.08, 0.5, 1.9), paintMat()));
door.position.set(side * 0.89, 0.15, -0.05);
const handle = add(new T.Mesh(new T.BoxGeometry(0.04, 0.05, 0.22), trimMat));
handle.position.set(side * 0.945, 0.28, 0.35);
}
// Dashboard across the cabin front with a dial strip on top,
// where high chase angles can see it.
const dashPanel = add(new T.Mesh(new T.BoxGeometry(1.5, 0.12, 0.4), trimMat));
dashPanel.position.set(0, 0.6, -0.85);
const dials = add(new T.Mesh(
new T.BoxGeometry(0.7, 0.02, 0.06),
new T.MeshStandardMaterial({
color: new T.Color(0.02, 0.03, 0.04),
emissive: new T.Color(0.5, 0.7, 0.85),
emissiveIntensity: 0.8,
roughness: 0.5,
})));
dials.position.set(0, 0.665, -0.85);
// Center console between the seats with a shifter-line glow.
const console_ = add(new T.Mesh(new T.BoxGeometry(0.16, 0.16, 1.1), trimMat));
console_.position.set(0, 0.64, 0.15);
const consoleGlow = add(new T.Mesh(
new T.BoxGeometry(0.05, 0.02, 0.8),
new T.MeshStandardMaterial({
color: new T.Color(0.02, 0.03, 0.04),
emissive: new T.Color(0.5, 0.7, 0.85),
emissiveIntensity: 0.6,
roughness: 0.5,
})));
consoleGlow.position.set(0, 0.725, 0.15);
// Steering wheel ahead of the front-left seat.
const column = add(new T.Mesh(new T.BoxGeometry(0.05, 0.05, 0.3), trimMat));
column.position.set(-0.33, 0.7, -0.42);
column.rotation.x = 0.2;
const wheel = add(new T.Mesh(new T.TorusGeometry(0.11, 0.025, 8, 18), trimMat));
wheel.position.set(-0.33, 0.76, -0.55);
wheel.rotation.x = -0.5;
}
// Wheels: four dark torus + hub, spin with speed (see below).
@@ -717,6 +763,33 @@ export const ride = {
bodyParts = body.children.slice();
} catch { bodyParts = null; }
const count = vs && vs.population ? Math.max(2, Math.min(4, vs.population.count | 0)) : 2;
// Two rows of two, like a real car: a 2-rider track gets a
// 2-seater, anything more a 4-seater (3 riders leave one seat
// empty, which is natural). Riders take seats in order, driver
// front-left where the wheel is.
const SEATS = count > 2
? [{ x: -0.33, z: -0.15 }, { x: 0.33, z: -0.15 },
{ x: -0.33, z: 0.45 }, { x: 0.33, z: 0.45 }]
: [{ x: -0.33, z: -0.15 }, { x: 0.33, z: -0.15 }];
const leatherMat = new T.MeshStandardMaterial({
color: new T.Color(0.06, 0.06, 0.07), roughness: 0.8, metalness: 0.05,
transparent: opacity < 0.999, opacity,
});
for (const seat of SEATS) {
const cushion = new T.Mesh(new T.BoxGeometry(0.42, 0.12, 0.42), leatherMat);
cushion.position.set(seat.x, 0.62, seat.z);
instance.car.add(cushion);
instance.bodyMeshes.push(cushion);
const back = new T.Mesh(new T.BoxGeometry(0.4, 0.5, 0.12), leatherMat);
back.position.set(seat.x, 0.85, seat.z + 0.24);
back.rotation.x = -0.12;
instance.car.add(back);
instance.bodyMeshes.push(back);
const headrest = new T.Mesh(new T.BoxGeometry(0.2, 0.14, 0.1), leatherMat);
headrest.position.set(seat.x, 1.12, seat.z + 0.28);
instance.car.add(headrest);
instance.bodyMeshes.push(headrest);
}
for (let i = 0; i < count; i++) {
let m;
if (bodyParts && bodyParts.length) {
@@ -742,10 +815,14 @@ export const ride = {
}
const g = new T.Group();
g.add(m);
// Seat row: spread across the cabin width, heads above the glass.
const fx = (i - (count - 1) / 2) * 0.62 + (rng() - 0.5) * 0.1;
// Seated in order: butt on the cushion, back against the
// backrest. Same rng cadence as the old scatter row (four
// draws per rider, same order) so downstream draws don't move.
const seat = SEATS[i];
const jx = (rng() - 0.5) * 0.08;
const jz = (rng() - 0.5) * 0.06;
g.scale.setScalar(0.5);
g.position.set(fx, 0.78, -0.25 + (rng() - 0.5) * 0.3);
g.position.set(seat.x + jx, 0.78, seat.z + jz);
g.rotation.y = Math.PI + (rng() - 0.5) * 0.5;
g.userData.baseY = g.position.y;
g.userData.index = i;