记录下three.js学习过程中不理解问题①
1、透视相机(persperctive)参数理解
const fov = 75;
指的是垂直方向的视野范围。
摄像机视角(fov = 75)
👁️
/ \
/ \ ← 这个夹角就是 75°
/ \
/ \
/___________\
near far
摄像机(你)看向前方:
👁️ —— fov 是你张开眼睛的角度(决定你能看到多广)
|
/ \
/ \ ← 看得见的区域(远处的 pyramid)= frustum
| | ← 视锥体(frustum)从 near 到 far 之间才看得见
near ← 最近 0.1 米
|
|
far ← 最远 5 米
参数 通俗记忆 作用 fov
视角开多大 决定上下看得多少 aspect
屏幕长宽比 不设置好画面会拉伸 near
最近看多少 太近的东西不显示 far
最远看多远 太远的东西不显示
1. 摄像机默认朝向
摄像机默认看向 Z 轴的负方向(即从 z 正方向往 z 负方向看)。
摄像机“上面”是 Y 轴正方向。
2. 为什么要把摄像机往后移?
你的立方体放在坐标原点
(0,0,0)
。如果摄像机位置也是原点,那它就在立方体里面,看不到立方体。
所以要把摄像机沿 z 轴正方向往后移动,比如设置
camera.position.z = 2
,让摄像机离立方体远一点,这样才能“看到”立方体。4. 宽高比对视野的影响
画布宽度是高度的两倍(比如300×150像素),宽高比 = 2。
垂直方向视角是你设置的75度,但水平方向视角会更大,因为画布宽了2倍。
也就是说,水平视角会“拉宽”你的视野,让你能看到更宽的范围。
fov=75°是垂直方向的视角;
画布宽高比=2,意味着水平视角比75°更大;
这样才能保证3D画面在宽屏幕上完整显示,不会裁剪或变形。
. 视觉效果
这个宽视角有点类似人眼的视野宽度:
人眼上下视角比左右视角窄,因为你眼睛是水平放置的。在你的三维场景里,水平视角比75°大(可能是100度、120度等),让你能更广阔地看到左右的物体。
requestAnimationFrame
是浏览器提供的一个高效的动画方法,专门用来让页面里的动画“连续播放”。工作原理:
它会告诉浏览器:“我准备好下一帧动画了,帮我安排合适的时间来刷新画面。”
浏览器会在每一帧合适的时间调用你指定的函数(比如更新旋转角度,重新绘制立方体)。
这个调用是循环的:每次画完一帧动画后,程序又调用自己,形成了动画的“循环”。为
为什么不用普通的
setInterval
或setTimeout
?
requestAnimationFrame
会根据屏幕刷新率来执行动画,动画更流畅,不会卡顿。当页面不可见时(切换标签页),它会自动暂停动画,节省性能和电量。
更适合做基于视觉的动画和绘图。
function render(time) {time *= 0.001; // 将时间单位变为秒cube.rotation.x = time;cube.rotation.y = time;renderer.render(scene, camera);requestAnimationFrame(render); } requestAnimationFrame(render);
requestAnimationFrame(render);
的意思就是:
告诉浏览器“请在下次重绘时调用
render
函数”。浏览器调用
render
时,会自动传入一个时间戳time
参数,这个时间戳是当前页面从加载开始经过的毫秒数。所以你不用自己传
time
,浏览器帮你传进去,方便你根据时间来做动画计算。总结一句话:
调用
requestAnimationFrame(render)
后,浏览器会自动给render
函数传入时间戳time
参数。
弧度和角度的关系
一圈是360度。
360度 = 2π弧度(π ≈ 3.1416)
所以一圈的弧度就是:
2×π≈6.2832弧度
这里旋转角度用弧度表示,
time
是经过time *= 0.001
后单位为秒的时间。也就是说,
当时间为1秒时,旋转角度是1弧度。
当时间为6.2832秒时,旋转角度是6.2832弧度,也就是一整圈。
让相机的视野始终和画布(canvas)保持一致比例,防止拉伸变形。
const canvas = renderer.domElement; camera.aspect = canvas.clientWidth / canvas.clientHeight; camera.updateProjectionMatrix();
canvas.clientWidth / canvas.clientHeight
:获取实际画布宽高比(比如 800px / 400px = 2)
camera.aspect
:更新相机的宽高比
camera.updateProjectionMatrix()
:重新计算相机的投影矩阵(必须的,不然相机不知道你改了宽高比)
为什么画面会“模糊”或“块状化”?
因为:
canvas 的 CSS显示尺寸 和 像素分辨率(绘图缓冲区)不一致。
<canvas style="width: 800px; height: 600px"></canvas>
如果你没设置它的像素尺寸,浏览器默认是
300x150px
。
也就是说你让它显示为 800×600,但实际里面的像素分辨率只有 300×150,就像你用一张 300×150 的图片硬撑到 800×600,当然糊了!正确做法:让 canvas 的像素尺寸 = CSS 尺寸
在 Three.js 中,我们使用这个方法调整 canvas 的 绘图缓冲区 大小:
renderer.setSize(width, height, false);
width
和height
:用 canvas 的clientWidth
和clientHeight
false
:表示 不要自动改 CSS 大小,让 CSS 控它。
封装一个自动检测并更新的函数
function resizeRendererToDisplaySize(renderer) {const canvas = renderer.domElement;const width = canvas.clientWidth;const height = canvas.clientHeight;const needResize = canvas.width !== width || canvas.height !== height;if (needResize) {renderer.setSize(width, height, false);}return needResize; }
用法:
在每一帧render()
里判断画布有没有大小变化,有就更新相机:function render(time) {time *= 0.001;if (resizeRendererToDisplaySize(renderer)) {const canvas = renderer.domElement;camera.aspect = canvas.clientWidth / canvas.clientHeight;camera.updateProjectionMatrix();}renderer.render(scene, camera);requestAnimationFrame(render); }
Canvas 实际尺寸 CSS 尺寸 结果 300x150 800x600 模糊(块状) 800x600 800x600 清晰 ✅ 以利用
resizeRendererToDisplaySize()
的返回值判断:“这帧有没有发生尺寸改变?”
如果有,除了设置 renderer,还要更新 camera 的宽高比。