feat(viewer): widen first-person walkthrough FOV to 60°
The walkthrough rode the default 50° orbit camera, which feels cramped on foot. Both walkthrough controllers (baked GlbWalkthroughController and the parametric WalkthroughControls fallback) now set a shared WALKTHROUGH_FOV = 60 on enter and restore the prior FOV on exit, leaving orbit framing untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
69c483b5f2
commit
70acf894d1
@@ -15,6 +15,7 @@ import {
|
|||||||
Mesh,
|
Mesh,
|
||||||
MeshBasicMaterial,
|
MeshBasicMaterial,
|
||||||
type Object3D,
|
type Object3D,
|
||||||
|
type PerspectiveCamera,
|
||||||
Quaternion,
|
Quaternion,
|
||||||
Vector3,
|
Vector3,
|
||||||
} from 'three'
|
} from 'three'
|
||||||
@@ -24,6 +25,7 @@ import { useGLTFKTX2 } from '../../hooks/use-gltf-ktx2'
|
|||||||
import { SCENE_LAYER } from '../../lib/layers'
|
import { SCENE_LAYER } from '../../lib/layers'
|
||||||
import useViewer from '../../store/use-viewer'
|
import useViewer from '../../store/use-viewer'
|
||||||
import BVHEcctrl, { type BVHEcctrlApi, type MovementInput } from './bvh-ecctrl'
|
import BVHEcctrl, { type BVHEcctrlApi, type MovementInput } from './bvh-ecctrl'
|
||||||
|
import { WALKTHROUGH_FOV } from './walkthrough-controls'
|
||||||
|
|
||||||
// Eye/capsule geometry mirrors the editor's first-person controller so the
|
// Eye/capsule geometry mirrors the editor's first-person controller so the
|
||||||
// baked walkthrough feels identical. The capsule centre sits below the eye; the
|
// baked walkthrough feels identical. The capsule centre sits below the eye; the
|
||||||
@@ -264,6 +266,22 @@ export function GlbWalkthroughController({ url }: { url: string }) {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Widen FOV while walking; the baked walkthrough rides the default 50° orbit
|
||||||
|
// camera, which feels cramped on foot. Keyed on `camera` so it re-applies if
|
||||||
|
// the instance swaps (e.g. the ortho→perspective switch above), restoring the
|
||||||
|
// prior FOV on exit.
|
||||||
|
useEffect(() => {
|
||||||
|
const cam = camera as PerspectiveCamera
|
||||||
|
if (!cam.isPerspectiveCamera) return
|
||||||
|
const prevFov = cam.fov
|
||||||
|
cam.fov = WALKTHROUGH_FOV
|
||||||
|
cam.updateProjectionMatrix()
|
||||||
|
return () => {
|
||||||
|
cam.fov = prevFov
|
||||||
|
cam.updateProjectionMatrix()
|
||||||
|
}
|
||||||
|
}, [camera])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
worldRef.current = world
|
worldRef.current = world
|
||||||
if (world) {
|
if (world) {
|
||||||
|
|||||||
@@ -3,12 +3,18 @@
|
|||||||
import { PointerLockControls } from '@react-three/drei'
|
import { PointerLockControls } from '@react-three/drei'
|
||||||
import { useFrame, useThree } from '@react-three/fiber'
|
import { useFrame, useThree } from '@react-three/fiber'
|
||||||
import { useCallback, useEffect, useRef } from 'react'
|
import { useCallback, useEffect, useRef } from 'react'
|
||||||
import { Vector3 } from 'three'
|
import { type PerspectiveCamera, Vector3 } from 'three'
|
||||||
import useViewer from '../../store/use-viewer'
|
import useViewer from '../../store/use-viewer'
|
||||||
|
|
||||||
const MOVE_SPEED = 5
|
const MOVE_SPEED = 5
|
||||||
const EYE_HEIGHT = 1.6
|
const EYE_HEIGHT = 1.6
|
||||||
|
|
||||||
|
// First-person FOV. The orbit camera is 50° (set on the Canvas), which feels
|
||||||
|
// cramped on foot; ~60° vertical (~90° horizontal at 16:9) restores peripheral
|
||||||
|
// awareness without wide-angle distortion. Applied only while walking — both
|
||||||
|
// walkthrough controllers read this and restore the orbit FOV on exit.
|
||||||
|
export const WALKTHROUGH_FOV = 60
|
||||||
|
|
||||||
const _direction = new Vector3()
|
const _direction = new Vector3()
|
||||||
const _forward = new Vector3()
|
const _forward = new Vector3()
|
||||||
const _right = new Vector3()
|
const _right = new Vector3()
|
||||||
@@ -26,6 +32,20 @@ export const WalkthroughControls = () => {
|
|||||||
}
|
}
|
||||||
}, [walkthroughMode, camera])
|
}, [walkthroughMode, camera])
|
||||||
|
|
||||||
|
// Widen FOV while walking; restore the orbit FOV on exit.
|
||||||
|
useEffect(() => {
|
||||||
|
if (!walkthroughMode) return
|
||||||
|
const cam = camera as PerspectiveCamera
|
||||||
|
if (!cam.isPerspectiveCamera) return
|
||||||
|
const prevFov = cam.fov
|
||||||
|
cam.fov = WALKTHROUGH_FOV
|
||||||
|
cam.updateProjectionMatrix()
|
||||||
|
return () => {
|
||||||
|
cam.fov = prevFov
|
||||||
|
cam.updateProjectionMatrix()
|
||||||
|
}
|
||||||
|
}, [walkthroughMode, camera])
|
||||||
|
|
||||||
// Keyboard handlers
|
// Keyboard handlers
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!walkthroughMode) return
|
if (!walkthroughMode) return
|
||||||
|
|||||||
Reference in New Issue
Block a user