diff --git a/src/components/map/ThreeMap.vue b/src/components/map/ThreeMap.vue index d565ec0..e09470e 100644 --- a/src/components/map/ThreeMap.vue +++ b/src/components/map/ThreeMap.vue @@ -77,6 +77,48 @@ type ZoomCameraSource = 'button' | 'gesture' const CANVAS_FONT_FAMILY = '"鸿蒙黑体", "HarmonyOS Sans SC", "HarmonyOS Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif' const FLOOR_CAMERA_DISTANCE_FACTOR = 0.78 +const SGS_VISUAL_RENDER_CONFIG = { + sceneBackground: 0xeceff1, + camera: { + fov: 42, + near: 0.1, + far: 20000, + initialPosition: new THREE.Vector3(20, 20, 20) + }, + renderer: { + dprCap: 1.5, + powerPreference: 'high-performance' as WebGLPowerPreference, + antialias: true, + alpha: false, + toneMapping: THREE.NoToneMapping, + toneMappingExposure: 1.0, + shadows: false + }, + lights: { + hemisphere: { + skyColor: 0xffffff, + groundColor: 0xb0bec5, + intensity: 1.7 + }, + key: { + color: 0xffffff, + intensity: 2.2, + position: new THREE.Vector3(80, 120, 80) + }, + fill: { + color: 0xffffff, + intensity: 0.55, + position: new THREE.Vector3(-60, 70, -50) + } + }, + controls: { + minDistance: 10, + maxDistance: 600, + minPolarAngle: 0, + maxPolarAngle: Math.PI / 2 - 0.05, + dampingFactor: 0.06 + } +} as const interface CameraFitOptions { distanceFactor?: number @@ -1420,33 +1462,39 @@ const initThree = async () => { } scene = new THREE.Scene() - scene.background = new THREE.Color(0xf7f8f4) + scene.background = new THREE.Color(SGS_VISUAL_RENDER_CONFIG.sceneBackground) const width = Math.max(1, container.clientWidth) const height = Math.max(1, container.clientHeight) - camera = new THREE.PerspectiveCamera(42, width / height, 0.1, 10000) - camera.position.set(80, 80, 120) + camera = new THREE.PerspectiveCamera( + SGS_VISUAL_RENDER_CONFIG.camera.fov, + width / height, + SGS_VISUAL_RENDER_CONFIG.camera.near, + SGS_VISUAL_RENDER_CONFIG.camera.far + ) + camera.position.copy(SGS_VISUAL_RENDER_CONFIG.camera.initialPosition) renderer = new THREE.WebGLRenderer({ - antialias: true, - alpha: true, - powerPreference: 'high-performance' + antialias: SGS_VISUAL_RENDER_CONFIG.renderer.antialias, + alpha: SGS_VISUAL_RENDER_CONFIG.renderer.alpha, + powerPreference: SGS_VISUAL_RENDER_CONFIG.renderer.powerPreference }) renderer.setSize(width, height) - renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2)) + renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, SGS_VISUAL_RENDER_CONFIG.renderer.dprCap)) renderer.outputColorSpace = THREE.SRGBColorSpace - renderer.toneMapping = THREE.NeutralToneMapping - renderer.toneMappingExposure = 1.0 + renderer.toneMapping = SGS_VISUAL_RENDER_CONFIG.renderer.toneMapping + renderer.toneMappingExposure = SGS_VISUAL_RENDER_CONFIG.renderer.toneMappingExposure + renderer.shadowMap.enabled = SGS_VISUAL_RENDER_CONFIG.renderer.shadows container.appendChild(renderer.domElement) controls = new OrbitControls(camera, renderer.domElement) controls.enableDamping = true - controls.dampingFactor = 0.08 + controls.dampingFactor = SGS_VISUAL_RENDER_CONFIG.controls.dampingFactor controls.enableZoom = true - controls.minDistance = 6 - controls.maxDistance = 1200 - controls.minPolarAngle = 0.08 - controls.maxPolarAngle = Math.PI * 0.48 + controls.minDistance = SGS_VISUAL_RENDER_CONFIG.controls.minDistance + controls.maxDistance = SGS_VISUAL_RENDER_CONFIG.controls.maxDistance + controls.minPolarAngle = SGS_VISUAL_RENDER_CONFIG.controls.minPolarAngle + controls.maxPolarAngle = SGS_VISUAL_RENDER_CONFIG.controls.maxPolarAngle syncControlInteractionOptions() loader = new GLTFLoader() @@ -1461,15 +1509,25 @@ const initThree = async () => { routeGroup.name = 'GuideModelRoute' scene.add(routeGroup) - const ambientLight = new THREE.AmbientLight(0xffffff, 0.9) - scene.add(ambientLight) + const hemisphereLight = new THREE.HemisphereLight( + SGS_VISUAL_RENDER_CONFIG.lights.hemisphere.skyColor, + SGS_VISUAL_RENDER_CONFIG.lights.hemisphere.groundColor, + SGS_VISUAL_RENDER_CONFIG.lights.hemisphere.intensity + ) + scene.add(hemisphereLight) - const keyLight = new THREE.DirectionalLight(0xffffff, 2.0) - keyLight.position.set(80, 120, 60) + const keyLight = new THREE.DirectionalLight( + SGS_VISUAL_RENDER_CONFIG.lights.key.color, + SGS_VISUAL_RENDER_CONFIG.lights.key.intensity + ) + keyLight.position.copy(SGS_VISUAL_RENDER_CONFIG.lights.key.position) scene.add(keyLight) - const fillLight = new THREE.DirectionalLight(0xdfeaff, 0.45) - fillLight.position.set(-80, 60, -80) + const fillLight = new THREE.DirectionalLight( + SGS_VISUAL_RENDER_CONFIG.lights.fill.color, + SGS_VISUAL_RENDER_CONFIG.lights.fill.intensity + ) + fillLight.position.copy(SGS_VISUAL_RENDER_CONFIG.lights.fill.position) scene.add(fillLight) resizeObserver = new ResizeObserver(handleResize) @@ -2881,8 +2939,8 @@ const setCameraView = ( const targetCenter = center.clone().add(targetOffset) const distance = Math.abs(maxDim / Math.sin(fov / 2)) * distanceFactor - camera.near = Math.max(0.1, maxDim / 1000) - camera.far = Math.max(10000, maxDim * 20) + camera.near = Math.max(SGS_VISUAL_RENDER_CONFIG.camera.near, maxDim / 1000) + camera.far = Math.max(SGS_VISUAL_RENDER_CONFIG.camera.far, maxDim * 20) camera.up.copy(options.up || new THREE.Vector3(0, 1, 0)) camera.updateProjectionMatrix() @@ -2901,8 +2959,8 @@ const setCameraView = ( nextPosition.add(screenOffset) nextTarget.add(screenOffset) } - controls.minDistance = Math.max(2, maxDim * 0.08) - controls.maxDistance = Math.max(20, maxDim * 8) + controls.minDistance = Math.max(SGS_VISUAL_RENDER_CONFIG.controls.minDistance, maxDim * 0.08) + controls.maxDistance = Math.max(SGS_VISUAL_RENDER_CONFIG.controls.maxDistance, maxDim * 8) moveCameraTo(nextPosition, nextTarget) } @@ -2954,7 +3012,7 @@ const zoomCamera = (direction: 'in' | 'out', options: { source?: ZoomCameraSourc const currentDistance = offset.length() const zoomFactor = direction === 'in' ? 0.72 : 1.28 const minDistance = controls.minDistance || 2 - const maxDistance = controls.maxDistance || 1200 + const maxDistance = controls.maxDistance || SGS_VISUAL_RENDER_CONFIG.controls.maxDistance const nextDistance = Math.min(maxDistance, Math.max(minDistance, currentDistance * zoomFactor)) if (!Number.isFinite(nextDistance) || nextDistance <= 0) return @@ -4198,12 +4256,12 @@ const focusCameraOnPoi = (poi: RenderPoi) => { const direction = new THREE.Vector3(0.72, 0.58, 1).normalize() const nextPosition = target.clone().add(direction.multiplyScalar(distance)) - camera.near = Math.max(0.1, maxDim / 1200) - camera.far = Math.max(10000, maxDim * 20) + camera.near = Math.max(SGS_VISUAL_RENDER_CONFIG.camera.near, maxDim / 1200) + camera.far = Math.max(SGS_VISUAL_RENDER_CONFIG.camera.far, maxDim * 20) camera.updateProjectionMatrix() - controls.minDistance = Math.max(2, maxDim * 0.025) - controls.maxDistance = Math.max(20, maxDim * 6) + controls.minDistance = Math.max(SGS_VISUAL_RENDER_CONFIG.controls.minDistance, maxDim * 0.025) + controls.maxDistance = Math.max(SGS_VISUAL_RENDER_CONFIG.controls.maxDistance, maxDim * 6) moveCameraTo(nextPosition, target) }