想象你在一个漆黑的房间里,想要让观众看清一件精美的雕塑。你需要在正确的位置放一盏射灯、给雕塑搭一个旋转的展示台、让观众能绕着雕塑走动、甚至伸手推动它旋转。Three.js 就是你手里的这套“舞台搭建工具箱”——只不过舞台从现实世界搬进了浏览器。 传统的二维图表像是贴在墙上的海报,信息再多也只能平铺展开。而 3D 可视化像是把海报变成了一个可以走进的展厅:数据点有了空间位置,指标的高低变成了立体山峰,关系网络变成了交错的光带。这篇文章会带你用 Three.js 从零搭建这样一个“数字展厅”:先铺好舞台地面(场景),装好观众席视角(相机),打开灯光(光照),让演员登台(几何体与模型),最后给演员写好剧本(数据绑定)——让静态的数据真正地“活”起来。

岗位关联

掌握 Three.js 3D 可视化,前端开发者能把冰冷的数据表格变成有冲击力的交互展厅,为数字孪生、智慧园区大屏等场景提供下一代数据呈现方案,大幅提升技术汇报与产品演示的感染力。

目录
  1. 可视化演示
  2. 搭建3D舞台
  3. 控制观众视角
  4. 点亮舞台灯光
  5. 邀请演员登场
  6. 编写剧本台词
  7. 让数据活起来
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示用Three.js打造浏览器的核心机制,通过采集/分析/决策/反馈四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

用Three.js打造浏览器:Thre Three.js的场景图与渲染 相机系统与OrbitContr 核心机制可视化 用Three.js打造浏览器整体架构与关键组件

搭建3D舞台

你还记得小学文艺汇演的舞台吗?老师先让工人铺好地板、挂好幕布,再请调音师把音响调试到位——在一切都准备好之前,演员是不能上台的。Three.js 的世界是一样的:第一步不是急着画图形,而是先把这个“虚拟剧院”的地基打牢。

这个地基由两个大件组成。第一件是场景(Scene),它是所有物体共同生活的空间——相当于整个舞台的物理范围。第二件是渲染器(Renderer),它像一个放映机的镜头,负责把舞台上的画面“拍摄”下来并投影到浏览器屏幕上。你创建了一个场景、放进一个渲染器,再配上舞台地板(背景色),地基就打好了。

不过,地基打好之后还缺一个“放映员”——他需要不停地把舞台画面投到屏幕上。渲染循环就是这个放映员:它用 requestAnimationFrame 让画面以每秒约 60 帧的速度持续刷新。如果没有这个循环,你只能看到一张静止的照片;有了它,舞台上的演员才能真正“动”起来。

渲染循环这个“放映员”一旦上岗,舞台就活了。地基搭好了,下一步该给舞台安装观众席的“眼睛”——也就是相机了。

每秒渲染帧数=1000msΔt每帧渲染耗时\text{每秒渲染帧数} = \frac{1000\text{ms}}{\Delta t_{\text{每帧渲染耗时}}}
这个公式说的是:一帧画面花的时间越短,每秒能播出的画面就越多,动画就越流畅。Three.js 通过 requestAnimationFrame 自动维持这个循环。
  1. 每秒渲染帧数表示观众看到的画面刷新速度,单位是 fps(frames per second,帧每秒)。\text{每秒渲染帧数} 用文字描述了这个单位。
  2. 1000ms1 秒等于 1000 毫秒,是总时间池。
  3. Δt(每帧渲染耗时)渲染器完成一帧画面所需的时间,包括所有物体位置计算、光照计算和像素绘制。用 \Delta t_{\text{每帧渲染耗时}} 标明它是“每帧”的时间。
  4. 两者相除用总时间除以单个帧的时间,就得到每秒能渲染多少帧。
javascript5 行
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);document.body.appendChild(renderer.domElement);

控制观众视角

假设你站在舞台前面,想看清楚演员的表情,你得往前走两步;想看清整个舞台的布局,你得退到后排。相机在 Three.js 里的角色,就是这双“观众的眼睛”——它决定你的观众从哪个位置、以什么角度看到这个 3D 世界。

