threejs系列之:物体详解🐧

写在最前

往期回顾:

  1. # threejs系列: 相机与投影 📷
  2. # threejs系列: 光源与光照🪀
  3. # threejs系列: 自定义几何体🎃
  4. # threejs系列: 几何变换(上)🍺
  5. # threejs系列: 几何变换(下)🏄‍♂️
  6. # threejs系列: 矩阵推导🎰
  7. threejs系列: 物体详解🐧
  8. threejs系列: 材质与贴图详解🦥
  9. threejs系列: 曲线详解🥓
  10. threejs系列: 动画详解🧠
  11. .......

物体

在 threejs 中主要提供点、线、精灵、网格等类给开发者快速的构建物体,接下来我们快速过一下这些内容。

Object3D

再讲物体之前,我们先认识物体的祖先类,也是threejs中最重要的类,为什么这么说呢?可以看看哪些东西是继承Object3D

  • Scene
  • 物体
  • Camera
  • Light
  • Audio
  • 等等.....

threejs中的北斗之尊了属于是

之前文章提到的物体几何变换的API都是它提供的,除此之外它还提供了很多强大的功能,如:

  1. 控制物体是否可见
js 复制代码
mesh.visible = false;
  1. 阴影相关
js 复制代码
mesh.castShadow = true; // 是否在阴影贴图中
mesh.receiveShadow = true; // 是否接收阴影

阴影相关会专门写一篇内容,争取在明天发出。

3.物体是否受到摄像机视锥体设置的最大远近距离影响:

js 复制代码
mesh.frustumCulled = true; // 默认 true;
  1. 矩阵相关

物体拥有matrix属性,保存物体的矩阵信息,当物体使用Object3D提供的几何变换API时,物体会自动计算并赋值matrix值。如果想自行修改matrix属性的话,则需要将matrixAutoUpdate = 设置为false;

updateMatrix 方法重置掉自行修改的matrix,重新通过scale\rotation\position方法计算并赋值matrix属性。

除非你非常熟悉 threejs 的矩阵内部运行原理,否则请不要修改matrixAutoUpdate属性

层级

我们知道一个物体由多个部件构成的, 部件又可能由多个小部件组成。threejs也是如此,物体可以直接通过.add方法添加子级,如:

js 复制代码
let mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0xFFFFFF }))
scene.add(mesh);

let mesh2 = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0xFFFFFF }))
mesh.add(mesh2);

console.log(mesh.children)

可通过children查看子级。

如果你希望父级是一个没有具体意义的对象,就像在 Vue 中的 template。

则可以通过 Group 类来添加,如:

js 复制代码
let mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0xFFFFFF }));
let group = new THREE.Group();
group.add(mesh);

console.log(group.children)

本地矩阵与世界矩阵

有了层级后,几何变换也变得不太一样了,当父级放大2倍,子级也会放大两倍。

csharp 复制代码
group.scale.set(2, 2, 2)

我们来看一下子级的矩阵信息 matrix

奇怪怎么还是单位矩阵并没有发生改变?因为这只是本地矩阵,只保存自己的变换信息,发生改变的是世界矩阵matrixWorld。

js 复制代码
console.log(mesh.matrixWord);

可以看到世界矩阵发生了改变。

本地矩阵

本地矩阵包含了对象的旋转、平移和缩放变换,本地矩阵的乘积表示了对象在本地坐标系中的变换。

世界矩阵

世界矩阵是对象本地矩阵和其所有祖宗对象本地矩阵的乘积,它表示了对象在世界坐标系中的变换。

世界坐标与本地坐标

对象的本地坐标是相对于其父对象的坐标,对象的世界坐标是相对于世界坐标原点的坐标。

获取对象的世界坐标

可以通过对象的 getWorldPosition() 方法来获取对象的世界坐标。

节点查找

随着层级越来越复杂,查找物体就变得困难了,正如 Dom 一样, Object3D 提供了 getObjectByIdgetObjectByName 等诸多方法用于查询。

也提供了 uuid 进行标识,也提供了 userData 用于存储自定义信息,还有 name 进行命名区分。

你可以使用 traverse 方法进行遍历,如需不展示的内容不进行遍历的话,threejs也封装了 traverseVisible 让你使用。

