|
| 1 | +import { |
| 2 | + ACCENT_STRIPE_HEIGHT, |
| 3 | + ACCENT_STRIPE_INTENSITY, |
| 4 | + BUS_COLOR, |
| 5 | + DOCKING_COLLAR_COLOR, |
| 6 | + DOCKING_COLLAR_LENGTH, |
| 7 | + DOCKING_COLLAR_RADIUS_FRAC, |
| 8 | + THRUSTER_COLOR, |
| 9 | + THRUSTER_COUNT, |
| 10 | + THRUSTER_NOZZLE_APEX_RADIUS, |
| 11 | + THRUSTER_NOZZLE_BASE_RADIUS, |
| 12 | + THRUSTER_NOZZLE_LENGTH, |
| 13 | + THRUSTER_PLACEMENT_RADIUS_FRAC, |
| 14 | +} from '../config/constants'; |
1 | 15 | import type { MainBodyProps } from '../types'; |
2 | 16 |
|
3 | | -export function MainBody({ |
4 | | - width, |
5 | | - height, |
6 | | - depth, |
7 | | - color, |
8 | | - emissive, |
9 | | - emissiveIntensity = 0.3, |
10 | | - metalness = 0.6, |
11 | | - roughness = 0.4, |
12 | | -}: MainBodyProps) { |
| 17 | +const RADIAL_SEGMENTS = 48; |
| 18 | +const NOZZLE_SEGMENTS = 20; |
| 19 | +const STRIPE_OVERHANG = 0.05; |
| 20 | + |
| 21 | +// cylinderGeometry's native axis is +Y. The outer group rotates +π/2 around X |
| 22 | +// so inside the group local +Y maps to world +Z; end-cap positions below use |
| 23 | +// local Y for "along the tube axis." |
| 24 | + |
| 25 | +export function MainBody({ width, height, depth, accent }: MainBodyProps) { |
| 26 | + const halfWidth = width / 2; |
| 27 | + const halfHeight = height / 2; |
| 28 | + |
| 29 | + const busScale = [halfWidth, 1, halfHeight] satisfies [number, number, number]; |
| 30 | + const stripeScale = [(width + STRIPE_OVERHANG) / 2, 1, (height + STRIPE_OVERHANG) / 2] satisfies [ |
| 31 | + number, |
| 32 | + number, |
| 33 | + number, |
| 34 | + ]; |
| 35 | + |
| 36 | + const collarRadiusX = halfWidth * DOCKING_COLLAR_RADIUS_FRAC; |
| 37 | + const collarRadiusZ = halfHeight * DOCKING_COLLAR_RADIUS_FRAC; |
| 38 | + const collarY = depth / 2 + DOCKING_COLLAR_LENGTH / 2; |
| 39 | + |
| 40 | + const thrusterRadiusX = halfWidth * THRUSTER_PLACEMENT_RADIUS_FRAC; |
| 41 | + const thrusterRadiusZ = halfHeight * THRUSTER_PLACEMENT_RADIUS_FRAC; |
| 42 | + const thrusterY = -depth / 2 - THRUSTER_NOZZLE_LENGTH / 2; |
| 43 | + |
13 | 44 | return ( |
14 | | - <mesh> |
15 | | - <boxGeometry args={[width, height, depth]} /> |
16 | | - <meshStandardMaterial |
17 | | - color={color} |
18 | | - metalness={metalness} |
19 | | - roughness={roughness} |
20 | | - emissive={emissive} |
21 | | - emissiveIntensity={emissive ? emissiveIntensity : 0} |
22 | | - transparent |
23 | | - opacity={1} |
24 | | - depthWrite={true} |
25 | | - /> |
26 | | - </mesh> |
| 45 | + <group rotation={[Math.PI / 2, 0, 0]}> |
| 46 | + <mesh scale={busScale}> |
| 47 | + <cylinderGeometry args={[1, 1, depth, RADIAL_SEGMENTS]} /> |
| 48 | + <meshStandardMaterial color={BUS_COLOR} metalness={0.05} roughness={0.75} /> |
| 49 | + </mesh> |
| 50 | + |
| 51 | + <mesh scale={stripeScale}> |
| 52 | + <cylinderGeometry args={[1, 1, ACCENT_STRIPE_HEIGHT, RADIAL_SEGMENTS]} /> |
| 53 | + <meshStandardMaterial |
| 54 | + color={accent} |
| 55 | + emissive={accent} |
| 56 | + emissiveIntensity={ACCENT_STRIPE_INTENSITY} |
| 57 | + metalness={0.1} |
| 58 | + roughness={0.6} |
| 59 | + /> |
| 60 | + </mesh> |
| 61 | + |
| 62 | + <mesh position={[0, collarY, 0]} scale={[collarRadiusX, 1, collarRadiusZ]}> |
| 63 | + <cylinderGeometry args={[1, 1, DOCKING_COLLAR_LENGTH, RADIAL_SEGMENTS]} /> |
| 64 | + <meshStandardMaterial color={DOCKING_COLLAR_COLOR} metalness={0.7} roughness={0.35} /> |
| 65 | + </mesh> |
| 66 | + |
| 67 | + {Array.from({ length: THRUSTER_COUNT }, (_, i) => { |
| 68 | + const angle = (i / THRUSTER_COUNT) * Math.PI * 2; |
| 69 | + const x = thrusterRadiusX * Math.cos(angle); |
| 70 | + const z = thrusterRadiusZ * Math.sin(angle); |
| 71 | + return ( |
| 72 | + <mesh key={`nozzle-${i}`} position={[x, thrusterY, z]}> |
| 73 | + <cylinderGeometry |
| 74 | + args={[ |
| 75 | + THRUSTER_NOZZLE_APEX_RADIUS, |
| 76 | + THRUSTER_NOZZLE_BASE_RADIUS, |
| 77 | + THRUSTER_NOZZLE_LENGTH, |
| 78 | + NOZZLE_SEGMENTS, |
| 79 | + ]} |
| 80 | + /> |
| 81 | + <meshStandardMaterial color={THRUSTER_COLOR} metalness={0.5} roughness={0.4} /> |
| 82 | + </mesh> |
| 83 | + ); |
| 84 | + })} |
| 85 | + </group> |
27 | 86 | ); |
28 | 87 | } |
0 commit comments