Ride: roadside figures always visible, statue-scale, glowing
Forced actor slots on like the billboard (sparse setups hid them), figures normalized to landmark scale against houses, crew-like emissive so they read at night. They were present but effectively invisible: gated, unlit, person-scale at the frame edge.
This commit is contained in:
@@ -1105,17 +1105,21 @@ export const ride = {
|
||||
const dense = (arrangement % 2 === 1);
|
||||
const showUpTo = dense ? n : Math.max(3, Math.floor(n * 0.45));
|
||||
// A billboard shot with a hidden billboard is an empty road: the
|
||||
// board's own slot is always on while it is the subject.
|
||||
// board's own slot is always on while it is the subject. Actor
|
||||
// figures likewise always show: they are the cast, not dressing,
|
||||
// and at most two slots ever hold them.
|
||||
const forced = billboard ? billSlotIndex(instance) : -1;
|
||||
for (let i = 0; i < n; i++) {
|
||||
instance.roadside.children[i].visible = opacity > 0.001 && (i < showUpTo || i === forced);
|
||||
const kid = instance.roadside.children[i];
|
||||
const isActor = !!kid.userData.actorSlot;
|
||||
kid.visible = opacity > 0.001 && (i < showUpTo || i === forced || isActor);
|
||||
}
|
||||
}
|
||||
// Roadside actors: figures of the track's cast standing among the
|
||||
// props on some builds (seeded at build; static all video, so they
|
||||
// stream past with their slot and never pop). Grown here, on first
|
||||
// update, because identity only arrives via update — the crew pattern.
|
||||
// They turn slowly to feel alive; analytic f(t), seek-stable.
|
||||
// They glance around to feel alive; analytic f(t), seek-stable.
|
||||
if (instance.roadside && identity && actorSpec && actorSpec.form) {
|
||||
for (const g of instance.roadside.children) {
|
||||
if (!g.userData.actorSlot) continue;
|
||||
@@ -1133,20 +1137,24 @@ export const ride = {
|
||||
const c = pal[pPal % pal.length] || pal[0];
|
||||
m.material = new T.MeshStandardMaterial({
|
||||
color: new T.Color(c[0], c[1], c[2]),
|
||||
emissive: new T.Color(c[0] * 0.3, c[1] * 0.3, c[2] * 0.3),
|
||||
emissiveIntensity: 1.0,
|
||||
roughness: 0.5, metalness: 0.08,
|
||||
transparent: opacity < 0.999, opacity,
|
||||
});
|
||||
fig.add(m);
|
||||
}
|
||||
// Feet on the ground, person-scale: normalize the form
|
||||
// to ~1.6 units tall (houses run 2-4) and plant the
|
||||
// lowest point at the roadside level regardless of
|
||||
// the form's own extent or origin. Local box
|
||||
// (unparented) over slot scale: exact.
|
||||
// Feet on the ground, landmark-scale: person-scale
|
||||
// figures are invisible from chase distance, so these
|
||||
// stand ~2.6 units against 2-4 unit houses — statues
|
||||
// of the cast among the props. Lowest point planted
|
||||
// at the roadside level regardless of the form's own
|
||||
// extent or origin. Local box (unparented) over slot
|
||||
// scale: exact.
|
||||
if (fig.children.length) {
|
||||
const _box = new T.Box3().setFromObject(fig);
|
||||
const _h = _box.max.y - _box.min.y;
|
||||
const _s = _h > 1e-6 ? 1.6 / _h : 1;
|
||||
const _s = _h > 1e-6 ? 2.6 / _h : 1;
|
||||
fig.scale.setScalar(_s);
|
||||
fig.position.y = -1.15 / g.scale.x - _s * _box.min.y;
|
||||
}
|
||||
@@ -1168,6 +1176,7 @@ export const ride = {
|
||||
? actorSpec.paletteMap[pIdx % actorSpec.paletteMap.length] : pIdx;
|
||||
const c = pal[pPal % pal.length] || pal[0];
|
||||
m.material.color.setRGB(c[0], c[1], c[2]);
|
||||
m.material.emissive.setRGB(c[0] * 0.3, c[1] * 0.3, c[2] * 0.3);
|
||||
m.material.opacity = opacity;
|
||||
m.material.transparent = opacity < 0.999;
|
||||
m.visible = opacity > 0.01;
|
||||
|
||||
Reference in New Issue
Block a user