Three.js 提供了两种最常见的“眼睛”。一种是透视相机(PerspectiveCamera),它模拟真实人眼,有“近大远小”的效果——就像你看远处的山很小、走近了才发现它巨大无比。另一种是正交相机(OrthographicCamera),它没有透视变形,物体无论远近大小都一样,适合看工程图纸或 2.5D 地图。

有了合适的“眼睛”,还得让观众能自由地转动头部。轨道控制器(OrbitControls) 就像给观众装了一个万向转椅:按住鼠标左键拖动可以旋转视角,滚动滚轮可以拉近拉远,按住右键可以平移——观众想看哪里就看哪里。

数据的空间感,全靠这双“眼睛”来呈现。

透视投影:(x′y′)=fz(xy)\text{透视投影}:\quad \begin{pmatrix} x' \\ y' \end{pmatrix} = \frac{f}{z} \begin{pmatrix} x \\ y \end{pmatrix}
这个公式说的是:屏幕上的位置(x',y')等于物体的原始位置(x,y)乘以“焦距 f 除以深度 z”这个缩放系数。物体离得越远(z 越大),缩放系数越小,看起来就越小——这就是“近大远小”的数学本质。
  1. 透视投影说明这个公式描述的是透视相机将 3D 坐标投影到 2D 屏幕的过程。
  2. (x',y')带撇号的坐标表示物体最终在屏幕上显示的位置,\begin{pmatrix} x' \\ y' \end{pmatrix} 表示这是一个二维向量。
  3. f(焦距)f 是相机的焦距,焦距越大,视野越窄,物体显得越大,\frac{f}{z} 将其放在分子上。
  4. z(深度)z 是物体到相机的距离。它在分母上,意味着 z 越大,缩放越小。
  5. 乘以原始坐标整个分数作用在 \begin{pmatrix} x \\ y \end{pmatrix} 上,将原始坐标缩放得到屏幕坐标。

点亮舞台灯光

如果你在黑暗中看一个演员,你只能看到他的轮廓,完全看不清服装的细节。舞台美术师知道:灯光比演员更重要。Three.js 里的光照系统同样如此——数据模型做得再精细,没有合适的光,画面也会平淡如纸。

Three.js 提供了几种“灯”。环境光(AmbientLight) 像剧场的壁灯,均匀地照亮所有角落,没有明显的明暗对比,让物体不至于一片漆黑。平行光(DirectionalLight) 像太阳,光线是平行的,能产生清晰的阴影,适合模拟户外场景。点光源(PointLight) 像舞台上的追光灯,从一个点向四周发散,近处亮、远处暗。

有了光,物体还需要“衣服”来反射光——这就是材质(Material)。MeshBasicMaterial 像一件不反光的棉布衣,不受光照影响,只显示自己的颜色;MeshLambertMaterial 像哑光面料,能吸收部分光;MeshPhongMaterial 像丝绸或金属,带有高光反射,看起来更有质感。选对材质,数据点的“颜值”会大幅提升。

灯光打好了,演员该登场了。

I表面=I光源distance2I_{\text{表面}} = \frac{I_{\text{光源}}}{\text{distance}^2}
这个公式说的是光强的衰减规律:物体离光源越远,接收到的光强按距离的平方衰减。舞台上的追光灯为什么照不到三楼观众席?就是因为距离变远后,光强快速减弱了。
  1. I(表面)I_{\text{表面}} 表示物体表面实际接收到的光照强度。
  2. I(光源)I_{\text{光源}} 表示光源本身的发光强度。
  3. distance²\text{distance}^2 是物体到光源距离的平方。它在分母上,说明距离一变大,光强急剧下降。
  4. 整体关系分子是光源强度,分母是距离平方,两者相除得到最终的表面亮度。

邀请演员登场

舞台、观众席、灯光都准备好了,现在轮到主角登场。这个主角就是几何体(Geometry)。Three.js 内置了各种“身形”——球形(Sphere)、立方体(Box)、圆柱体(Cylinder)——就像服装店里的基本款模特,你直接拿起就能用。

