threejs基础 - 几何体

前言

在上篇文章《lil-gui调试开发3D效果》中,给立方体材质开启线框模式,可以发现立方体的每个面都是由 2 个三角平面构成。

three.js 中最基础的面单位是就是 1 个三角形。创建一个物体需要确定该物体的几何形状和材质,本篇文章来介绍 Three.js 的几何体相关基础知识。

顶点创建平面

Three.js 提供了一个几何形状的基类API,BufferGeometry,官方文档查看这里

三角平面

js 复制代码
const plane_geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0]);
plane_geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const plane_material = new THREE.MeshBasicMaterial({
  color: "#2fa295",
});
const plane = new THREE.Mesh(plane_geometry, plane_material);
scene.add(plane);

以上代码中,通过设置顶点的方式创建一个三角平面。新建一个基础几何形状plane_geometry,设置它的position顶点坐标位置,通过BufferAttribute确定使用上面设置的Float32Array坐标数组,每 3 个确定为一个坐标。

页面效果如下:

以上创建的三角形平面的坐标顺序是逆时针,那如果换成顺时针呢?

只需要修改vertices

ini 复制代码
const vertices = new Float32Array([-1, -1, 0, 1, 1, 0, 1, -1, 0]);

页面效果如下:

正面视角看不见三角平面,当反转视角时才能看到。这说明了 Three.js 中平面是分正反的,当逆时针创建是正面,顺时针创建是反面。

正方形平面

1 个正方形平面是由 2 个三角形平面组成。

js 复制代码
const plane_geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -1, -1, 0, 1, -1, 0, 1, 1, 0, 1, 1, 0, -1, 1, 0, -1, -1, 0,
]);
plane_geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const plane_material = new THREE.MeshBasicMaterial({
  color: "#2fa295",
  wireframe: true,
});
const plane = new THREE.Mesh(plane_geometry, plane_material);
scene.add(plane);

页面效果如下:

这里需要注意,存在一个问题。在控制台输出plane,可以看出当前平面的顶点个数count是 6,这和我们认知的一个正方形平面 4 个顶点不符。这是因为 2 个三角形的顶点(-1,-1,0)(1,1,0)没有共用。

这就需要采用索引方式创建,复用可共用的顶点坐标。

索引创建平面

js 复制代码
const plane_geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0]);
plane_geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
plane_geometry.setIndex(new THREE.BufferAttribute(indices, 1));
const plane_material = new THREE.MeshBasicMaterial({
  color: "#2fa295",
  wireframe: true,
});
const plane = new THREE.Mesh(plane_geometry, plane_material);
scene.add(plane);

以上代码中,仍然是创建一个顶点数组,数组中每 3 个为一组设置几何体的坐标位置,通过Uint16Array创建索引数组,其中[0,1,2]第 0 个索引位置的坐标位置(-1,-1,0),第 1 个索引位置的坐标位置(1,-1,0),第 2 个索引位置的坐标位置(1,1,0),这 3 个坐标位置创建 1 个三角平面。以此类推,[2,3,0]创建第 2 个三角平面。

页面效果如下:

再次打印plane,控制台输出结果如下:当前平面的顶点个数count是 4

多材质

根据顶点创建平面,1 个基础平面是三角形平面,1 个正方形平面需要 2 个三角形平面组成,那一个正方体 6 个平面是需要 12 个三角形平面组成,每个平面都是可以设置不同的材质。

举个栗子,设置 1 个正方形平面中 2 种不同材质的三角形平面。

js 复制代码
const plane_geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0]);
plane_geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
plane_geometry.setIndex(new THREE.BufferAttribute(indices, 1));
plane_geometry.addGroup(0, 3, 0);
plane_geometry.addGroup(3, 3, 1);
const plane_material = new THREE.MeshBasicMaterial({
  color: "#FF0000",
});
const plane_material1 = new THREE.MeshBasicMaterial({
  color: "#0000FF",
});
const plane = new THREE.Mesh(plane_geometry, [plane_material, plane_material1]);
scene.add(plane);

以上代码中,通过addGroup方法设置不同顶点分组的采用不同的材质,该方法的具体使用说明参见官方文档。第 1 个参数是索引数组的开始下标,第 2 个参数是几个顶点,第 3 个参数是采用第几个材质,因此addGroup(0, 3, 0)表示从索引数组[0, 1, 2, 2, 3, 0]下标 0 的位置开始,选择 3 个顶点坐标作为一组使用第 0 个材质plane_material

页面效果如下:

再举个栗子,正方体 6 个平面颜色不同。

js 复制代码
const geometry = new THREE.BoxGeometry(1, 1, 1);
function rainbowMaterial(colors) {
  let _arr = [];
  colors.forEach((color) => {
    _arr.push(new THREE.MeshBasicMaterial({ color }));
  });
  return _arr;
}
const cube = new THREE.Mesh(
  geometry,
  rainbowMaterial([
    "#FF0000",
    "#FF7F00",
    "#FFFF00",
    "#00FF00",
    "#00FFFF",
    "#0000FF",
    "#8B00FF",
  ])
);

页面效果如下:

常见几何体

以上通过顶点创建平面,而 1 个物体是由多个面组成的,使用的是BufferGeometry这个 API 显得特别麻烦,好在 Three.js 已经封装了不同的几何体 API 供用户使用,不同几何体的具体的使用查看官方文档

例如,创建一个平面。

js 复制代码
const geometry = new THREE.PlaneGeometry( 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0xffff00});
const plane = new THREE.Mesh( geometry, material );
scene.add( plane );

单从代码量上可以看出,Three.js 提供的这些封装的几何体API,更加方便。

在官方文档中,选择你需要使用的几何体,可以直接在示例中通过 GUI 调试,对于开发更关注它提供的构造函数选项。例如:

最后

注:本文首发微信公众号【前端一起学】,里面有持续更新的Vue源码实战专栏,Electron实战,Three.js入门教程等,还有更多前端基础知识超详细总结,欢迎关注。

相关推荐
蜗牛快跑21311 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy12 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
前端郭德纲2 小时前
浏览器是加载ES6模块的?
javascript·算法
JerryXZR2 小时前
JavaScript核心编程 - 原型链 作用域 与 执行上下文
开发语言·javascript·原型模式