所以在 threejs 中,查找物体非常容易。

Mesh 网格

网格是什么?

在 3D 计算机图形和实体建模中,网格是定义多面体对象形状的顶点、边和面的集合,由网格创建的对象需要包含顶点(Vertex)、边(edge)、面(faces)、多边形(polygons)和曲面(sufaces)元素信息。

创建

在前面的文章中,我们多次使用到了Mesh类,Mesh是常用的网格,不管是在创建一个简单的正方体还是复杂的圆环缓冲都得用它创建。

js 复制代码
   new THREE.Mesh(BufferGeometry, Material);

需要传入几何体和材质的实例,几何体在前面的文章中有详细的讲解,而材质(Material)是描述物体外观和光学特性的属性集合,它包括物体的颜色、反射属性(如漫反射、高光反射)、透明度、折射率等。几何体更像是前端的HTML,而材质像是CSS,他们组合从而构成一个完美的物体。

InstancedMesh 实例化网格

每次 three.js 将一个物体交给 WebGL 进行渲染,就称为一次 draw call。

draw call 是指向图形渲染管线提交一次绘制请求的操作,减少draw call次数可以有效的提高渲染效率。

对于多个具有相同材质的 mesh,可以只创建一个材质实例,然后将其应用于所有 mesh,这样可以减少 draw call 的数量,这就是 InstancedMesh 实例化网格的由来。

当你需要渲染大量的相同的网格时,使用InstancedMesh是最好的选择,例如《我的世界》游戏中有大量相同的石块,这时候你就需要用到这个了。

我们来创建 800 * 800 个的Mesh

js 复制代码
const row = 800;
const col = 800;

let group = new THREE.Group();

for (let i = 0; i < row; i++) {
    for (let j = 0; j < col; j++) {
        let mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0xFFFFFF }));
        mesh.position.set(i, j, 0);
        group.add(mesh)
    }
}

scene.add(group)

因为加载物体太多的缘故,此时我的浏览器已经无响应重启了,就如前端的长列表一样。

再看看用 InstancedMesh,InstancedMesh设置变换需要用它自己独特的方法,设置颜色需要用setColorAt,设置变换需要用 setMatrixAt

js 复制代码
const row = 800;
const col = 800;

let mesh = new THREE.InstancedMesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0xFFFFFF }), row * col);
let index = 0;

for (let i = 0; i < row; i++) {
    for (let j = 0; j < col; j++) {
        index++;
        let matrix = new THREE.Matrix4();
        matrix.setPosition(i - row / 2, j - col / 2, 0);
        mesh.setColorAt(index, new THREE.Color(index / (row * col), 0, 0))
        mesh.setMatrixAt(index, matrix);
    }
}

scene.add(mesh)

此时会发现虽然fps虽然有一点点下降,但是还是能够使用的,并且基本上不会有同时出现160000的业务场景。

InstanceMesh算是 threejs 性能优化方案的其中一种。

Points 与 Line

Points 通常搭配 PointMaterial 点材质使用, Line 通常搭配 LineBasicMaterial(实线) 或 LineDashMaterial(虚线)使用,用法非常简单就不在这里细讲了,过!

相关推荐
新缸中之脑5 分钟前
Llama 3.2 安卓手机安装教程
前端·人工智能·算法
hmz8568 分钟前
最新网课搜题答案查询小程序源码/题库多接口微信小程序源码+自带流量主
前端·微信小程序·小程序
看到请催我学习14 分钟前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript
blaizeer43 分钟前
深入理解 CSS 浮动(Float):详尽指南
前端·css
速盾cdn1 小时前
速盾:网页游戏部署高防服务器有什么优势?
服务器·前端·web安全
小白求学11 小时前
CSS浮动
前端·css·css3
什么鬼昵称1 小时前
Pikachu-csrf-CSRF(POST)
前端·csrf
XiaoYu20022 小时前
22.JS高级-ES6之Symbol类型与Set、Map数据结构
前端·javascript·代码规范
golitter.2 小时前
Vue组件库Element-ui
前端·vue.js·ui
golitter.2 小时前
Ajax和axios简单用法
前端·ajax·okhttp