但光有身形还不够,演员还得穿上衣服才能见人。在 Three.js 里,网格对象(Mesh) 就是“身形 + 服装”的组合:它将一个几何体(身形)和一个材质(服装)打包成一个可以被放入场景的对象。你可以把它比作出场单上的完整角色卡:

当数据的形状超过简单的几何体时,比如要展示一台精密的发动机模型,就得让专业的建模师在 Blender 或 C4D 里雕好模型,再以 GLTF/OBJ 格式导入到 Three.js 中。这就像是从服装店直接请来一位穿着成衣的演员——你不需要亲手缝制每件衣服,只需要加载他的“档案”。

布景完成,演员已就位,剧场的准备工作全部结束。但要让这场演出真正有“剧情”,还得让演员按照剧本表演——这就是数据绑定。

Mesh=Geometry⊕Material\text{Mesh} = \text{Geometry} \oplus \text{Material}
这个公式用加法表示一个网格对象的本质:几何形状定义了“长什么样”,材质定义了“什么质感”,两者组合在一起,一个可以放进场景的完整角色就诞生了。
  1. Mesh(网格对象)\text{Mesh} 表示 scene 中可渲染的最小完整单位,它是最终被渲染器绘制的对象。
  2. Geometry(几何体)\text{Geometry} 定义物体的几何形状,即顶点坐标、面的连接方式等信息。
  3. ⊕(组合符号)\oplus 表示“组合”,Mesh 不是几何和材质的简单叠加,而是有机地组合成一个新对象。
  4. Material(材质)\text{Material} 决定了物体表面如何与光交互——是哑光、高光还是发光。
javascript4 行
const geometry = new THREE.BoxGeometry(1, 1, 1);const material = new THREE.MeshPhongMaterial({ color: 0x818cf8 });const cube = new THREE.Mesh(geometry, material);scene.add(cube);

编写剧本台词

一个 3D 场景就像一场舞台剧:演员有台词,灯光有提示,道具要配合。在数据可视化里,剧本就是你的数据。Three.js 中的数据绑定,本质上就是回答这样一个问题:数据的每一个数值,该控制舞台上的什么参数?

最常见的映射方式是“数据控制柱子的高度”。销售额高,柱子就高;客户量多,球体就大。这种映射的数学基础是归一化——先把数值范围缩放到一个合适的比例尺上,防止数据大的把舞台捅破,数据小的看不见。

除了高度,数据还可以映射到颜色和大小。在散点图中,每个点是一个小球体,点的颜色可以表示类别(红色警戒、绿色健康),点的大小可以表示权重。这一思路与我们之前在 Canvas 2D 条形图中熟悉的“数据到视觉编码”完全一致,只是 Three.js 把它扩展到了三维空间。

当观众用鼠标点击场景中的一个数据点时,Three.js 需要用射线检测(Raycaster) 来判定鼠标的二维坐标与哪个 3D 物体相交——这相当于“顺着观众的视线发射一束看不见的光,看看它碰到了哪位演员”。

剧本写好了,但舞台上的演出应该是活的。

Ray: P(t)=O+t⋅D\text{Ray: } \mathbf{P}(t) = \mathbf{O} + t \cdot \mathbf{D}
这条公式描述了一条三维空间中的射线:从起点 O(相机位置)出发,沿方向 D 前进,t 表示走了多远。当 t 对应的点正好落在某个物体表面时,就表明鼠标点中了这个物体。
  1. P(t)\mathbf{P}(t) 表示射线在前进 t 个单位后所到达的空间位置,是一个三维向量。
  2. O(起点)\mathbf{O} 是射线的起点,在拾取场景中它通常是相机的位置坐标。
  3. t(步长)t 是一个非负的标量参数,表示射线传播的距离,数学上每取一个 t 就得到射线上一个点。
  4. D(方向)\mathbf{D} 是射线的单位方向向量,决定射线朝哪个方向发射。整个公式就是一个参数化射线方程。
javascript1 行
const normalizedValue = (value - min) / (max - min) * maxHeight;

让数据活起来

静态的 3D 场景只是一张漂亮的截图。真正的“可视化”要能让观众感受到数据的生命力——柱子缓缓升起、数据点轻轻浮动、视角平滑旋转。这就是 Three.js 动画体系要解决的问题。

