Three.js窗口缩放3D模型不适配及TypeError错误求助
问题描述
- 网站Hero区域背景集成3D模型后,基础功能正常,但手动调整窗口尺寸时,3D模型无法适配新的窗口大小。
- 控制台抛出错误:
TypeError: Cannot read properties of undefined (reading 'position'),错误指向Three.js代码第69行。
解决方案
1. 修复控制台错误
错误源于3D模型的异步加载机制:animate函数会在模型加载完成前就执行,此时model变量仍为undefined,直接访问model.position就会触发报错。
修改animate函数,增加模型存在性判断:
function animate() { requestAnimationFrame(animate); // 仅当模型加载完成后才修改位置 if (model) { model.position.y = -2; } controls.update(); renderer.render(scene, camera); }
2. 实现窗口尺寸自适应
需要监听窗口的resize事件,动态更新相机的宽高比与渲染器的尺寸,同时更新相机的投影矩阵以保证画面正确适配:
在JavaScript代码中添加以下监听逻辑:
// 监听窗口尺寸变化 window.addEventListener('resize', () => { // 更新相机宽高比 camera.aspect = window.innerWidth / window.innerHeight; // 必须更新投影矩阵才能让宽高比生效 camera.updateProjectionMatrix(); // 更新渲染器尺寸以匹配窗口 renderer.setSize(window.innerWidth, window.innerHeight); });
修改后的完整JavaScript代码
import * as THREE from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js"; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); const heroSection = document.querySelector("#hero-section"); heroSection.appendChild(renderer.domElement); // 导入3D模型 const loader = new GLTFLoader(); let model; loader.load( "./scene.gltf", function (gltf) { model = gltf.scene; scene.add(gltf.scene); }, undefined, function (error) { console.error(error); } ); // 控制相机移动 const controls = new OrbitControls(camera, renderer.domElement); controls.enableZoom = false; const ambientLight = new THREE.AmbientLight(0xffffff); const light = new THREE.AmbientLight(0x404040); scene.add(ambientLight, light); // 设置相机位置 camera.position.set(0, 1, 5); controls.update(); // 监听窗口尺寸变化 window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); function animate() { requestAnimationFrame(animate); if (model) { model.position.y = -2; } controls.update(); renderer.render(scene, camera); } animate();
补充说明
- CSS和HTML代码无需修改,现有布局已保证canvas在Hero区域内全屏显示。
- 若模型加载后位置仍不符合预期,可调整
model.position.y的数值,或在模型加载完成的回调中一次性设置位置(避免在animate中重复设置)。
内容的提问来源于stack exchange,提问作者user13069641
相关产品推荐
相关产品推荐

