1
0

feat: build deterministic freeway and Lumbridge EV v2

This commit is contained in:
2026-08-19 01:12:47 -07:00
parent 94de2d8bee
commit ddf814a657
15 changed files with 716 additions and 24 deletions
+2
View File
@@ -1,7 +1,9 @@
export {
MODEL_X_METRICS,
LUMBRIDGE_EV_METRICS,
advanceModelXWheels,
buildModelX,
buildLumbridgeEV,
cloneModelX,
createModelXMaterials,
disposeModelX,
+64 -10
View File
@@ -1,5 +1,5 @@
/**
* A procedural, unbadged black Model X-style electric crossover.
* Lumbridge EV-01: an original, unbadged procedural electric grand tourer.
*
* The asset is authored in metres with its origin on the road at the centre of
* the wheelbase. It faces -Z at yaw zero, matching the rest of Tera; +X is the
@@ -8,7 +8,8 @@
* sparse because this car is normally read from a corridor or chase camera.
*
* Build one rig and clone it. Clones share geometry and materials while their
* wheel and steering joints remain independent. Dispose the original only
* wheel and steering joints remain independent. Legacy Model-X API names are
* retained as serialized/realtime compatibility contracts, not design intent.
* after every clone has left the scene.
*/
@@ -26,6 +27,9 @@ export const MODEL_X_METRICS = {
maxSteeringAngle: 0.62,
} as const;
/** Preferred product-facing name; MODEL_X_METRICS remains a compatibility alias. */
export const LUMBRIDGE_EV_METRICS = MODEL_X_METRICS;
export type ModelXDetail = "corridor" | "follow";
export interface ModelXMaterials {
@@ -87,30 +91,32 @@ const UNIT_PLANE = new THREE.PlaneGeometry(1, 1);
/** Default materials are intentionally untextured: no binary art and no UV dependency. */
export function createModelXMaterials(
paint: THREE.ColorRepresentation = 0x050607,
paint: THREE.ColorRepresentation = 0x465157,
): ModelXMaterials {
const body = new THREE.MeshPhysicalMaterial({
name: "model-x.paint",
color: paint,
metalness: 0.72,
roughness: 0.22,
roughness: 0.26,
clearcoat: 1,
clearcoatRoughness: 0.12,
emissive: 0x11191e,
emissiveIntensity: 0.72,
});
return {
paint: body,
glass: new THREE.MeshPhysicalMaterial({
name: "model-x.glass",
color: 0x101b22,
color: 0x193746,
metalness: 0.12,
roughness: 0.12,
transparent: true,
opacity: 0.86,
opacity: 0.78,
side: THREE.DoubleSide,
}),
trim: new THREE.MeshStandardMaterial({
name: "model-x.trim",
color: 0x101214,
color: 0x272d31,
metalness: 0.68,
roughness: 0.3,
}),
@@ -122,9 +128,11 @@ export function createModelXMaterials(
}),
wheel: new THREE.MeshStandardMaterial({
name: "model-x.wheel",
color: 0x2d3135,
color: 0x515960,
metalness: 0.88,
roughness: 0.25,
emissive: 0x111519,
emissiveIntensity: 0.45,
}),
brake: new THREE.MeshStandardMaterial({
name: "model-x.brake",
@@ -136,14 +144,14 @@ export function createModelXMaterials(
name: "model-x.headlight",
color: 0xd9f4ff,
emissive: 0xb8eaff,
emissiveIntensity: 2.4,
emissiveIntensity: 3.2,
roughness: 0.16,
}),
tailLight: new THREE.MeshStandardMaterial({
name: "model-x.tail-light",
color: 0xff2433,
emissive: 0xd70918,
emissiveIntensity: 1.9,
emissiveIntensity: 2.8,
roughness: 0.2,
}),
};
@@ -376,6 +384,44 @@ function buildBody(materials: ModelXMaterials, detail: ModelXDetail): THREE.Grou
});
}
// EV-01 signature: continuous light blades and satin aero rails remain
// readable at corridor LOD without a badge or a borrowed grille shape.
batch.box(materials.headlight, {
position: [0, 0.89, -2.43],
scale: [1.28, 0.035, 0.028],
});
batch.box(materials.tailLight, {
position: [0, 0.98, 2.39],
scale: [1.34, 0.032, 0.026],
});
for (const side of [-1, 1]) {
batch.box(materials.wheel, {
position: [side * 0.985, 0.47, 0.12],
scale: [0.025, 0.06, 3.45],
});
}
if (detail === "follow") {
// A small real interior reads through the panoramic glazing in chase and
// driver cameras. It deliberately uses the pooled trim surface.
batch.box(materials.trim, {
position: [0, 1.05, -0.58],
scale: [1.45, 0.12, 0.34],
rotation: [-0.12, 0, 0],
});
for (const side of [-1, 1]) {
batch.box(materials.trim, {
position: [side * 0.38, 1.02, 0.08],
scale: [0.42, 0.52, 0.46],
rotation: [0.12, 0, 0],
});
batch.box(materials.trim, {
position: [side * 0.38, 1.33, 0.17],
scale: [0.32, 0.28, 0.2],
});
}
}
// Lower aero surfaces stop the black shell dissolving into the road.
batch.box(materials.trim, {
position: [0, 0.39, -1.92],
@@ -502,6 +548,9 @@ export function buildModelX(options: ModelXBuildOptions = {}): ModelXRig {
root.name = "model-x";
root.userData.kind = "vehicle";
root.userData.vehicleModel = "model-x";
root.userData.design = "lumbridge-ev-01";
root.userData.lod = detail;
root.userData.unbranded = true;
root.userData.forwardAxis = "-Z";
root.add(buildBody(materials, detail));
@@ -518,6 +567,11 @@ export function buildModelX(options: ModelXBuildOptions = {}): ModelXRig {
return { root, body: root.getObjectByName("model-x.body") as THREE.Group, wheels, ownsMaterials: !options.materials };
}
/** Preferred builder for the original Lumbridge EV visual. */
export function buildLumbridgeEV(options: ModelXBuildOptions = {}): ModelXRig {
return buildModelX(options);
}
/** Clone the hierarchy while sharing all immutable geometry and material resources. */
export function cloneModelX(source: ModelXRig): ModelXRig {
return resolveRig(source.root.clone(true), false);