前面提到的 渲染循环 在这里发挥关键作用:动画的本质,就是在每一帧渲染前微调场景中各物体的属性(位置、角度、透明度等),以“每一帧都变一点”的方式累计出运动的错觉。这与你小时候在书本角落画小人、快速翻页形成动画的原理完全一样——但 Three.js 替你完成了那本“书”。

为了让运动平滑而非跳变,需要引入 插值(Interpolation)。比如一个数据点要从位置 A 移动到位置 B,我们不希望它瞬间闪现,而是希望它在 1 秒内匀速地滑过去——于是每一帧计算这次移动的中间位置,呈现出一条平滑的轨迹。

有了渲染循环和插值这两个“时间魔法师”,我们还能给场景加上交互——用户点击一个数据柱子,柱子自动旋转一圈或展开详细面板。Three.js 的交互事件体系让用户不再是“被动看戏的观众”,而是能“走上舞台参与表演的嘉宾”。

至此,一套完整的 Three.js 3D 数据可视化方案已经成型。

P(t)=(1−t)⋅A+t⋅B,t∈[0,1]\mathbf{P}(t) = (1 - t) \cdot \mathbf{A} + t \cdot \mathbf{B}, \quad t \in [0, 1]
这个公式是线性插值:t 是 0 到 1 之间的进度值。t=0 时 P 等于 A,t=1 时 P 等于 B,t 在中间时 P 就在 AB 连线上平滑移动。
  1. P(t)\mathbf{P}(t) 表示 t 时刻插值点的位置。
  2. (1-t)·A当 t=0 时,(1-t)\cdot\mathbf{A} = A,即起点生效;当 t=1 时这一项为 0,起点不再影响结果。
  3. t·B当 t=1 时,整个式子等于 B;当 t=0 时此项为 0。
  4. t ∈ [0,1]t \in [0, 1] 表示 t 的取值范围,超出这个范围就不叫插值而叫外推了。

AI 应用场景

智慧园区数字孪生大屏

阶段:数据呈现与决策支持

解决的问题:传统园区管理用二维平面图展示楼宇、人流、能耗数据,信息层级不直观,运维人员难以快速定位异常区域。用 Three.js 构建园区 3D 数字孪生模型后,每栋楼的能耗、温度、人流量实时映射为 3D 柱子的高度和颜色,异常区域一目了然。

具体案例:某科技园区将园区内 12 栋楼的实时水电数据绑定到 Three.js 搭建的 3D 模型楼宇上,楼顶的柱状体随能耗升高而长高,绿色到红色渐变表示能耗等级。运维人员在 3D 场景中点击任意楼层即可下钻到楼层平面控制台。结合我们在“编写剧本台词”中学到的射线拾取技术,点击一栋楼会高亮显示并弹出详单。

AI 训练数据分布演示

阶段:数据探索与特征分析

解决的问题:做机器学习时,面对高维数据我们常常“看不见”它们的分布。把高维特征用 PCA 或 t-SNE 降维到三维空间后,用 Three.js 散点图展示聚类效果,数据分布变得直观可感。

具体案例:AI 团队在训练图像分类模型时,用 Three.js 构建了 MNIST 手写数字的 3D 特征分布图。每个数字样本是一个小球,颜色代表预测类别,小球之间的距离代表特征相似度。模型训练过程中,团队发现某些类别的小球混杂在一起,定位到是数据标注错误导致了分类边界模糊,修正后模型准确率提升了 4%。

电商 3D 商品展示

阶段:产品表达与用户交互

解决的问题:传统电商商品展示依赖二维照片,用户无法真实感知商品形状。用 Three.js 加载 GLTF 模型,实现 360 度旋转查看和材质切换,让用户在购买前“把商品拿在手里端详”。

具体案例:某家具电商平台用 Three.js 搭建了 3D 展厅,用户可以通过轨道控制器(就是“观众的万向转椅”)旋转沙发模型、切换不同布料材质(切换材质),避免实际购买后“色差”和“尺寸误差”的退换货痛点。接入 AI 家具摆放推荐后,用户还能将 3D 沙发拖入自家照片中看效果。

