Implement fly mode in FPV controls: added vertical movement capabilities, toggle functionality with 'G' key, and updated control logic for jumping and crouching. Enhanced user instructions in index.html. Improved lighting setup in lighting.js with additional directional light and adjustments to existing lights for better illumination. Refined material handling in model-loader.js to ensure proper rendering of glass and non-glass materials.

This commit is contained in:
sebseb7
2025-08-26 00:56:40 +02:00
parent 60871b3963
commit e66e26764e
4 changed files with 172 additions and 67 deletions

View File

@@ -2,6 +2,7 @@ import * as THREE from 'three';
// FPV Mode variables
let fpvMode = false;
let flyMode = false; // New fly mode state
let fpvControls = {
moveForward: false,
moveBackward: false,
@@ -9,6 +10,8 @@ let fpvControls = {
moveRight: false,
jump: false,
crouch: false,
moveUp: false, // For fly mode
moveDown: false, // For fly mode
canJump: true,
velocity: new THREE.Vector3(),
direction: new THREE.Vector3(),
@@ -69,6 +72,14 @@ function onKeyDown(event) {
return false;
}
break;
case 'KeyG':
if (fpvMode) {
event.preventDefault();
event.stopPropagation();
toggleFlyMode();
return false;
}
break;
case 'KeyW':
if (fpvMode) fpvControls.moveForward = true;
break;
@@ -84,16 +95,24 @@ function onKeyDown(event) {
case 'Space':
if (fpvMode) {
event.preventDefault();
if (flyMode) {
fpvControls.moveUp = true;
} else {
fpvControls.jump = true;
}
}
break;
case 'ShiftLeft':
case 'ShiftRight':
if (fpvMode) {
event.preventDefault();
if (flyMode) {
fpvControls.moveDown = true;
} else {
fpvControls.crouch = true;
fpvControls.isCrouching = true;
}
}
break;
}
}
@@ -113,14 +132,24 @@ function onKeyUp(event) {
if (fpvMode) fpvControls.moveRight = false;
break;
case 'Space':
if (fpvMode) fpvControls.jump = false;
if (fpvMode) {
if (flyMode) {
fpvControls.moveUp = false;
} else {
fpvControls.jump = false;
}
}
break;
case 'ShiftLeft':
case 'ShiftRight':
if (fpvMode) {
if (flyMode) {
fpvControls.moveDown = false;
} else {
fpvControls.crouch = false;
fpvControls.isCrouching = false;
}
}
break;
}
}
@@ -194,7 +223,29 @@ function enterFPVMode(renderer) {
renderer.domElement.requestPointerLock();
}
console.log('FPV mode active - WASD to move, mouse to look, ESC to exit');
console.log('FPV mode active - WASD to move, mouse to look, G to toggle fly mode, ESC to exit');
}
function toggleFlyMode() {
flyMode = !flyMode;
// Reset vertical states when switching modes
fpvControls.verticalVelocity = 0;
fpvControls.isJumping = false;
fpvControls.isCrouching = false;
fpvControls.moveUp = false;
fpvControls.moveDown = false;
fpvControls.jump = false;
fpvControls.crouch = false;
if (flyMode) {
console.log('🚁 Fly mode enabled - SPACE to ascend, SHIFT to descend, no gravity');
} else {
console.log('🚶 Walk mode enabled - SPACE to jump, SHIFT to crouch, with gravity');
// Set current height to maintain position when switching back to walk mode
fpvControls.currentHeight = window.camera.position.y;
fpvControls.targetHeight = fpvControls.currentHeight;
}
}
function exitFPVMode() {
@@ -234,12 +285,17 @@ function exitFPVMode() {
fpvControls.moveRight = false;
fpvControls.jump = false;
fpvControls.crouch = false;
fpvControls.moveUp = false;
fpvControls.moveDown = false;
fpvControls.verticalVelocity = 0;
fpvControls.isJumping = false;
fpvControls.isCrouching = false;
fpvControls.currentHeight = window.eyeHeight;
fpvControls.targetHeight = window.eyeHeight;
// Reset fly mode
flyMode = false;
console.log('Orbit controls restored');
}, 50);
}
@@ -248,11 +304,12 @@ export function updateFPVMovement(camera) {
if (!fpvMode) return;
const delta = 0.016; // Approximate 60fps
const moveSpeed = 100.0; // Units per second (1000x faster)
const jumpSpeed = 220.0; // Jump initial velocity (4x higher)
const gravity = 420.0; // Gravity strength (4x faster)
const crouchHeight = window.eyeHeight * 0.5; // Crouch height (60% of normal eye height)
const moveSpeed = 100.0; // Units per second
const jumpSpeed = 220.0; // Jump initial velocity
const gravity = 420.0; // Gravity strength
const crouchHeight = window.eyeHeight * 0.5; // Crouch height
const crouchSpeed = 100.0; // Speed of crouching transition
const flySpeed = 80.0; // Vertical fly speed
// Reset direction
fpvControls.direction.set(0, 0, 0);
@@ -260,26 +317,44 @@ export function updateFPVMovement(camera) {
// Calculate movement direction based on current rotation
const forward = new THREE.Vector3(0, 0, -1);
const right = new THREE.Vector3(1, 0, 0);
const up = new THREE.Vector3(0, 1, 0);
// Apply horizontal rotation to movement vectors
forward.applyAxisAngle(new THREE.Vector3(0, 1, 0), fpvControls.rotation.y);
right.applyAxisAngle(new THREE.Vector3(0, 1, 0), fpvControls.rotation.y);
// Apply movement inputs
// Apply horizontal movement inputs
if (fpvControls.moveForward) fpvControls.direction.add(forward);
if (fpvControls.moveBackward) fpvControls.direction.sub(forward);
if (fpvControls.moveLeft) fpvControls.direction.sub(right);
if (fpvControls.moveRight) fpvControls.direction.add(right);
// Normalize and apply speed
// Normalize and apply horizontal speed
if (fpvControls.direction.length() > 0) {
fpvControls.direction.normalize();
fpvControls.direction.multiplyScalar(moveSpeed * delta);
// Apply movement to camera position
// Apply horizontal movement to camera position
camera.position.add(fpvControls.direction);
}
if (flyMode) {
// FLY MODE - No gravity, direct vertical control
let verticalMovement = 0;
if (fpvControls.moveUp) {
verticalMovement += flySpeed * delta;
}
if (fpvControls.moveDown) {
verticalMovement -= flySpeed * delta;
}
if (verticalMovement !== 0) {
camera.position.y += verticalMovement;
}
} else {
// WALK MODE - Gravity, jumping, crouching
// Handle jumping
if (fpvControls.jump && fpvControls.canJump && !fpvControls.isJumping) {
fpvControls.verticalVelocity = jumpSpeed;
@@ -318,6 +393,7 @@ export function updateFPVMovement(camera) {
}
camera.position.y = fpvControls.currentHeight;
}
}
// Apply rotation to camera
camera.rotation.set(fpvControls.rotation.x, fpvControls.rotation.y, 0, 'YXZ');

View File

@@ -23,7 +23,8 @@
<p>✌️ Two finger drag: Pan around scene</p>
<hr style="margin: 10px 0; border: 1px solid #555;">
<p>🚶 <button id="fpv-btn" style="background: #2196F3; color: white; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer; font-size: 12px; margin-right: 10px;">Enter FPV Mode</button> <span style="font-size: 11px; color: #aaa;">(or press F key to toggle)</span></p>
<p style="font-size: 11px; color: #aaa; margin: 5px 0;">In FPV: WASD to move, mouse to look, SPACE to jump, SHIFT to crouch, F or ESC to exit</p>
<p style="font-size: 11px; color: #aaa; margin: 5px 0;">In FPV: WASD to move, mouse to look, G to toggle fly mode, F or ESC to exit</p>
<p style="font-size: 10px; color: #888; margin: 2px 0;">Walk mode: SPACE jump, SHIFT crouch | Fly mode: SPACE ascend, SHIFT descend</p>
<button id="print-btn" style="background: #4CAF50; color: white; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer; font-size: 12px;">🖨️ Print</button>
</div>

View File

@@ -18,18 +18,25 @@ export function setupLighting(scene, camera) {
pointLight.position.set(-10, 10, 10);
scene.add(pointLight);
// Camera light - follows the camera to illuminate from viewing angle
window.cameraLight = new THREE.PointLight(0xffffff, 1.0, 200);
// Enhanced camera point light - follows the camera to illuminate from viewing angle
window.cameraLight = new THREE.PointLight(0xffffff, 2.0, 300);
window.cameraLight.position.copy(camera.position);
scene.add(window.cameraLight);
// Additional camera spotlight for focused illumination
window.cameraSpotlight = new THREE.SpotLight(0xffffff, 0.8, 100, Math.PI / 4, 0.3);
// Camera spotlight for focused illumination (like a headlamp)
window.cameraSpotlight = new THREE.SpotLight(0xffffff, 1.5, 150, Math.PI / 6, 0.2);
window.cameraSpotlight.position.copy(camera.position);
window.cameraSpotlight.target.position.set(0, 0, 0); // Point at origin initially
scene.add(window.cameraSpotlight);
scene.add(window.cameraSpotlight.target);
// Additional camera directional light (like a flashlight)
window.cameraDirectionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
window.cameraDirectionalLight.position.copy(camera.position);
window.cameraDirectionalLight.target.position.set(0, 0, -1);
scene.add(window.cameraDirectionalLight);
scene.add(window.cameraDirectionalLight.target);
// Interior point lights (will be repositioned when model loads) - increased intensity
window.interiorLight = new THREE.PointLight(0xffffff, 0.8, 50);
window.interiorLight.position.set(0, 0, 0); // Will be moved to model center
@@ -44,7 +51,7 @@ export function setupLighting(scene, camera) {
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.8);
scene.add(hemiLight);
console.log('✨ Camera lights added - they will follow your view');
console.log('✨ Enhanced camera lights added - headlamp-style illumination will follow your view');
// Create environment map for glass reflections
setupEnvironmentMap();
@@ -91,10 +98,26 @@ export function updateCameraLights(camera, controls) {
if (window.cameraSpotlight) {
window.cameraSpotlight.position.copy(camera.position);
// Make spotlight point towards the orbit controls target (model center)
if (controls && controls.target) {
window.cameraSpotlight.target.position.copy(controls.target);
// Calculate where the camera is looking
const lookDirection = new THREE.Vector3(0, 0, -1);
lookDirection.applyQuaternion(camera.quaternion);
// Set spotlight target based on camera direction
const targetPosition = camera.position.clone().add(lookDirection.multiplyScalar(10));
window.cameraSpotlight.target.position.copy(targetPosition);
}
if (window.cameraDirectionalLight) {
window.cameraDirectionalLight.position.copy(camera.position);
// Calculate where the camera is looking for directional light
const lookDirection = new THREE.Vector3(0, 0, -1);
lookDirection.applyQuaternion(camera.quaternion);
// Set directional light target based on camera direction
const targetPosition = camera.position.clone().add(lookDirection.multiplyScalar(5));
window.cameraDirectionalLight.target.position.copy(targetPosition);
}
}
@@ -119,13 +142,17 @@ export function adjustLightsForModel(modelBounds) {
window.interiorLight2.distance = maxDimension * 1.5;
}
// Update camera lights to target the model center
// Update camera lights based on model size
if (window.cameraLight) {
window.cameraLight.distance = maxDimension * 3; // Adjust range based on model size
window.cameraLight.distance = maxDimension * 4; // Adjust range based on model size
}
if (window.cameraSpotlight) {
window.cameraSpotlight.target.position.copy(center);
window.cameraSpotlight.distance = maxDimension * 2;
window.cameraSpotlight.distance = maxDimension * 3;
}
if (window.cameraDirectionalLight) {
// Directional lights don't have distance, but we can adjust intensity
window.cameraDirectionalLight.intensity = 1.0;
}
}

View File

@@ -12,10 +12,11 @@ export function loadCubeModel(scene, camera, controls, onLoadComplete) {
mtlLoader.load('cube.mtl', function(materials) {
materials.preload();
// Configure materials for double-sided rendering with proper transparency
// Configure materials with proper transparency
Object.keys(materials.materials).forEach(function(key) {
const material = materials.materials[key];
material.side = THREE.DoubleSide;
// Only set DoubleSide for glass materials, others use FrontSide
material.side = key.toLowerCase().includes('glass') ? THREE.DoubleSide : THREE.FrontSide;
// Handle glass materials specially
if (key.toLowerCase().includes('glass')) {
@@ -120,12 +121,12 @@ export function loadCubeModel(scene, camera, controls, onLoadComplete) {
child.add(wireframeLines);
}
} else {
// Non-glass materials
child.material.side = THREE.DoubleSide;
// Non-glass materials - fix texture appearing on both sides
child.material.side = THREE.FrontSide;
child.material.transparent = false;
child.material.opacity = 1.0;
// Ensure proper lighting on both sides
// Ensure proper lighting
if (child.material.type === 'MeshLambertMaterial' || child.material.type === 'MeshPhongMaterial') {
child.material.emissive = new THREE.Color(0x222222); // Increased self-illumination for brightness
}
@@ -177,7 +178,7 @@ export function loadObjWithoutMaterials(scene, camera, controls, onLoadComplete)
// Apply default material with better interior visibility
const defaultMaterial = new THREE.MeshPhongMaterial({
color: 0xffffff,
side: THREE.DoubleSide,
side: THREE.FrontSide, // Fix texture appearing on both sides
transparent: false,
opacity: 1.0,
emissive: new THREE.Color(0x222222), // Increased self-illumination for brightness