基本构成
Three.js 是用来创建和渲染三维世界的。
网格对象 = 几何体 + 材质
mesh = geometry + material
辅助工具
OrbitControls: 支持通过鼠标拖动来 360 度观察 3D 场景。
GUI: 可视化调试参数
视椎体理解
const camera2 = new THREE.PerspectiveCamera(20, 16 / 9, 100, 300);
第一个参数是角度,第二个参数是宽高比,第三个是近裁截面的距离,第四个参数是远裁截面的距离。
几何体理解
所有几何体都是一堆顶点数据,构成一堆三角形,三角形构成了任何几何体。
点模型、线模型、网格模型
正反面
从相机看过去的方向,如果一个三角形是逆时针连接的顶点,就是正面,顺时针就是反面。
默认是正面可见,如果你想双面可见,可以在材质里设置下:
const material = new THREE.MeshBasicMaterial({
color: new THREE.Color('orange'),
side: THREE.DoubleSide // 双面可见
});
分段
几何体还支持分段,也就是分成几段再细分三角形,分段越多顶点和三角形越多,渲染越精细,但性能也会变差,所以要设置一个适中的值,一般保持默认就行。
贴图
const loader = new THREE.TextureLoader();
const texture = loader.load('./zhuan.jpg');
const geometry = new THREE.PlaneGeometry(1000, 1000);
const material = new THREE.MeshBasicMaterial({ map: texture });
uv坐标
贴图图片对应的对标系:而每个顶点对应的图片渲染位置就是模型的uv坐标
uv 动画
纹理对象 Texture 有个 offset 属性,可以让纹理贴图在 x、y 方向做一些偏移。 这相当于改变了 uv 坐标,所以这种改变 texture.offset 的动画叫做 uv 动画。
// render方法中修改offset
mesh.material.map.offset.y += 0.01;
// 材质设置成贴图重复,就可以实现无限滚动
texture.wrapT = THREE.RepeatWrapping;
曲线
曲线API: threejs.org/docs/index.…
- 椭圆曲线 EllipseCurve:画椭圆、圆曲线
- 样式曲线 SplineCurve:画经过一些点的曲线
- 二次贝塞尔曲线 QuadraticBezierCurve:可以通过控制点调节曲率,有一个控制点
- 三次贝塞尔曲线 CubicBezierCurve3:可以画三维曲线,通过控制点调节曲率,有两个控制点
- 直线 LineCurve:直线是曲线的一种特殊情况,传入两个端点
- 曲线路径 CurvePath:可以传入多条曲线,组合起来
构建几何体
- 几何体是由一堆顶点构成的三角形构成的,但直接写顶点数据太麻烦,Three.js 提供了一些 API 可以按照一些规律来生成几何体。
- LatheGeometry 可以由曲线绕 y 轴旋转生成几何体
- TubeGeometry 可以由曲线生成一定半径的空心管道
- ShapeGeometry 可以通过 Shape 来生成多边形,Shape 可以传入一堆点构成,也可以通过 lineTo、moveTo 等 api 来画。shape.holes 可以定义内孔。
- ExtrudeGeometry 可以通过 Shape 拉伸形成几何体。
- 按照这些规律,可以生成很多有用的几何体。
隧道穿梭
- 用三维样条曲线画了穿过 n 个点的三维曲线,然后用 TubeGeometry 生成管道。
- 给它设置纹理贴图,调整颜色空间,设置 map、aoMap 之后,真实感就很强了。
- 通过改变 camera 的 position 和 lookAt 实现了镜头穿梭隧道的感觉。
- 相机的位置是通过 curve.getSpacedPoints 取的一堆均匀的点。
深度冲突
const renderer = new THREE.WebGLRenderer({
logarithmicDepthBuffer: true
});
世界坐标和局部坐标
添加到 Group 之后,它的绝对坐标是 group 的 position 加上它的 position,这个叫做世界坐标。 而它在 Group 内部的 position 叫做局部坐标。
获取世界坐标
mesh.getWorldPosition(pos);
console.log(pos); // 世界坐标
console.log(group.position);
console.log(mesh.position); // 局部坐标
遍历所有对象
scene.traverse((obj) => {
console.log(obj);
});
查找mesh
const cube = scene.getObjectByName('cube');
cube.material.color = new THREE.Color('lightgreen');