Three.js 适配的“保姆级”教程,拒绝拉伸和模糊!
第一步:CSS 铺满全屏
首先,我们要让 Canvas 元素本身在网页里占满位置。这步最简单,但是很关键,很多人容易漏掉 display: block。
默认情况下,Canvas 是 inline 元素,这会导致它底部莫名其妙多出几像素的“留白”(就像文字的行高一样)。
✅ 正确的 CSS 写法:
html, body {
margin: 0;
height: 100%;
}
#c {
width: 100%; /* 宽度占满父容器 */
height: 100%; /* 高度占满父容器 */
display: block; /* 关键!去除底部留白 */
}
第二步:拒绝“暴力拉伸”
CSS 把 Canvas 拉大了,但 Canvas 内部的“绘图缓冲区”(Drawing Buffer)可能还停留在原来的大小。
这就好比你把一张 100x100 的低清图片,强行用 CSS 放大到 1920x1080 显示,结果必然是模糊和马赛克。
在渲染循环中检查 Three.js 官方推荐写一个通用函数,在每一帧渲染前检查 Canvas 的显示大小和实际大小是否一致。
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
// 获取 Canvas 在屏幕上显示的像素宽
const width = canvas.clientWidth;
// 获取 Canvas 在屏幕上显示的像素高
const height = canvas.clientHeight;
// 检查渲染器的内部尺寸是否和显示尺寸一样
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
// 如果不一样,就调整渲染器大小
// 第三个参数 false 很重要!表示不要让渲染器去修改 Canvas 的 CSS 样式
renderer.setSize(width, height, false);
}
return needResize;
}
第三步:告诉摄像机“别把人拍扁了”(校准)
解决了模糊问题,还有一个变形问题。
想象一下,你的显示器本来是宽屏(16:9),摄像机也是按 16:9 拍摄的。当你把窗口缩窄变成竖屏(9:16)时,如果摄像机不调整,它还是把 16:9 的画面强行塞进 9:16 的格子里,物体就会被横向挤压。
所以,每当分辨率改变时,我们必须更新摄像机的 长宽比 (Aspect Ratio)。
✅ 最终的渲染循环代码:
function render(time) {
time *= 0.001;
// 1. 检查并调整分辨率
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
// 2. 修正摄像机长宽比
camera.aspect = canvas.clientWidth / canvas.clientHeight;
// 3. 必须调用这个方法,摄像机参数才会生效!
camera.updateProjectionMatrix();
}
// 正常渲染
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
📂 核心代码与完整示例: my-three-app
总结
如果你喜欢本教程,记得点赞+收藏!关注我获取更多Three.js开发干货