Python 演示

python41 行
import numpy as npimport matplotlib.pyplot as plt def normalize(arr, new_min=0, new_max=100):    """把数据归一到 [new_min, new_max] 区间,模拟 Three.js 坐标映射"""    arr_min, arr_max = arr.min(), arr.max()    if arr_max == arr_min:        return np.full_like(arr, (new_min + new_max) / 2)    return (arr - arr_min) / (arr_max - arr_min) * (new_max - new_min) + new_min def generate_sales_data(n_points=50):    """随机生成模拟的销售数据"""    rng = np.random.default_rng(42)    return {        'sales': rng.integers(50, 500, n_points),        'profit': rng.integers(5, 100, n_points),        'city_code': rng.integers(0, 5, n_points),    } def build_3d_scene(data):    """把数据映射成 3D 场景中的位置、大小、颜色"""    sales_norm = normalize(data['sales'], 0, 100)    profit_norm = normalize(data['profit'], 0, 100)    city_idx = data['city_code']     colors = plt.cm.viridis(city_idx / city_idx.max())    sizes = 20 + sales_norm * 3    fig = plt.figure(figsize=(10, 8))    ax = fig.add_subplot(111, projection='3d')    ax.scatter(sales_norm, profit_norm, city_idx * 10,               c=colors, s=sizes, alpha=0.7)    ax.set_xlabel('Sales (0-100)')    ax.set_ylabel('Profit (0-100)')    ax.set_zlabel('City Code')    ax.set_title('3D Sales Data Visualization (Simulating Three.js Scene)')    return fig, ax if __name__ == '__main__':    data = generate_sales_data()    fig, ax = build_3d_scene(data)    plt.show()
目的:用 Python 的 matplotlib 模拟 Three.js 的“数据→3D 视觉通道”映射过程,帮助不熟悉 WebGL 的读者理解数据如何在三维空间中编码。
  1. def normalize(arr, new_min=0, new_max=100):归一化函数把任意数值范围的数据缩放到目标区间,对应 Three.js 场景中把业务数据映射到三维坐标时的缩放逻辑。
  2. (arr - arr_min) / (arr_max - arr_min) * (new_max - new_min) + new_min标准最大最小归一化公式:先计算数据在原始范围的比例,再按比例搬到新区间。
  3. rng.integers(50, 500, n_points)生成 50 个城市的模拟销售额数据,该数据后续映射为 3D 场景中散点的位置。
  4. sales_norm = normalize(data['sales'], 0, 100)把原始销售额映射到 0-100 的“场景坐标空间”,对应 Three.js 中 z = normalize(value) 的操作。
  5. sizes = 20 + sales_norm * 3保持销售额同时控制点大小,演示“一个数据维度驱动多个视觉通道”的思路。
  6. ax.scatter(sales_norm, profit_norm, city_idx * 10, c=colors, s=sizes, alpha=0.7)核心的 3D 散点绘制函数:参数 c 和 s 分别绑定颜色与大小,等价于 Three.js 中的 Mesh 颜色与缩放属性。
  7. plt.cm.viridis(city_idx / city_idx.max())将城市编号映射为颜色值,对应 Three.js 中“数据类别→材质颜色”的编码方式。

常见误区

误区我一直分不清 Scene、Camera、Renderer 到底有什么区别,觉得它们都是“画布”的一部分,随便用哪个都能画东西。

正解这三者分工完全不同:Scene 是放物体的舞台(容器),Camera 是拍舞台的摄像机(视角),Renderer 是把摄像机看到的画面画到屏幕上的放映机(绘制工具)。缺少任何一个,画面都出不来。用剧场的比喻来说:场景是舞台的空间范围,相机是摄影师的机位,渲染器是摄影师按下快门后冲洗照片的过程。

为何常见:初学时看到官方示例里三行代码几乎固定不变,觉得它们是一个“固定搭配”,于是把它们混杂在一起。没意识到它们各自负责生命周期中完全不同的阶段。

