diff --git a/app/components/flightlab/pfd/PfdAircraftModel.vue b/app/components/flightlab/pfd/PfdAircraftModel.vue index 64b1241..9bc7885 100644 --- a/app/components/flightlab/pfd/PfdAircraftModel.vue +++ b/app/components/flightlab/pfd/PfdAircraftModel.vue @@ -29,56 +29,62 @@ let targetPitchRad = 0 let targetBankRad = 0 function buildAircraft(): THREE.Group { + // Three.js coords: X=right, Y=up, Z=toward viewer + // Aircraft: nose toward -Z, wings along X, Y is up const group = new THREE.Group() - // Fuselage - cylinder rotated to lie along X axis + const bodyColor = 0xdcdcdc + const darkColor = 0x2a2a2a + const engineColor = 0x555555 + + // Fuselage — cylinder along Z axis (default cylinder is along Y, rotate to Z) const fuselageGeo = new THREE.CylinderGeometry(0.4, 0.35, 5, 12) - const fuselageMat = new THREE.MeshStandardMaterial({ color: 0xdcdcdc }) + const fuselageMat = new THREE.MeshStandardMaterial({ color: bodyColor }) const fuselage = new THREE.Mesh(fuselageGeo, fuselageMat) - fuselage.rotation.z = Math.PI / 2 + fuselage.rotation.x = Math.PI / 2 // rotate Y-cylinder to lie along Z group.add(fuselage) - // Nose cone + // Nose cone — pointing toward -Z (forward) const noseGeo = new THREE.ConeGeometry(0.35, 1, 12) - const noseMat = new THREE.MeshStandardMaterial({ color: 0x2a2a2a }) + const noseMat = new THREE.MeshStandardMaterial({ color: darkColor }) const nose = new THREE.Mesh(noseGeo, noseMat) - nose.rotation.z = -Math.PI / 2 - nose.position.set(3, 0, 0) + nose.rotation.x = Math.PI / 2 // cone tip points along -Z + nose.position.set(0, 0, -3) group.add(nose) - // Main wings - const wingGeo = new THREE.BoxGeometry(0.6, 4.5, 0.08) - const wingMat = new THREE.MeshStandardMaterial({ color: 0xdcdcdc }) + // Main wings — wide along X (wingspan), thin along Z (chord), very thin along Y + const wingGeo = new THREE.BoxGeometry(4.5, 0.08, 0.6) // X=span, Y=thickness, Z=chord + const wingMat = new THREE.MeshStandardMaterial({ color: bodyColor }) const wings = new THREE.Mesh(wingGeo, wingMat) - wings.position.set(-0.2, 0, 0) + wings.position.set(0, 0, 0.2) group.add(wings) - // Horizontal stabilizer - const hStabGeo = new THREE.BoxGeometry(0.3, 1.8, 0.06) - const hStabMat = new THREE.MeshStandardMaterial({ color: 0xdcdcdc }) + // Horizontal stabilizer — same orientation as wings, smaller + const hStabGeo = new THREE.BoxGeometry(1.8, 0.06, 0.3) // X=span, Y=thick, Z=chord + const hStabMat = new THREE.MeshStandardMaterial({ color: bodyColor }) const hStab = new THREE.Mesh(hStabGeo, hStabMat) - hStab.position.set(-2.3, 0, 0) + hStab.position.set(0, 0, 2.3) group.add(hStab) - // Vertical stabilizer - const vStabGeo = new THREE.BoxGeometry(0.6, 0.06, 1.2) - const vStabMat = new THREE.MeshStandardMaterial({ color: 0xdcdcdc }) + // Vertical stabilizer — tall along Y, along Z (chord) + const vStabGeo = new THREE.BoxGeometry(0.06, 1.2, 0.6) // X=thin, Y=height, Z=chord + const vStabMat = new THREE.MeshStandardMaterial({ color: bodyColor }) const vStab = new THREE.Mesh(vStabGeo, vStabMat) - vStab.position.set(-2.1, 0, 0.6) + vStab.position.set(0, 0.6, 2.1) group.add(vStab) - // Engines (two, under each wing) + // Engines (two, under each wing) — cylinders along Z const engineGeo = new THREE.CylinderGeometry(0.18, 0.22, 0.8, 8) - const engineMat = new THREE.MeshStandardMaterial({ color: 0x555555 }) + const engineMat = new THREE.MeshStandardMaterial({ color: engineColor }) const engineLeft = new THREE.Mesh(engineGeo, engineMat) - engineLeft.rotation.z = Math.PI / 2 - engineLeft.position.set(0.2, -1.5, -0.35) + engineLeft.rotation.x = Math.PI / 2 // align along Z + engineLeft.position.set(-1.5, -0.35, -0.2) group.add(engineLeft) const engineRight = new THREE.Mesh(engineGeo, engineMat) - engineRight.rotation.z = Math.PI / 2 - engineRight.position.set(0.2, 1.5, -0.35) + engineRight.rotation.x = Math.PI / 2 // align along Z + engineRight.position.set(1.5, -0.35, -0.2) group.add(engineRight) return group @@ -96,10 +102,10 @@ function initScene() { scene.background = new THREE.Color(0x1a5fb4) scene.fog = new THREE.Fog(0x62a0ea, 30, 80) - // Camera + // Camera — view from front-left, slightly above + // Aircraft nose points -Z, so camera at +Z looks at front camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 200) - // View from front-right, slightly above — shows pitch and bank clearly - camera.position.set(6, 2, 4) + camera.position.set(-4, 3, -6) camera.lookAt(0, 0, 0) // Lights @@ -156,11 +162,11 @@ function animate() { animFrameId = requestAnimationFrame(animate) if (aircraft) { - // Aircraft flies along +X, wings along Y, Z is up - // Pitch: rotate around Y axis (wing axis) — positive pitch = nose up - aircraft.rotation.y = lerp(aircraft.rotation.y, targetPitchRad, 0.1) - // Bank: rotate around X axis (longitudinal axis) — positive bank = right wing down - aircraft.rotation.x = lerp(aircraft.rotation.x, targetBankRad, 0.1) + // Aircraft: nose toward -Z, wings along X, Y is up + // Pitch: rotate around X axis — positive pitch = nose up (rotates nose away from -Z toward +Y) + aircraft.rotation.x = lerp(aircraft.rotation.x, targetPitchRad, 0.1) + // Bank: rotate around Z axis — positive bank = right wing down + aircraft.rotation.z = lerp(aircraft.rotation.z, -targetBankRad, 0.1) } if (renderer && scene && camera) { diff --git a/app/components/flightlab/pfd/PfdHeadingIndicator.vue b/app/components/flightlab/pfd/PfdHeadingIndicator.vue index 003a173..69f78e1 100644 --- a/app/components/flightlab/pfd/PfdHeadingIndicator.vue +++ b/app/components/flightlab/pfd/PfdHeadingIndicator.vue @@ -93,23 +93,52 @@ const readoutBoxHeight = 18 rx="2" /> - + + + + {{ readoutText }} + + + + + + - + - + - - - - - - - - {{ readoutText }} -