文章目录
- 一、核心概念
- 二、对象与材质
- 三、动画与交互
- 四、性能优化
- 五、高级渲染
- 六、加载与资源
- 七、工程实践
- 八、特效实现
- 九、调试与问题
- 十、综合应用
一、核心概念
-
Three.js三大核心组件及作用
解析:- 场景(Scene):容器,存放所有3D对象
- 相机(Camera):视角定义(常用透视相机
PerspectiveCamera
) - 渲染器(Renderer):将场景渲染到Canvas画布
口诀:场景装对象,相机定视角,渲染出画面
-
描述坐标系系统
解析:右手坐标系(X右/Y上/Z屏幕外)。使用AxesHelper
可视化坐标轴。 -
几何体(Geometry) vs 缓冲几何体(BufferGeometry)区别
解析:Geometry
:易用但性能低(适合简单模型)BufferGeometry
:直接操作顶点数据,节省内存(生产环境必用)
二、对象与材质
-
创建带纹理的立方体
解析:const texture = new THREE.TextureLoader().load('brick.jpg') const material = new THREE.MeshBasicMaterial({ map: texture }) const cube = new THREE.Mesh(new THREE.BoxGeometry(), material)
-
MeshStandardMaterial 和 MeshBasicMaterial 区别
解析:BasicMaterial
:基础材质,无视灯光StandardMaterial
:PBR材质,支持金属度/粗糙度(需光源)
-
如何让物体产生阴影?
解析:- 渲染器开启阴影:
renderer.shadowMap.enabled = true
- 光源投射阴影:
light.castShadow = true
- 物体接收阴影:
mesh.castShadow = true; mesh.receiveShadow = true
- 渲染器开启阴影:
三、动画与交互
-
实现物体旋转动画
解析:在渲染循环中更新:function animate() {requestAnimationFrame(animate)cube.rotation.x += 0.01renderer.render(scene, camera) }
-
射线检测(Raycasting)原理
解析:从鼠标点击位置发出一条射线,检测与物体的交点:const raycaster = new THREE.Raycaster() const mouse = new THREE.Vector2() raycaster.setFromCamera(mouse, camera) const intersects = raycaster.intersectObjects(scene.children)
-
如何实现第一人称控制器?
解析:使用PointerLockControls
+ 键盘事件监听位移。
四、性能优化
-
如何降低Draw Call?
解析:- 合并几何体:
BufferGeometryUtils.mergeBufferGeometries()
- 使用实例化网格:
THREE.InstancedMesh
(渲染相同物体) - 减少材质种类
- 合并几何体:
-
LOD(Level of Detail)应用场景
解析:根据物体距离切换不同精度模型:const lod = new THREE.LOD() lod.addLevel(lowModel, 50) // 距离>50时显示低模 lod.addLevel(highModel, 0) // 距离<50时显示高模
-
内存泄露常见原因
解析:- 未销毁纹理:
texture.dispose()
- 未移除事件监听
- 未释放几何体:
geometry.dispose()
- 未销毁纹理:
五、高级渲染
-
后期处理(Post-Processing)流程
解析:- 创建效果组合器:
new EffectComposer(renderer)
- 添加渲染通道:
composer.addPass(renderPass)
- 添加效果:
composer.addPass(new BloomPass())
- 创建效果组合器:
-
着色器(Shader)编写步骤
解析:const material = new THREE.ShaderMaterial({vertexShader: `void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,fragmentShader: `void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }` })
-
如何实现环境光遮蔽(AO)?
解析:- 使用
THREE.AmbientOcclusionPass
- 或模型烘焙AO贴图
- 使用
六、加载与资源
-
GLTF加载流程
解析:import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' new GLTFLoader().load('model.glb', (gltf) => {scene.add(gltf.scene) })
-
如何显示加载进度?
解析:监听进度事件:loader.load('model.glb', onLoad, (xhr) => {console.log((xhr.loaded / xhr.total * 100) + '% loaded') })
-
Draco压缩模型加载
解析:设置DRACOLoader:const dracoLoader = new DRACOLoader() dracoLoader.setDecoderPath('/draco/') gltfLoader.setDRACOLoader(dracoLoader)
七、工程实践
-
如何适配不同屏幕尺寸?
解析:window.addEventListener('resize', () => {camera.aspect = window.innerWidth / window.innerHeightcamera.updateProjectionMatrix()renderer.setSize(window.innerWidth, window.innerHeight) })
-
与React/Vue集成方案
解析:- React:使用
react-three-fiber
- Vue:
vue-threejs
组件封装Canvas
- React:使用
-
Web Worker在Three.js中的应用
解析:将复杂计算(如地形生成)移入Worker线程。
八、特效实现
-
如何制作粒子效果?
解析:const particles = new THREE.Points(new THREE.BufferGeometry().setAttribute('position', new Float32Array(positions)),new THREE.PointsMaterial({ size: 0.1 }) )
-
实现水面反射
解析:- 创建反射平面:
new THREE.Reflector()
- 或用Shader模拟波纹
- 创建反射平面:
-
模型蒙皮动画原理
解析:骨骼(Skeleton)驱动顶点权重(SkinWeight),通过AnimationMixer
播放动画剪辑。
九、调试与问题
-
性能分析工具
解析:- Chrome DevTools Performance面板
- Three.js自带状态:
renderer.info
(统计Draw Call/内存) stats.js
库显示FPS
-
模型闪烁(Z-fighting)解决方案
解析:- 增加深度偏移:
material.polygonOffset = true
- 调整相机近剪裁平面:
camera.near = 0.1
- 提高深度缓冲区精度
- 增加深度偏移:
-
移动端卡顿优化
解析:- 降低分辨率:
renderer.setPixelRatio(0.75)
- 简化场景(减少三角形数量)
- 禁用阴影/后期效果
- 降低分辨率:
十、综合应用
-
设计一个3D楼盘展示系统(开放题)
解析:- 核心:Three.js + 户型图加载器
- 功能:
- 第一人称漫游(
PointerLockControls
) - 热点标注(射线检测)
- 光照切换(白天/夜晚模式)
- 第一人称漫游(
- 优化:模型LOD + 图片懒加载
-
如何实现VR支持?
解析:
使用WebXR
API:renderer.xr.enabled = true document.body.appendChild(VRButton.createButton(renderer))
-
Three.js与Blender工作流整合
解析:- Blender建模 → 导出GLTF
- Three.js加载模型 + 添加交互
- 自定义Shader增强材质
面试考察重点:
- 基础:三大组件、坐标系、动画循环
- 核心:BufferGeometry优势、材质类型、阴影实现
- 性能:Draw Call优化、内存管理、LOD策略
- 深度:着色器编写、后处理链、蒙皮动画原理
- 工程:框架集成、移动端适配、模型加载
附:高频问题避坑指南
- ✘ 用
Geometry
处理复杂模型 → ✓ 生产环境必须用BufferGeometry
- ✘ 忘记销毁资源 → ✓ 页面关闭时调用
dispose()
- ✘ 直接修改顶点数据 → ✓ 修改后执行
geometry.attributes.position.needsUpdate = true
- ✘ 忽视帧率控制 → ✓ 复杂场景使用
renderer.setAnimationLoop()
替代requestAnimationFrame
重点理解 “性能优化手段” 和 “WebGL底层原理”,大厂尤其关注千万级顶点场景的处理能力!