误区DirectionalLight 和 PointLight 都是灯光,效果应该差不多,只是名字不一样而已。

正解区别巨大。平行光的光线是平行的,光源可以想象在无限远处,全场照度均匀,适合模拟太阳;点光源的光线是发散的,从某个点向外扩散,有强烈的距离衰减。用舞台比喻:平行光是头顶上方一排均匀的平板灯,全场亮暗一致;点光是追光灯,只照亮舞台上的一点,越远越暗。

为何常见:因为日常生活中“灯”这个字太过笼统,我们不会区分灯在物理上造成的亮暗差异。而在 Three.js 中,每种光的数学模型不同,渲染效果天差地别。

误区我在网上下载了一个 GLTF 模型,用 `load` 方法加载后以为它会自动出现在屏幕上,结果一片空白。

正解加载只是“把演员请到后台”,你必须做两件事才能让他上场:第一,把加载到的场景(gltf.scene)添加到你的主 Scene 中;第二,确认你的相机位置和大小能“看到”他。另外,很多模型本身自带材质,但模型过大或居中设置不当,也会导致加载成功后因为缩放比例和相机位置问题而看不到。

为何常见:把“加载成功”和“渲染可见”混为一谈。真实世界的排练也一样:演员到了后台不代表他已经站在舞台中央,导演还要安排他上场并调整他的站位。

误区我把销售额数据直接赋给柱子的高度,为什么不显示 5000 那么高的柱子?

正解Three.js 使用的三维坐标系单位是相对值,不是真实物理单位。5000 与场景中相机的位置(通常 z 在 5-100 之间)不匹配,会飞出视野。必须先做归一化——把数据映射到 0-1 或 0-100 的场景单位区间,再乘以期望的最大高度。就像你在 PPT 中放入一张巨大的照片,必须缩放它才能适应画布。

为何常见:新手容易把数据值直接当成坐标值使用,忽略了坐标系需要一个适配数据范围的缩放过程。

误区我应该给所有物体都添加动画,这样场景看起来更炫酷!于是每一帧更新几十个物体的旋转和位置,结果页面卡得要死。

正解动画循环本身很简单,但每一帧要执行的更新操作越少,性能越好。每帧更新大量对象的属性、调用 render,都会占用 GPU/CPU。好的做法是:能不动的物体就不动,只对必要的对象做更新;复杂的模型可以预烘焙到纹理上;需要大量动画时考虑使用 GPU 粒子系统。

为何常见:被炫酷的 3D 效果吸引,以为“越多越强”,忘记每帧都是性能预算有限的实时渲染。真实演出也一样:舞台上所有特效同时开火,反而会让观众眼花缭乱,还会导致设备过载。

面试题

Q1. 在 Three.js 中,Scene(场景)的主要职责是什么?

单选题 · easy

  • A.负责绘制像素到屏幕上
  • B.存储物体、灯光和相机← 正确答案
  • C.计算物体的物理运动规律
  • D.创建纹理和材质资源

答案:B。Scene 是存放物体的容器,相当于舞台空间,它包含所有网格、灯光和相机,渲染器从场景中读取需要绘制的内容。A 是渲染器的职责,C 是物理引擎的工作,D 是纹理加载器的工作。

Q2. 在 Three.js 中,OrthographicCamera 与 PerspectiveCamera 的主要区别是什么?

单选题 · easy

  • A.前者有背景色,后者没有
  • B.前者没有近大远小效果← 正确答案
  • C.前者支持阴影,后者不支持
  • D.前者只能用于正交三维图

答案:B。正交相机没有透视变形,物体大小不随距离变化,工程图常用;透视相机模拟人眼,有近大远小效果。A、C、D 均为干扰项,阴影与相机类型无关。

Q3. requestAnimationFrame 在 Three.js 渲染循环中的主要作用是什么?

单选题 · easy

  • A.将画面输出到外部显示器
  • B.在下一帧刷新前调用回调函数← 正确答案
  • C.处理鼠标和键盘的输入事件
  • D.计算场景中物体的碰撞结果

答案:B。requestAnimationFrame 在浏览器准备刷新画面时调用传入的回调,让动画循环以屏幕刷新率运行,从而保证流畅。A 是浏览器渲染管线的工作,C 是事件系统,D 是物理引擎的职责。

