Vue中使用Three.js加载GLB模型时,为什么旋转后模型位置错乱?
在Vue组件里用Three.js加载GLB模型,旋转相机时模型位置突然偏移到角落了,之前在纯HTML环境没问题,现在改成Vue组件后就出问题了
代码结构是这样的:
<template>
<div ref="container" class="model-container"></div>
</template>
<script setup>
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const container = ref(null);
let renderer;
onMounted(() => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
container.value.appendChild(renderer.domElement);
const loader = new GLTFLoader();
loader.load('/model.glb', (gltf) => {
scene.add(gltf.scene);
gltf.scene.position.set(0,0,-5);
});
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
});
</script>
我已经尝试过设置模型位置、调整相机参数,甚至用boundingSphere计算中心点,但旋转时模型还是会突然跳到左上角。是不是Vue的响应式系统影响了Three.js的渲染循环?
另外WebGLRenderer会占用整个画布,但你把它塞进container后没设置样式,容易被CSS挤压变形。还有动画循环里的camera始终是初始实例,没更新过投影矩阵。
代码给你:
模板别忘了加样式:
核心就三点:用容器实际尺寸初始化相机比例、监听resize更新矩阵、别用window.innerWidth/Height这种全局值。Vue里DOM异步挂载,必须等ref有值再读尺寸。
具体来说,你的代码中缺少对窗口尺寸变化的监听,以及相机投影矩阵的更新。当旋转相机时,如果没有重新计算视口宽高比,模型就会“飞走”或者跳到奇怪的位置。这是Three.js常见的坑。
### 解决方案
我们需要做几件事:
1. 监听窗口大小变化事件。
2. 每次窗口大小变化时,更新相机的宽高比和渲染器的尺寸。
3. 确保在调整后重新设置相机的投影矩阵。
下面是修改后的完整代码:
### 为什么这样做?
- **相机宽高比**:当你调整浏览器窗口大小时,如果没有更新相机的
aspect属性(即宽高比),会导致渲染结果变形或模型位置错乱。- **投影矩阵更新**:每次修改相机的
aspect后,必须调用camera.updateProjectionMatrix()来应用新的宽高比。- **渲染器尺寸同步**:渲染器的尺寸也需要与窗口同步,否则画面会裁剪或拉伸。
- **设备像素比**:通过
renderer.setPixelRatio(window.devicePixelRatio)可以确保在高分辨率屏幕上显示清晰。### 其他注意事项
如果模型还是有偏移,可能是因为加载的GLB模型本身有原点偏移的问题。你可以通过以下方式检查并修正:
这样应该就能解决你提到的问题了。希望这次能帮到你!