@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user