如何在Svelte应用中用Threlte实现Perspective Camera平滑复位
解决Threlte中相机位置平滑复位的问题
核心问题分析
你遇到的Cannot assign to read only property 'position'错误,本质是Three.js的Vector3对象(即$camera.position)属于不可直接替换的引用类型,直接赋值新对象会触发只读限制,必须通过修改其内部属性或调用set()方法更新。另外,cameraStart仅在组件初始化时生效,无法触发动态更新,需要结合Svelte的响应式和动画工具实现平滑过渡。
完整修复代码
<script> // @ts-nocheck import { tweened } from 'svelte/motion'; import { cubicOut } from 'svelte/easing'; import FurnaceScene from '$lib/furnaceScene.svelte'; import PlateScene from '$lib/plateScene.svelte'; import { browser } from '$app/environment'; import * as Threlte from '@threlte/core'; import * as Three from 'three'; import { onMount } from 'svelte'; import { useThrelte } from '@threlte/core'; const { camera } = useThrelte(); let plateData; // 初始化带动画的相机目标位置变量 const cameraTarget = tweened( { x: 0, y: 30, z: 0 }, { duration: 1000, easing: cubicOut } ); // 响应式同步动画变量到相机位置 $: { if ($camera) { $camera.position.set($cameraTarget.x, $cameraTarget.y, $cameraTarget.z); $camera.updateProjectionMatrix(); } } onMount(() => { getPlateLocation(); }); // 平滑复位相机 async function resetCamera() { await $cameraTarget.set({ x: 0, y: 30, z: 0 }); } // 处理OrbitControls拖动结束时同步动画变量 function handleControlsEnd() { $cameraTarget.set({ x: $camera.position.x, y: $camera.position.y, z: $camera.position.z }); } // 全局复位函数 if (browser) { window.handleResetFromComponent = resetCamera; } async function getPlateLocation() { const response = await fetch('api/plates'); plateData = await response.json(); } // 开发用辅助网格 const gridHelper = new Three.GridHelper(40, 40); const axesHelper = new Three.AxesHelper(10); </script> {#if plateData} <Threlte.PerspectiveCamera lookAt={{ y: 0 }}> <Threlte.OrbitControls maxDistance="30" minDistance="10" enableDamping on:end={handleControlsEnd} /> </Threlte.PerspectiveCamera> <Threlte.AmbientLight color="white" intensity={0.2} /> <Threlte.DirectionalLight color="white" intensity={2} position={{ x: 10, y: 8, z: 6 }} /> <Threlte.Object3DInstance object={gridHelper} /> <Threlte.Object3DInstance object={axesHelper} /> <FurnaceScene /> {#each plateData as plate} <PlateScene {plate} /> {/each} {/if}
关键修改说明
- 用
tweened管理动画状态:创建cameraTarget作为动画驱动的响应式变量,控制相机位置的平滑过渡,支持自定义时长和缓动函数。 - 响应式同步相机位置:通过
$:响应式语句,使用Three.js的set()方法将动画变量值同步到相机位置,避免直接赋值触发只读错误。 - 同步OrbitControls状态:在拖动结束时更新
cameraTarget,确保手动调整相机后,动画变量与实际位置保持一致。 - 简化复位逻辑:直接调用
$cameraTarget.set()即可触发平滑复位动画,无需手动操作相机对象。 - 移除无效静态绑定:相机位置由动画变量动态控制,不再依赖初始化时的
cameraStart对象。
内容的提问来源于stack exchange,提问作者Avi4nFLu
相关产品推荐
相关产品推荐

