
在 three.js 中,窗口缩放时需同步更新相机宽高比与投影矩阵,并重设渲染器尺寸;若顺序错误(如先调用 updateProjectionMatrix() 再修改 aspect),将导致最大化时画面拉伸或渲染异常。
在 three.js 中,窗口缩放时需同步更新相机宽高比与投影矩阵,并重设渲染器尺寸;若顺序错误(如先调用 `updateprojectionmatrix()` 再修改 `aspect`),将导致最大化时画面拉伸或渲染异常。
窗口缩放是 Web 3D 应用中高频触发的交互事件,但其行为在不同操作系统和浏览器中存在细微差异:手动拖拽调整窗口大小通常能稳定触发 resize 事件,而点击最大化按钮(尤其在 Windows 或 macOS 全屏模式下)可能伴随布局重排、CSS 过渡或延迟渲染,导致 window.innerWidth/Height 暂时未同步更新,或事件处理逻辑执行顺序不当,进而引发画面畸变。
核心问题在于你原代码中调用 camera.updateProjectionMatrix() 的位置——它必须在设置 camera.aspect 之后执行。因为 updateProjectionMatrix() 会基于当前 aspect 值重新计算透视投影矩阵;若先调用该方法,再修改 aspect,则新宽高比不会生效,导致后续渲染使用过期的投影参数,最终表现为模型拉伸、UI 错位或视口裁剪异常。
✅ 正确写法如下(含防抖优化建议):
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
// 推荐:使用防抖避免高频 resize 触发性能问题
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
// ✅ 关键顺序:先更新 aspect,再更新投影矩阵
camera.aspect = sizes.width / sizes.height;
camera.updateProjectionMatrix(); // 依赖最新的 aspect 值
renderer.setSize(sizes.width, sizes.height);
// 可选:若使用 CSS 渲染器(如 CSS2DRenderer),也需同步更新其尺寸
}, 16); // 约 1 帧延迟,兼顾响应性与性能
});
// 主循环保持不变
const loop = () => {
renderer.render(scene, camera);
requestAnimationFrame(loop);
};
loop();
⚠️ 注意事项:
- 不要省略
camera.aspect = ...—— 即使updateProjectionMatrix()被调用,它不会自动读取当前窗口尺寸,必须显式赋值; - 若使用
OrthographicCamera,同样需更新left/right/top/bottom并调用updateProjectionMatrix(); - 在移动端或使用
vh/vw布局时,建议监听orientationchange或采用ResizeObserver替代resize事件,以应对 Safari 等浏览器的兼容性问题; - 某些框架(如 React + three.js)中,需确保
resize处理函数绑定在组件挂载后、卸载前解绑,避免内存泄漏。
总结:three.js 窗口适配的本质是「状态同步」——确保相机参数、渲染器尺寸、DOM 容器三者始终一致。只要牢记 aspect → updateProjectionMatrix() → setSize() 这一黄金顺序,并辅以合理的防抖与生命周期管理,即可彻底规避最大化失真问题。










