three - 基本知识

32 阅读3分钟

基本构成

Three.js 是用来创建和渲染三维世界的。

image.png

网格对象 = 几何体 + 材质
mesh = geometry + material

辅助工具

OrbitControls: 支持通过鼠标拖动来 360 度观察 3D 场景。
GUI: 可视化调试参数

视椎体理解

const camera2 = new THREE.PerspectiveCamera(20, 16 / 9, 100, 300);

第一个参数是角度,第二个参数是宽高比,第三个是近裁截面的距离,第四个参数是远裁截面的距离。

image.png

几何体理解

所有几何体都是一堆顶点数据,构成一堆三角形,三角形构成了任何几何体。

点模型、线模型、网格模型

正反面

从相机看过去的方向,如果一个三角形是逆时针连接的顶点,就是正面,顺时针就是反面。

默认是正面可见,如果你想双面可见,可以在材质里设置下:

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坐标

image.png

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');