如果你小时候玩过积木,那你其实已经懂 Three.js 了。想象一下:你把一块块方积木垒成小房子,给屋顶贴上蓝色贴纸,在小窗户里放一盏小灯,然后围着房子转圈看它——这个“搭积木、贴贴纸、放灯光、绕着看”的过程,正是 Three.js 在浏览器里做的事。只不过,你的积木块变成了立方体、球体、圆柱体这些几何体,贴纸变成了材质贴图,灯光变成了虚拟光源,而“围着看”则是通过一个可移动的虚拟相机完成的。Three.js 就像一盒精美的积木套装:它帮你封装好了最复杂的几何计算和渲染管线,你只需要专注于“搭什么”和“怎么搭”,而不是从零去造一块积木。这套工具由 Three.js 团队维护,基于 WebGL,让浏览器无需任何插件就能渲染出令人惊叹的 3D 场景。
掌握 Three.js,等于拿到了打开“三维互联网”大门的钥匙。无论你未来做数据可视化、在线游戏、产品展示还是元宇宙方向,这项技能都能让你从众多前端开发者中脱颖而出。
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
场景舞台搭建
想象你刚拆开一盒积木,第一件事是什么?当然是找一块平整的底板——只有把底板铺好,你才知道往哪儿放积木、积木之间怎么连接。在 Three.js 里,这块“底板”就是 Scene(场景)。它是所有对象的容器,你创建的每一个积木(几何体)、贴纸(材质)、灯光都必须放进这个容器里,否则就像把积木放在地上——虽然存在,但不在你的“积木房子”里。
当你 new THREE.Scene() 创建一个场景时,Three.js 会在内存中维护一棵对象树。你可以把任何可见或不可见的对象挂到这棵树上,就像往底板上堆叠积木。场景还自带一套坐标系——右手坐标系,其中 X 轴向右、Y 轴向上、Z 轴朝向你。这套坐标系就像是底板上的刻度线,让你能精确地说出“这块积木放在距离中心 5 格、高度 3 格的位置”。
Scene 对象最核心的几个能力包括:add() 方法像一只手,把积木稳稳放到底板上;remove() 方法像拆积木,需要时也能干净地拿走;traverse() 方法像你的眼睛,可以在场景里巡视每一个节点。需要注意的是,Three.js 的 Scene 继承自 Object3D,这意味着它本身也可以拥有位置、旋转、缩放属性——这在实现“滚动的天空盒”或“动态世界”时非常有用。
1. 创建场景:Scene 是最顶层的容器,所有对象都要挂载进来。
2. 添加对象:通过 add 方法把物体挂到场景树下,此时物体才进入渲染范围。
3. 对象树结构:每个场景都是一棵层级树,根节点是 Scene,子节点可以是 Mesh、Light、Camera 等。
把场景想象成一张无限大的积木底板,这解释了为什么 Three.js 的性能瓶颈往往不在场景本身,而在于场景里的对象数量。合理组织场景树,是 3D 应用优雅与高效的起点。
相机视野控制
搭好积木房子后,你想从各个角度欣赏它。你会怎么做?蹲下来从窗户看、站到凳子上俯视、或者绕着一圈走。在 Three.js 里,你的“眼睛”就是 Camera(相机)。它是一个抽象的视点,决定了“从哪个位置、朝哪个方向、以多大视野”去看场景。没有相机的 Three.js 应用是黑屏的——就像闭着眼睛搭积木,东西都在,但你看不见。
Three.js 最常用的两种相机是 PerspectiveCamera(透视相机)和 OrthographicCamera(正交相机)。透视相机模拟人眼和真实相机的特性:近大远小,现实生活中我们看到的世界就是这样的。正交相机则保持物体大小恒定,不管距离远近,就像建筑图纸的平面视图。透视相机适合游戏和产品展示,正交相机适合 2.5D 界面和建筑平面图。其核心参数包括视野角度(FOV)、宽高比(aspect)、近裁剪面(near)和远裁剪面(far)。
相机的定位也讲究:position.set(x, y, z) 确定相机站在哪里,lookAt(x, y, z) 让相机看向哪里。这就像你站在积木房子东南角,视线聚焦在房屋正门的把手上。设置好这两个参数,就等于确定了“摄影师的位置和镜头朝向”。
1. 近大远小:透视矩阵把三维坐标投影到二维屏幕,核心是视锥体变换。
2. 定义视野:fov 是垂直方向的视野角度,单位是度。
3. 裁剪范围:near 和 far 定义了相机能看到的最远和最近距离,超出范围的物体被裁剪掉。
相机就像你的双眼,决定了你看到一个怎样的 3D 世界。调好相机参数,是每个 Three.js 应用的第一步——它不是技术题,而是视觉艺术题。
几何体积木
现在进入最有趣的环节:往底板上搭积木。积木盒里有各种各样的形状——立方体、球体、圆柱体、圆锥体、环面……在 Three.js 中,这些形状被称为 Geometry 或 BufferGeometry。它们是 3D 场景的最小积木单元,通过组合它们,可以搭建出几乎任何你想要的物体:房子、汽车、人物,甚至整个城市。
Three.js 内置了大量基础几何体,就像积木盒里的标准件。BoxGeometry(宽,高,深) 是正方体,SphereGeometry(半径,分段数) 是球体,CylinderGeometry(半径顶,半径底,高度) 是圆柱体。每个几何体都由顶点(vertices)和面(faces)构成——顶点是积木块的角落,面是积木块的表面。当你创建一个 BoxGeometry 时,Three.js 会计算好 8 个顶点、6 个面(每个面由 2 个三角形组成),然后把这些数据以 BufferGeometry 的形式存在内存中。
BufferGeometry 是 Three.js 从 r125 版本开始主推的几何体格式。它把顶点位置、法线、颜色、UV 坐标等数据按二进制连续存储在缓冲区中,GPU 可以直接读取并进行渲染。它的优势在于高效——就像积木块表面提前印好了所有贴纸的定位孔,拼搭时直接对齐就行。而旧的 Geometry 由于数据分散、操作灵活但效率较低,在新版本中已被移除。
1. 定位顶点:每个顶点都有三维坐标,定义积木的角落位置。
2. 连接顶点成三角形:index 数组定义每三个顶点组成一个三角形面,GPU 用它来渲染表面。
3. 法线计算:每个顶点都有一个法线向量,它决定光照在表面上的反射效果。
积木块是 3D 世界的根基。理解了顶点、面、缓冲区,你就理解了 GPU 如何“看见”这个世界——而不是被 Three.js 的 API 牵着走。这是从“会用”迈向“懂行”的关键一步。
材质与灯光
积木块的形状有了,但它们还是灰蒙蒙的——就像刚出厂的素色积木,没有贴纸、没有颜色。要让积木真正“活”起来,需要两样东西:Material(材质)和 Light(灯光)。材质是积木的皮肤,决定了物体表面如何反射光线;灯光是房间里的灯,它照亮积木,让皮肤显现出颜色和质感。
Three.js 内置了多种材质,就像不同风格的贴纸。MeshBasicMaterial 是最简单的“纯色贴纸”,它不依赖光照,只用纯色绘制,适合做背景和辅助线。MeshLambertMaterial 是“哑光贴纸”,表面不反光,适用于粗糙的物体(如墙壁、泥土)。MeshPhongMaterial 是“亮光贴纸”,带高光反射,适合塑料、金属质感。MeshStandardMaterial 是“物理贴纸”,基于 PBR(物理渲染),效果最真实,适合写实风格。
光源则是场景中的“灯”。AmbientLight 是环境光,像天花板上的吸顶灯,均匀照亮全屋;DirectionalLight 是平行光,像太阳,以固定方向照射;PointLight 是点光源,像一盏台灯,从一点向四面八方发亮;SpotLight 是聚光灯,像舞台追光灯,形成一束光锥。不同材质对光的反应完全不同——MeshBasicMaterial 完全不理会光源,而 MeshStandardMaterial 会综合计算漫反射、镜面反射和环境光照。
1. 漫反射(Lambert 模型):粗糙表面的反射强度与光线入射角的余弦成正比。
2. 高光反射(Phong 模型):光滑表面的高光强度与反射向量和视线向量的夹角有关。
3. PBR 能量守恒:表面的反射率与折射率之和不超过 1,保证物理正确。
材质和灯光就像积木的“颜值担当”。即使几何体再精细,没有好的材质和灯光,场景依然显得廉价;反之,一个球体加一束灯光,也能呈现电影级的质感。这就是 3D 渲染的魅力。
动画渲染循环
积木房子搭好了、贴纸贴好了、灯光也亮了,但它是静止的——像一张照片。照片很好看,但我们想要的是“电影”。如何让积木旋转起来、让小车动起来、让小鸟飞行?答案是“动画渲染循环”(render loop)。Three.js 的动画机制很简单:不断更新物体状态,然后重新渲染场景。
这个循环的核心是 requestAnimationFrame 函数,它是浏览器提供的“节拍器”。它告诉浏览器:“在下一帧绘制时,请调用这个函数。”浏览器会在每次屏幕刷新时(通常是每秒 60 次)调用它,从而实现流畅的动画。Three.js 的 renderer.render(scene, camera) 可以把这个循环封装得极其简洁。
在实际项目中,你还需要一个关键工具:Clock(时钟)。它能精确计算两帧之间的时间差(delta time),这个差值正好可以用来驱动运动。为什么要用 Clock?因为不同设备的刷新率不同——一台 120Hz 的显示器和一台 60Hz 的显示器,如果每帧旋转固定角度,动画速度就会差一倍。而把它设置为“每秒旋转 60 度”(rotation += 60 * delta),就能保证在任何设备上都以相同的速度旋转。
1. 计算时间增量:Clock.getDelta() 返回距上一次调用该函数的时间间隔(秒)。
2. 更新位置:每帧根据速度乘以时间增量来计算位移量,保证动画速度与帧率无关。
3. 渲染新画面:调用渲染器,将最新的场景状态绘制到屏幕上。
动画循环就是 3D 世界的“心跳”。有了这个心跳,场景中的一切才能活起来。理解 requestAnimationFrame 和 Clock 的关系,你就掌握了让 3D 世界“动起来”的魔法钥匙。
function animate() { requestAnimationFrame(animate); mesh.rotation.x += 0.01; // 更新积木的旋转 renderer.render(scene, camera); // 重新渲染整个世界}animate();
交互与碰撞
一个会动的 3D 场景很酷,但如果用户只能看、不能摸,那就像一个不允许触摸展品的博物馆——精美但缺乏参与感。要让用户“摸”到积木,就需要交互。Three.js 中最核心的交互工具是 Raycaster(射线检测器)、OrbitControls(轨道控制器),以及用于物理反馈的碰撞检测。
Raycaster 的原理其实非常简单:从相机(或鼠标)位置发射一条看不见的射线,检测这条射线在空间中穿过了哪些物体。就像你闭上一只眼、用手指指向一个方向,你知道手指在那条线上有多远。Raycaster 会返回被射线击中的所有物体列表,并按距离排序。这样用户点击屏幕上的一个点,你就能知道“用户点击了哪个积木”。
OrbitControls 是 Three.js 最常用的相机控制工具,它让用户可以用鼠标拖拽旋转视角、滚轮缩放、右键平移。它就像是给相机装上了一台“云台”,用户可以直接操控自己的视角。看似复杂的功能,用起来只需几行代码:
当交互变得复杂(比如用户拖拽积木到另一个积木上),就需要碰撞检测了。Three.js 本身没有完整的物理引擎,而是通过 Raycaster 和 Box3 等工具实现基础碰撞。例如 Box3 可以计算两个物体的包围盒是否相交。更复杂的物理效果(重力、弹跳、关节)则要集成第三方物理引擎(如 Cannon.js 或 Ammo.js)。碰撞检测的工作原理是:先计算两个物体表面的最近点,再判断是否穿透。
1. 构建射线:从鼠标屏幕坐标转换到世界坐标系,再向场景中发射射线。
2. 检测相交:射线与每个物体的三角形面进行相交测试,找最近的交点。
3. 包围盒碰撞:比较两个物体包围盒各轴的范围,若全部重叠则发生碰撞。
交互系统是 3D 应用与用户之间的“桥梁”。没有它,Three.js 只是一个“展示盒”;有了它,就变成了“游乐场”。
const controls = new THREE.OrbitControls(camera, renderer.domElement);性能优化策略
积木搭得越来越多,场景越来越丰富,但问题也随之而来:画面开始卡顿。就像积木搭得太高,重心不稳,稍微一碰就塌。在 3D 应用里,“卡顿”的本质是帧率(FPS)下降——每秒钟能渲染的画面帧数不足。Three.js 应用的性能优化,就是在和 GPU 的交道中做一个精明的房东,让每一分资源都用在刀刃上。
优化的核心思路有三个方向。第一个方向是减少绘制调用(Draw Calls)。每次 renderer.render() 时,WebGL 需要逐物体进行绘制,一次绘制调用一个物体。如果一个场景里有 1000 个物体,就需要 1000 次绘制调用。优化方法是使用 InstancedMesh 或 mergeBufferGeometries,把同种几何体合并成一个整体。就像把所有相同的积木块粘在一起,变成一个“超大积木”,只需一次绘制。
第二个方向是纹理优化。纹理贴图是显存的大户。5000×5000 的纹理比 1024×1024 的大 25 倍。优化方法包括:压缩纹理格式、动态生成 mipmap(多级纹理)、限制纹理尺寸。使用 RGBELoader 等工具时,也要注意场景中同时加载的纹理总量。
第三个方向是 LOD(Level of Detail,细节层级)——这叫按需简化。当积木离你远,你看不清细节时,用它低精度的替代品显示;当积木靠近时,再切换高精度模型。Three.js 的 THREE.LOD 对象可以帮助实现这一机制,它会根据物体与相机的距离,自动选择不同精度的模型显示。
1. 实例化绘制:相同几何体的多次绘制合并为一次,减少状态切换。
2. LOD 选择:根据距离动态切换模型精度。
3. 纹理压缩:通过压缩格式降低显存占用。
性能优化是 3D 应用从“能跑”到“流畅跑”的分水岭。记住三把钥匙:减少绘制调用、精简纹理、按需分配细节。就像整理积木盒——相同颜色放一起、大块头放底层、不常用的小件收进抽屉,搭起来自然顺手流畅。
AI 应用场景
智能家居 3D 可视化面板
阶段:数据可视化与交互
解决的问题:传统家居控制面板以二维列表展示设备状态,用户难以直观感知空间布局。使用 Three.js 搭建 3D 户型图,将灯光、窗帘、空调等设备以 3D 模型实时渲染,用户一眼看清全屋状态,点击设备即可控制,极大提升交互效率。
具体案例:某智能家居公司使用 Three.js 构建了 3D 数字孪生面板。户型图按真实尺寸建模,用户进入后看到客厅、卧室、厨房的 3D 模型。点击卧室灯光模型,弹出亮度滑块;拖动滑块,场景中灯光即时变化。结合 AI 节能算法,系统还能在 3D 模型中用颜色标识不同房间的能耗等级,实现可视化节能管理。
在线 3D 商品展示与定制
阶段:互动式前端展示
解决的问题:电商商品展示以图文为主,用户无法全面了解商品的立体结构和细节。基于 Three.js 的商品 3D 展示页让用户随意旋转、缩放产品,甚至可以实时定制颜色、材质。
具体案例:某定制家具品牌在其官网引入 Three.js 3D 展厅。用户可以选择沙发模型进行 360° 旋转,点击“换面料”按钮切换皮料颜色和材质,所有变换实时渲染。该页面上线后,商品详情页停留时长远超图文页面,极大地增强了购买信心。
Python 演示
import asyncioimport jsonfrom pyppeteer import launch THREE_JS_APP = """<!DOCTYPE html><html><head><style>body { margin: 0; overflow: hidden; }</style></head><body><script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script><script> var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); var geometry = new THREE.BoxGeometry(1, 1, 1); var material = new THREE.MeshStandardMaterial({ color: 0x818CF8 }); var cube = new THREE.Mesh(geometry, material); scene.add(cube); var light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(5, 10, 7); scene.add(light); scene.add(new THREE.AmbientLight(0x404040)); camera.position.z = 3; var frames = 0; function render() { requestAnimationFrame(render); cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera); frames++; } render();</script></body></html>""" async def main(): browser = await launch() page = await browser.newPage() page.on('console', lambda msg: print('[browser]', msg.text)) await page.goto('data:text/html,' + THREE_JS_APP) await page.waitFor(1000) perf = await page.evaluate('''() => ({ webgl: !!document.querySelector('canvas'), size: { w: renderer.domElement.width, h: renderer.domElement.height } })''') print('perf:', json.dumps(perf)) await page.screenshot({'path': 'threejs_demo.png'}) await browser.close() asyncio.get_event_loop().run_until_complete(main())
from pyppeteer import launch引入无头浏览器控制库,相当于让 Python 开一个“隐形浏览器”。renderer.domElement.width访问 Three.js 渲染器的画布宽度,验证是否按预期尺寸渲染。page.evaluate()在页面上下文中执行 JavaScript 代码,把 Three.js 关键状态回传给 Python。page.waitFor(1000)等待 1 秒让首帧渲染完成,模拟真实用户的等待体验。async def main()使用异步语法管理浏览器生命周期,避免多标签页导致的阻塞。page.screenshot()截取 3D 场景渲染结果,用于视觉回归测试。browser.close()关闭浏览器,释放内存资源。
常见误区
误区我把立方体创建出来了,怎么屏幕上什么都没有?是不是我的电脑不支持 WebGL?我明明看到别人的代码也是这样写的啊。
正解最常见的黑屏原因之一就是忘了把物体添加到场景里。就像你搭好了一块积木却放在桌子底下,摄像机(眼睛)自然看不到它。请一定记得 scene.add(mesh),并确认相机的位置正对着物体。此外还应检查相机的 near 和 far 裁剪面,物体如果在裁剪范围之外,也会被悄然隐藏。
为何常见:初学者容易把“创建对象”和“在场景中显示”划等号。而 Three.js 中所有对象都要挂到场景树中才会被渲染,这种“依赖层级”的思维需要刻意练习。
误区我设置的相机参数明明没问题,为什么物体被拉伸了?是不是 Three.js 的 bug?看方形的积木都变成扁的了。
正解这通常是 camera.aspect 没有跟随窗口大小更新。相机的 aspect 代表画面的宽高比,如果创建时是 16:9,而实际窗口变成了 1:1,画面就会明显变形。正确做法是在窗口 resize 时同时更新 camera.aspect = window.innerWidth / window.innerHeight 和 renderer.setSize。
为何常见:人们容易忘记“相机参数是持久状态”——它不会自动感知浏览器窗口变化。很多刚入门的朋友会忽略 window.addEventListener('resize', ...) 这个监听器。
误区既然要不断刷新,直接用 `setInterval(render, 1000/60)` 不就行了吗?反正都是每秒 60 次调用函数。
正解两者有本质区别。requestAnimationFrame 是浏览器原生优化的帧回调机制,其执行频率与屏幕刷新率完全同步(通常是 60Hz),且在页面不可见时会自动暂停,节省资源。而 setInterval 无论页面是否可见都会执行,在后台标签页中会不断积压任务,造成性能浪费;同时在刷新率非 60Hz 的屏幕上也会产生掉帧或撕裂。
为何常见:习惯了传统 JavaScript 定时器逻辑的人,容易用 setInterval 的思维套用到 Three.js 动画上,忽略了渲染循环需要与屏幕刷新同步这一特性。
误区我场景里倒了 1000 个立方体,帧率一下降到 15fps。我的电脑是不是太旧了?需要换显卡才行吗?
正解在 Three.js 中,性能瓶颈往往不是顶点数量,而是绘制调用次数。1000 个独立 Mesh 就是 1000 次绘制调用,这会导致 CPU 和 GPU 之间频繁通信。优化方法是用 InstancedMesh(实例化网格),把 1000 个立方体合并为一次绘制调用。正确的思路不是换硬件,而是用正确的 API 组合。
为何常见:人们习惯用“物体多”来解释卡顿,却没有意识到 WebGL 绘制的瓶颈模型。理解“绘制调用”和“顶点数”的区别,是 3D 性能优化入门的第一课。
误区我的场景好黑,我把 `AmbientLight` 亮度加了好几倍还是没用,是不是 Three.js 的灯光有缺陷?
正解如果物体使用 MeshStandardMaterial 或 MeshPhongMaterial,其亮度依赖于法线方向和光源方向的夹角。若物体表面为纯黑、法线缺失,即使灯光再亮也无法显现。另一种可能是材质被替换成了 MeshBasicMaterial,它完全不响应光照。请先确认材质类型,再调整灯光功率和颜色。
为何常见:初学者通常对材质和灯光的关系认识模糊,不理解“材质决定如何响应光”。从“加灯”到“理解渲染方程”,是入门到进阶的必由之路。
面试题
Q1. Three.js 中,Scene 对象的角色相当于什么?
- A.一个充满魔法的大杯子
- B.一个存放所有对象的容器← 正确答案
- C.一个专门输出文字的终端
- D.一个直接渲染画面的显卡
答案:B。场景是 Three.js 所有对象的容器,相当于搭积木时的底板。选项 A 太玄、C 是控制台的角色、D 是渲染器的功能,只有 B 准确描述了 Scene 的职责。
Q2. 下面哪种相机适合用于模拟人眼的近大远小效果?
- A.透视相机 PerspectiveCamera← 正确答案
- B.正交相机 OrthographicCamera
- C.立方相机 CubeCamera
- D.不可见相机 StereoCamera
答案:A。透视相机的视锥体模拟人眼视觉,具有近大远小的效果,适合 3D 游戏和产品展示。正交相机没有透视变形,适合绘制平面图。C 和 D 是特殊场景才会用到的相机类型。
Q3. Three.js 中,renderer.render(scene, camera) 的作用是?
- A.把场景和相机对象拼接成一个新物体
- B.根据相机视角将场景绘制到画布上← 正确答案
- C.把场景中的物体全部删除重画
- D.将相机的位置移动到一个新坐标
答案:B。renderer.render() 是渲染管线的核心,它使用相机定义的视角来绘制场景中的对象,并输出到画布。它不是拼接物体也不是删除物体,更不是移动相机,而是“拍照”这一动作本身。
Q4. Raycaster 在 Three.js 中的主要用途是什么?
- A.在场景中生成光线的动画效果
- B.发射虚拟射线检测空间中的对象← 正确答案
- C.给物体添加材质贴图
- D.压缩场景中的几何体内存
答案:B。Raycaster 从一个点发射射线,检测射线穿过的所有物体,常用于鼠标点击选中物体。它不生成可见光线、不与材质相关、更不负责内存压缩。在三方场景的交互中,它是“拾取”操作的核心工具。
Q5. 以下哪些方法可以提升 Three.js 应用的渲染性能?
- A.使用 InstancedMesh 合并相同几何体← 正确答案
- B.使用 LOD 按距离切换模型精度← 正确答案
- C.在每帧中调用 renderer.setSize 来适配窗口
- D.提前压缩纹理等资源← 正确答案
答案:ABD。实例化合并减少绘制调用、LOD 按需简化远距离模型、压缩纹理减少显存占用,都是参数化且能大幅提升性能的做法。而每帧调用 setSize 会反复触发渲染尺寸配置,造成性能浪费,应该仅在窗口 resize 时调用。
Q6. MeshStandardMaterial 与 MeshBasicMaterial 最根本的区别在于?
- A.前者颜色多彩,后者只有黑色
- B.前者受光照影响,后者不受光照影响← 正确答案
- C.前者只能用于平面,后者只能用于球体
- D.前者体积大,后者体积小
答案:B。MeshStandardMaterial 基于 PBR 物理渲染模型,需要计算光线和材质交互,而 MeshBasicMaterial 是纯色渲染,不受任何光源影响。这是两者最本质的差异,也决定了它们的适用场景。
Q7. 关于 PerspectiveCamera 的 near 和 far 参数,下列说法正确的是?
- A.它们定义了相机可见的距离范围← 正确答案
- B.超出
far的物体将不会被渲染← 正确答案 - C.
near值越小就能看到越清晰的物体 - D.两者之比过大可能导致深度缓冲精度不足← 正确答案
答案:ABD。near/far 定义视锥体的裁剪范围,超出部分不会被渲染。near 太小不会提升清晰度,反而可能因深度缓冲区精度问题导致渲染错误。far/near 比值越大,深度精度被稀释的程度越高,这就是选项 D 正确的原因。
Q8. 在 Three.js 动画循环中,使用 Clock.getDelta() 的主要目的是:
- A.计算动画已经运行的总时长
- B.获取每帧之间的时间间隔以保证帧率无关的速度← 正确答案
- C.阻塞主线程降低渲染频率
- D.强制动画帧率固定为 60FPS
答案:B。getDelta() 返回与上一帧的时间差,用来计算“每单位时间”的运动量,保证动画在不同刷新率设备上速度一致。它不计算总时长,更不会阻塞线程或强制帧率。
Q9. OrbitControls 主要让用户能够完成什么操作?
- A.让物体自动旋转
- B.通过鼠标拖拽旋转、缩放、平移视角← 正确答案
- C.编辑物体的顶点数据
- D.生成动态光照贴图
答案:B。OrbitControls 是相机控制器,让用户像操作云台一样控制相机的观察角度。它不旋转物体本身,也不编辑几何体或生成贴图。它是 Three.js 中实现“环绕观察”交互的标准方案。
Q10. 下列哪个是 Three.js 中最基本的可渲染对象?
- A.一个用于存储数据的 JSON 对象
- B.由几何体和材质组成的 Mesh← 正确答案
- C.一个用于加载纹理的图片按钮
- D.一个输出日志到控制台的函数
答案:B。Mesh(网格)是 Three.js 中最基本的渲染对象,它把几何体形状和材质外观组合成一个可渲染的整体。它不是数据存储结构、不是 UI 元素,更不是函数,而是场景中“看得见摸得着”的实体。