本文档旨在覆盖从 Three.js 基础到图形学底层、性能优化及 WebGPU 前沿的 100 道面试题。
第一部分:基础核心 (Q1-Q20)
Q1: Three.js 的三大核心组件是什么?
- Scene (场景):所有物体的容器。
- Camera (相机):决定观察视角(透视或正交)。
- Renderer (渲染器):将场景和相机结合,渲染出最终画面 (Canvas)。
Q2: BufferGeometry 和 Geometry (已废弃) 的区别?
- BufferGeometry:数据存储在
TypedArray(如Float32Array) 中,直接映射到 GPU 的 Buffer,性能极高,内存占用低。 - Geometry:使用
Vector3和Face3对象存储,内存占用大,转换到 GPU 慢,现已从 Three.js 核心移除。
Q3: Mesh, Line, Points 的区别?
- Mesh:三角形网格,由顶点索引构成面。
- Line:线段,连接相邻顶点。
- Points:粒子点,每个顶点渲染为一个面向屏幕的方形/圆形。
Q4: 什么是 Scene Graph (场景图)?
- 一种树状结构,用于管理场景中的物体。
- 子物体 (
children) 会继承父物体 (parent) 的变换(位置、旋转、缩放)。 - 核心方法:
add(),remove(),attach()。
Q5: PerspectiveCamera 和 OrthographicCamera 的区别?
- PerspectiveCamera (透视):近大远小,模拟人眼,用于 3D 场景。参数:fov, aspect, near, far。
- OrthographicCamera (正交):无透视效果,物体大小与距离无关,用于 2D UI、工程制图。参数:left, right, top, bottom, near, far。
Q6: 解释 Three.js 中的材质 (Material) 基类及其共有属性。
- 所有材质继承自
Material。 - 共有属性:
opacity(透明度),transparent(是否透明),side(Front/Back/Double),visible(可见性),depthTest(深度测试),depthWrite(深度写入)。
Q7: MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial 的区别?
- Basic:不受光照影响,纯色。
- Lambert:基于 Lambert 光照模型,漫反射,不支持镜面高光,适合粗糙表面(性能好)。
- Phong:基于 Blinn-Phong 模型,支持镜面高光 (Shininess),适合光滑表面。
Q8: 什么是 WebGLRenderer 的 antialias (抗锯齿)?
- 开启后,WebGL 会尝试使用 MSAA (多重采样抗锯齿) 处理边缘锯齿。
- 注意:在高 DPI (Retina) 屏幕上,通常不需要开启,或者配合
setPixelRatio使用,否则性能开销大。
Q9: 如何处理窗口大小调整 (Resize)?
- 更新相机的
aspect(长宽比)。 - 调用
camera.updateProjectionMatrix()。 - 调用
renderer.setSize(width, height)。 - 调用
renderer.setPixelRatio(window.devicePixelRatio)。
Q10: Group 和 Object3D 有什么区别?
- 功能上几乎完全相同。
Group语义更明确,表示“一组物体”。Object3D是基类,所有可变换物体都继承自它。
Q11: 什么是 Clock 对象?为什么要用它?
- 用于跟踪时间。
getDelta():获取上一帧到当前帧的时间间隔 (秒)。- 用途:保证动画速度与帧率无关(Frame Rate Independence),移动距离 = 速度 * delta。
Q12: Three.js 坐标系是左手还是右手?
- 右手坐标系。
- X轴向右,Y轴向上,Z轴指向屏幕外(观察者)。
Q13: 如何获取物体的世界坐标?
object.getWorldPosition(targetVector3)。- 或者手动更新矩阵后从
matrixWorld中提取。
Q14: 什么是 Layers (图层)?
- 用于控制相机只渲染特定层的物体,或者光照只影响特定层的物体。
object.layers.set(1),camera.layers.enable(1)。
Q15: 什么是 Fog (雾)?有哪些类型?
- Fog:线性雾,随距离线性变浓。参数:color, near, far。
- FogExp2:指数雾,随距离指数变浓,更真实。参数:color, density。
Q16: 如何克隆 (Clone) 和 复制 (Copy) 一个物体?
clone():创建新对象(浅拷贝,几何体和材质通常共享引用)。copy(source):将 source 的属性值复制给当前对象。
Q17: 什么是 UserData?
object.userData:一个空对象{},专门留给开发者存储自定义数据,不会被 Three.js 内部逻辑修改。
Q18: 解释 dispose() 的作用。
- Three.js 创建的 WebGL 资源(Buffer, Texture, Shader)不会自动释放。
- 必须手动调用
geometry.dispose(),material.dispose(),texture.dispose()来释放 GPU 内存,防止内存泄漏。
Q19: 什么是 Color Space (色彩空间)?Linear vs sRGB?
- Linear:线性空间,适合物理计算(光照混合)。
- sRGB:显示器显示的非线性空间。
- 流程:纹理通常是 sRGB -> 解码为 Linear 进行渲染计算 -> 编码回 sRGB 输出到屏幕。
- Three.js 默认使用
THREE.SRGBColorSpace。
Q20: 什么是 ShadowMaterial?
- 一种透明材质,只接收阴影。
- 用途:AR 应用中,将虚拟物体的阴影投射到真实世界的视频流背景上。
第二部分:数学与算法 (Q21-Q30)
Q21: Vector3 的 dot() 和 cross() 分别代表什么?
- dot (点乘):结果是标量。
a·b = |a||b|cosθ。用于计算夹角、投影、判断前后方向。 - cross (叉乘):结果是向量。垂直于 a 和 b 构成的平面。用于计算法线、左右方向。
Q22: 矩阵 (Matrix4) 在 3D 中的作用?
- 存储变换信息(平移、旋转、缩放)。
- ModelMatrix:局部 -> 世界。
- ViewMatrix:世界 -> 相机空间。
- ProjectionMatrix:相机空间 -> 裁剪空间 (NDC)。
Q23: 欧拉角 (Euler) 的万向节死锁 (Gimbal Lock) 是什么?
- 使用 X/Y/Z 轴旋转时,当中间轴旋转 90 度,会导致另外两个轴重合,失去一个旋转自由度。
- 解决:使用四元数 (Quaternion)。
Q24: 四元数 (Quaternion) 的优势?
- 避免万向节死锁。
- 插值 (Slerp) 平滑。
- 计算效率比矩阵高。
Q25: 什么是 Raycaster (射线检测)?原理是什么?
- 原理:从相机位置穿过屏幕点击点发射一条射线。
- 检测:计算射线与场景中包围球/包围盒/三角形的交点。
- 用途:鼠标拾取、点击事件。
Q26: 什么是 Frustum Culling (视锥体剔除)?
- 判断物体的包围体(Bounding Sphere/Box)是否在相机视锥体内。
- 如果在外面,则完全不提交给 GPU 绘制。
Q27: 包围盒 Box3 和 Sphere 的区别?
- Sphere (包围球):计算快,检测快,但不够紧凑。
- Box3 (AABB 轴对齐包围盒):比球更紧凑,但旋转后需要重新计算(因为它始终轴对齐)。
- OBB (有向包围盒):随物体旋转,最紧凑,但计算最复杂。
Q28: 什么是 NDC (标准化设备坐标)?
- 坐标范围
[-1, 1]的立方体空间。 - Vertex Shader 的最终输出
gl_Position就是 NDC 坐标。
Q29: lookAt() 方法是如何工作的?
- 构建一个旋转矩阵,使物体的 Z 轴(负方向)指向目标点,Y 轴指向上方。
- 常用于相机跟随、炮塔瞄准。
Q30: 什么是 MVP 矩阵?
- M (Model) * V (View) * P (Projection)。
- 顶点坐标变换流程:Local -> World -> Camera -> Clip Space。
第三部分:纹理与材质进阶 (Q31-Q45)
Q31: 纹理过滤 Nearest vs Linear?
- Nearest:最近邻,像素化风格(Minecraft)。
- Linear:线性插值,平滑模糊。
Q32: 什么是 Mipmap?
- 生成一系列分辨率递减的纹理图。
- 作用:解决远处物体纹理闪烁(摩尔纹)问题,提高缓存命中率。
- 要求:纹理尺寸最好是 2 的幂次方 (POT)。
Q33: 各向异性过滤 (Anisotropy) 是什么?
- 解决以倾斜角度观察纹理时变模糊的问题(如地面延伸到远处)。
texture.anisotropy = renderer.capabilities.getMaxAnisotropy()。
Q34: UV 映射是什么?
- 将 2D 纹理坐标 (0~1) 映射到 3D 模型的顶点上。
geometry.attributes.uv。
Q35: 法线贴图 (Normal Map) vs 凹凸贴图 (Bump Map)?
- Bump Map:灰度图,只模拟高度扰动,效果较假。
- Normal Map:RGB 图,直接改变表面法线方向,光影细节更真实,性能消耗极低。
Q36: 置换贴图 (Displacement Map) 的特点?
- 真正改变顶点的几何位置。
- 需要网格有足够多的顶点(细分),否则效果呈锯齿状。
Q37: 环境贴图 (Environment Map) 有哪几种形式?
- CubeTexture:6 张图组成的立方体盒子。
- Equirectangular:一张全景图 (HDR/EXR),球形展开。
Q38: 什么是 Alpha Map?
- 灰度图,控制材质的透明度(白色不透,黑色全透)。
- 需要开启
transparent = true。
Q39: 纹理压缩格式 KTX2 / DDS 的优势?
- 显存优化:GPU 可以直接读取压缩格式,无需解压,大幅降低显存占用。
- 带宽优化:文件体积小,加载快。
Q40: 什么是 DataTexture?
- 直接用 JavaScript 的 TypedArray 数据创建纹理。
- 用途:GPGPU 计算(存位置/速度)、程序化生成纹理。
Q41: 什么是 DepthMaterial (深度材质)?
- 将片元到相机的距离渲染为灰度颜色。
- 用途:阴影贴图生成、景深效果、SSAO。
Q42: 什么是 Side 属性 (FrontSide, BackSide, DoubleSide)?
- 决定渲染三角形的哪一面。
- BackSide:常用于天空盒(从内部看球体)。
- DoubleSide:性能开销加倍,尽量少用。
Q43: 什么是 Blending (混合模式)?
- 控制新像素颜色如何与背景颜色混合。
- NormalBlending:正常遮挡/透明。
- AdditiveBlending:加法混合(发光效果,粒子)。
- SubtractiveBlending:减法混合。
Q44: 什么是 Premultiplied Alpha?
- 颜色值预先乘上了 Alpha 值。
- 可以避免混合时的黑边问题。
Q45: HDR (高动态范围) 纹理的优势?
- 存储超过 0~1 范围的亮度值。
- 提供真实的光照信息,用于 IBL (基于图像的照明)。
第四部分:光照与阴影 (Q46-Q55)
Q46: AmbientLight, HemisphereLight, DirectionalLight 的区别?
- Ambient:均匀照亮所有物体,无方向,无阴影。
- Hemisphere:模拟天空和地面反光,有上下两个颜色渐变。
- Directional:平行光(太阳),有方向,产生平行阴影。
Q47: PointLight, SpotLight, RectAreaLight 的区别?
- Point:点光源(灯泡),向四周发散。
- Spot:聚光灯(手电筒),有锥形范围。
- RectArea:面光源(窗户、灯管),光照更柔和真实,消耗高。
Q48: Three.js 阴影的实现原理?
- Shadow Map:从光源视角渲染深度图,再在主渲染流程中对比深度。
Q49: 常见的阴影类型 (Basic, PCF, PCFSoft, VSM)?
- Basic:像素化严重,性能最高。
- PCF:边缘模糊处理,默认选择。
- PCFSoft:更柔和。
- VSM:方差阴影,解决漏光,适合模糊阴影。
Q50: 什么是 Shadow Acne (阴影痤疮) 和 Peter Panning (悬浮)?
- Acne:由于精度问题,物体表面产生了自我遮挡的条纹。解决:增加
bias。 - Peter Panning:
bias太大导致阴影与物体分离。解决:调整bias和normalBias。
Q51: 什么是 Light Probe (光照探针)?
- 预计算空间中某一点的光照信息(球谐函数 SH)。
- 用于替代昂贵的实时光照,照亮动态物体。
Q52: 什么是 Physically Correct Lights (物理正确光照)?
- 使用物理单位(如流明、坎德拉)计算光照强度。
- 光照随距离平方衰减。
renderer.useLegacyLights = false(新版默认)。
Q53: 什么是 IBL (Image Based Lighting)?
- 使用环境贴图(HDR)作为光源照亮物体。
- PBR 渲染的核心,提供真实的反射和漫反射环境光。
Q54: 阴影贴图的分辨率 (mapSize) 影响什么?
- 分辨率越高,阴影越清晰,但显存占用和计算开销越大。
- 通常设为 1024, 2048, 4096。
Q55: 如何优化阴影性能?
- 减少投射阴影的光源数量。
- 使用
Bake(烘焙) 将静态阴影烧录到纹理中。 - 限制 Shadow Camera 的视锥体范围 (
camera.left/right/top/bottom),使其紧贴场景。
第五部分:PBR 与渲染原理 (Q56-Q65)
Q56: PBR 的两个核心工作流?
- Metalness/Roughness (Three.js 标准):金属度、粗糙度。
- Specular/Glossiness:高光颜色、光泽度。
Q57: 什么是 Tone Mapping (色调映射)?
- 将 HDR (高动态范围) 的颜色压缩到显示器能显示的 LDR (0~1) 范围。
- Reinhard:简单压制。
- ACESFilmic:电影级效果,对比度高,色彩鲜艳(推荐)。
Q58: 什么是 Gamma Correction (伽马校正)?
- 人眼对亮度的感知是非线性的。
- 渲染计算在线性空间,输出时需要进行 Gamma 校正 (Power 1/2.2) 以匹配显示器。
Q59: 什么是 Z-Fighting (深度冲突)?
- 两个面距离太近,深度值精度不足,导致闪烁。
- 解决:增加距离、使用
logarithmicDepthBuffer、调整相机near/far范围。
Q60: 什么是 Stencil Buffer (模板缓冲区)?
- 用于遮罩、剖切、轮廓描边。
- 控制像素是否被写入颜色缓冲区。
Q61: 什么是 Draw Call?为什么它影响性能?
- CPU 通知 GPU 绘制一次网格的命令。
- 每次 Draw Call 都有 CPU 准备数据的开销。Draw Call 太多会导致 CPU 瓶颈。
Q62: 什么是 Render Order (渲染顺序)?
- 不透明物体:从近到远渲染(利用深度测试减少像素重绘)。
- 透明物体:从远到近渲染(保证混合正确)。
- 可手动设置
renderOrder。
Q63: 什么是 MSAA, FXAA, SMAA?
- MSAA:硬件多重采样,质量好,显存高(WebGLRenderer 默认)。
- FXAA:后处理快速近似抗锯齿,有些模糊。
- SMAA:后处理子像素形态抗锯齿,质量高,开销中等。
Q64: 什么是 AO (Ambient Occlusion)?
- 环境光遮蔽。模拟角落、缝隙处光线难以到达产生的阴影,增加立体感。
Q65: 什么是 Deferred Rendering (延迟渲染)?Three.js 支持吗?
- 先渲染几何信息(位置、法线、颜色)到 G-Buffer,再统一计算光照。支持大量光源。
- Three.js 默认是 Forward Rendering (前向渲染)。延迟渲染需要通过
WebGPURenderer或自定义 Shader 实现。
第六部分:Shader 与 WebGL (Q66-Q80)
Q66: Vertex Shader 和 Fragment Shader 的区别?
- Vertex:处理顶点,计算位置 (
gl_Position)。 - Fragment:处理像素(片元),计算颜色 (
gl_FragColor)。
Q67: Uniform, Attribute, Varying 的区别?
- Uniform:全局变量,对所有顶点/片元相同(如时间、光照位置)。
- Attribute:顶点独有数据(如位置、UV、法线),只在 Vertex Shader 可用。
- Varying:从 Vertex 传递给 Fragment 的插值数据。
Q68: ShaderMaterial 和 RawShaderMaterial 的区别?
- ShaderMaterial:包含 Three.js 内置的 uniforms 和 attributes,支持
#include。 - RawShaderMaterial:纯净环境,不包含任何内置变量,需手动声明。
Q69: 什么是 onBeforeCompile?
- 在 Three.js 编译内置材质 Shader 之前,拦截并修改 Shader 代码。
- 用于在标准材质上微调效果(如添加噪点、顶点波浪),而无需重写整个 Shader。
Q70: 常用 GLSL 函数有哪些?
mix(): 线性插值。step(): 阶梯函数(0 或 1)。smoothstep(): 平滑阶梯(S形曲线)。fract(): 取小数部分。
Q71: 什么是 Post-processing (后处理)?
- 在场景渲染完成后,对最终图像进行滤镜处理。
- 如:Bloom (辉光), DOF (景深), Vignette (暗角)。
Q72: EffectComposer 的工作流?
- RenderPass (场景 -> FBO) -> ShaderPass (FBO -> 处理 -> FBO) -> ... -> OutputPass (屏幕)。
- 使用 Ping-Pong 双缓冲技术。
Q73: 什么是 GPGPU?
- General-Purpose computing on GPU。
- 利用纹理存储非图像数据(如粒子位置),在 Fragment Shader 中进行物理计算。
Q74: 什么是 FBO (Frame Buffer Object)?
- 帧缓冲区对象。允许渲染到纹理,而不是屏幕。
Q75: gl_Position 的 w 分量有什么用?
- 用于透视除法。
(x/w, y/w, z/w)将坐标转换到 NDC 空间。
Q76: 什么是 Highp, Mediump, Lowp?
- GLSL 中的精度限定符。
highp(高精度,位置计算),mediump(中精度,UV/颜色),lowp(低精度)。
Q77: 如何在 Shader 中实现纹理滚动?
vUv + time * speed。
Q78: 什么是 Signed Distance Field (SDF)?
- 符号距离场。表示空间中一点到最近物体表面的距离。
- 用于字体渲染、Raymarching (光线步进) 渲染体积云/分形。
Q79: WebGL 1.0 和 2.0 的主要区别?
- WebGL 2.0 基于 OpenGL ES 3.0。
- 支持 3D Texture, MSAA Renderbuffer, Uniform Buffer Objects, 更多的纹理格式。
- Three.js 默认尝试使用 WebGL 2.0。
Q80: 什么是 Uniform Buffer Object (UBO)?
- 允许在多个 Shader 间共享同一块 Uniform 数据块(如全局光照信息),减少 CPU-GPU 传输开销。
第七部分:性能优化 (Q81-Q90)
Q81: InstancedMesh (实例化网格) 的原理?
- 一次 Draw Call 绘制多个相同的几何体。
- 通过 Attribute 存储每个实例的变换矩阵 (Matrix) 和颜色。
Q82: 什么是 Geometry Merging (合并几何体)?
- 将多个静态物体的几何体数据合并成一个大的 BufferGeometry。
- 减少 Draw Call,但失去了单独控制每个物体的能力。
Q83: 什么是 LOD (Level of Detail)?
- 根据物体距离相机的远近,动态切换高/中/低面数的模型。
- 平衡画质与性能。
Q84: 如何检测性能瓶颈?
- Stats.js:查看 FPS, MS (帧时)。
- renderer.info:查看 Draw Calls, Triangles, Textures 数量。
- Spector.js:截帧分析 WebGL 命令。
Q85: 纹理优化的策略?
- 尺寸:POT (2的幂),不要过大。
- 格式:使用 .jpg (不透明), .png (透明), .ktx2 (GPU压缩)。
- Mipmap:开启以优化显存带宽。
Q86: 什么是 OffscreenCanvas?
- 在 WebWorker 中进行渲染,避免主线程(UI线程)卡顿。
Q87: Draco 压缩是什么?
- Google 开源的几何体压缩库。
- 大幅减小 .gltf 文件体积,但需要在客户端进行解码(有少许 CPU 开销)。
Q88: 什么是 Object Pooling (对象池)?
- 预先创建一组对象(如子弹),使用时取出,用完后重置并放回,而不是销毁。
- 避免频繁 GC (垃圾回收) 造成的卡顿。
Q89: 什么时候使用 frustumCulled = false?
- 当物体在 Vertex Shader 中发生了大幅度偏移(如飘动的旗帜),导致原本的包围盒失效,被错误剔除时。
Q90: 什么是 PowerPreference?
new WebGLRenderer({ powerPreference: 'high-performance' })。- 提示浏览器使用独立显卡(双显卡电脑)。
第八部分:WebGPU、动画与工程化 (Q91-Q100)
Q91: WebGPU 的 Compute Shader 是什么?
- 一种不经过光栅化管线,直接利用 GPU 并行计算能力的着色器。
- 适合粒子系统、物理模拟、图像处理。
Q92: 什么是 Storage Buffer?
- WebGPU 中的一种缓冲区,允许 Compute Shader 读写大量结构化数据。
- 比 WebGL 的 Texture Hack 更灵活、容量更大。
Q93: Three.js 的 TSL (Three Shading Language) 是什么?
- 一种基于节点的 Shader 编写方式(JS 语法)。
- 自动编译为 WGSL (WebGPU) 或 GLSL (WebGL),实现跨后端兼容。
Q94: 骨骼动画 (SkinnedMesh) 的原理?
- 顶点绑定到骨骼 (Bone)。
- 每个顶点有
skinIndices(骨骼索引) 和skinWeights(权重)。 - 顶点位置 = 骨骼变换矩阵 * 初始位置 * 权重。
Q95: Morph Targets (变形动画) 的原理?
- 存储顶点的多个目标位置(如表情:笑、哭)。
- 在 Shader 中对基础位置和目标位置进行线性插值。
Q96: 常见的物理引擎有哪些?
- Cannon.js:纯 JS,轻量,停止维护但常用。
- Ammo.js:Bullet 引擎的 WASM 版,功能全但重。
- Rapier:Rust 编写的 WASM 引擎,性能极高,新贵。
- PhysX:NVIDIA 引擎,Web 版较少见。
Q97: 如何实现第一人称漫游 (Collision Detection)?
- 简单:Raycaster 检测脚下高度。
- 复杂:使用物理引擎的胶囊体 (Capsule) 碰撞检测。
- Octree (八叉树):优化静态场景的碰撞检测性能。
Q98: LoadingManager 的作用?
- 统一管理多个加载器 (Texture, Model)。
- 提供
onProgress,onLoad回调,用于制作全局进度条。
Q99: 如何在 Blender 中优化导出给 Three.js 的模型?
- 应用变换 (Apply Transforms)。
- 合并网格 (Join Meshes)。
- 烘焙光照贴图 (Bake Texture)。
- 使用 GLTF 格式导出,勾选压缩。
Q100: Web 3D 的未来趋势?
- WebGPU 普及,带来桌面级渲染能力。
- AI 生成 3D (TripoSR, CSM)。
- 混合渲染 (光线追踪 + 光栅化)。
- 轻量化与云渲染 结合。