Q4. 下列哪种光源最适合模拟户外阳光直射的明亮效果?

单选题 · mid

  • A.环境光 AmbientLight
  • B.平行光 DirectionalLight← 正确答案
  • C.点光源 PointLight
  • D.聚光灯 SpotLight

答案:B。平行光的光线互相平行,来自无限远处,模拟太阳光非常合适。环境光均匀照亮所有表面、没有方向性;点光源从一点向外发散,有距离衰减;聚光灯呈锥形照射,适合局部强调。

Q5. 将一个网格对象成功添加到场景后,还需要加入什么才能让它显示出来?

单选题 · mid

  • A.AxesHelper 坐标轴辅助
  • B.Camera 和 Renderer← 正确答案
  • C.Raycaster 射线检测
  • D.BufferGeometry 缓存几何体

答案:B。场景中有了物体之后,必须有相机决定“从哪个角度拍”、渲染器决定“怎么画到屏幕上”,两者缺一不可。A 是辅助工具,C 是交互拾取工具,D 是几何体内部结构,都不直接影响渲染。

Q6. 关于 Three.js 中数据与视觉通道的映射,下列说法正确的是哪些?

多选题 · mid

  • A.数据可以映射为物体的大小← 正确答案
  • B.数据可以映射为物体的颜色← 正确答案
  • C.数据可以映射改变物体的材质← 正确答案
  • D.数据必须映射为物体的位置

答案:ABC。Three.js 数据绑定的灵活性体现在多种视觉通道:大小、位置、颜色、透明度、材质属性等都可以被数据驱动。D 过于绝对,位置只是其中一种可能的映射方式,并非“必须”,所以排除。

Q7. Three.js 中,Raycaster 主要的功能是什么?

单选题 · mid

  • A.优化场景渲染性能
  • B.检测射线与物体的相交← 正确答案
  • C.计算阴影的投射方向
  • D.生成程序化纹理贴图

答案:B。Raycaster 从某个点沿方向发射一条射线,检测它是否与场景中的网格相交。拾取就是利用这个技术判断鼠标点击是否命中某个 3D 物体。A 是渲染优化器,C 是阴影计算,D 是纹理生成,都与射线无关。

Q8. 以下哪些做法能提升 Three.js 场景的渲染性能?

多选题 · mid

  • A.在动画循环中动态改变所有光源的位置
  • B.仅对需要更新的物体修改属性← 正确答案
  • C.对静态场景关闭重新渲染← 正确答案
  • D.使用大分辨率纹理给每个物体贴图

答案:BC。动画循环中每帧只应更新真正变化的物体;如果场景完全静止,可以只渲染一帧,省略重复渲染。A 中每帧移动所有光源会大幅增加计算量;D 大纹理占用显存,反而降低性能。

Q9. 在 Three.js 中,关于 MeshPhongMaterial 与 MeshLambertMaterial 的异同,下列描述正确的有哪些?

多选题 · hard

  • A.Phong 材质支持高光反射← 正确答案
  • B.Lambert 材质受光照影响← 正确答案
  • C.Phong 材质不受光照影响
  • D.Lambert 材质计算量通常更小← 正确答案

答案:ABD。MeshPhongMaterial 支持镜面高光,能呈现光泽感;MeshLambertMaterial 只计算漫反射,没有高光,因此计算量较小。C 错误——Phong 材质也受光照影响,只是多了高光分量。

Q10. 线性插值公式 P(t) = (1-t)·A + t·B 中,当 t=0.5 时,P 位于什么位置?

单选题 · hard

  • A.线段 AB 的三分之一处
  • B.线段 AB 的中点← 正确答案
  • C.靠近 B 点四分之一处
  • D.线段 AB 延长线之外

答案:B。当 t=0.5 时,P 等于 A 和 B 各占一半的加权平均,正好是线段 AB 的中点。t 从 0 到 1 线性变化时,P 从 A 匀速移动到 B,这是平滑动画的基础。其他比例分数均不符合 t=0.5 的语义。