fix: orient stop panels toward the road
Each stop's group faced world +Z regardless of the road's local tangent, so IDENTITÉS and GREETINGS showed mirrored text and the GREETINGS plane read as crossing the road. Compute yaw once per stop via atan2 from the anchor to pointAt(stop.t) so the panel's +Z always points at the road it belongs to. Lamp yaw is world-space absolute, so subtract the group's new rotation to keep its facing unchanged.
This commit is contained in:
@@ -30,6 +30,8 @@ function hash(id: string): number {
|
||||
}
|
||||
|
||||
// face the lamp's curved arm back toward the road, plus a per-stop wobble
|
||||
// (absolute world yaw — the caller compensates for the group's own facing
|
||||
// rotation so the arm keeps its world-space orientation)
|
||||
function lampYaw(stop: Stop): number {
|
||||
const tan = tangentAt(stop.t)
|
||||
const n = new Vector3(-tan.z, 0, tan.x)
|
||||
@@ -43,12 +45,20 @@ export function StopPanel({ stop, children, width = 340 }: {
|
||||
children: ReactNode
|
||||
width?: number
|
||||
}) {
|
||||
const pos = useMemo(() => stopAnchor(stop), [stop])
|
||||
// orient the group so its +Z (the sign/panel's readable face) points at
|
||||
// the road point where the bus stops, instead of always facing world +Z —
|
||||
// otherwise, depending on which side of the curve the stop sits on, the
|
||||
// panel can show its back to the arriving bus.
|
||||
const { pos, rotationY } = useMemo(() => {
|
||||
const p = stopAnchor(stop)
|
||||
const road = pointAt(stop.t)
|
||||
return { pos: p, rotationY: Math.atan2(road.x - p.x, road.z - p.z) }
|
||||
}, [stop])
|
||||
const active = useRide((s) => s.stop?.id === stop.id)
|
||||
const { scene: signScene } = useGLTF('/models/sign-highway-wide.glb')
|
||||
const { scene: lampScene } = useGLTF('/models/light-curved.glb')
|
||||
return (
|
||||
<group position={pos}>
|
||||
<group position={pos} rotation={[0, rotationY, 0]}>
|
||||
{/* bus-stop sign: billboard-on-posts (native board faces its local
|
||||
-X; rotate 90° so the face reads along +Z toward the road) */}
|
||||
<Clone object={signScene} scale={SIGN_SCALE} rotation={[0, Math.PI / 2, 0]} />
|
||||
@@ -58,8 +68,10 @@ export function StopPanel({ stop, children, width = 340 }: {
|
||||
<Html transform position={[0, 2.6, 0.4]} distanceFactor={10} style={{ width }}>
|
||||
<div className={`panel${active ? ' panel--active' : ''}`}>{children}</div>
|
||||
</Html>
|
||||
{/* street lamp beside the stop */}
|
||||
<Clone object={lampScene} scale={LAMP_SCALE} position={[5.2, 0, -1]} rotation={[0, lampYaw(stop), 0]} />
|
||||
{/* street lamp beside the stop — compensate for the group's own yaw so
|
||||
the arm keeps facing the road in world space, unaffected by the
|
||||
panel's new facing rotation */}
|
||||
<Clone object={lampScene} scale={LAMP_SCALE} position={[5.2, 0, -1]} rotation={[0, lampYaw(stop) - rotationY, 0]} />
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user