4.1.自定义几何体

以下以网格模型讲解的,网格模型本质上是由N个三角形拼接而成的图形。我们设置三个坐标点(顶点) 就可以确定一个三角形,多个三角形如果设置得当,就可以组成各种形状的面或者立体图形。多个坐标逆时针围成的是正面。

// 创建一个BufferGeometry几何体实例
const geometry = new THREE.BufferGeometry()

// 三个一组,为一个顶点坐标(图形是由N个三角形组成)
const vertices = new Float32Array([
                 -100, -100, 100,
         100, -100, 100,
         100, 100, 100,
        
         100, 100, 100,
         -100, 100, 100,
         -100, -100, 100
]);

// 设置几何体的钉钉位置
// 3 表示3个值为一组
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

整点的代码:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=100">
   <title>Document</title>
</head>

<body>
   <script type="importmap">
       {
                   "imports": {
                   "three": "./three.module.min.js",
                   "three/addons/": "./jsm/"
               }
       }
   </script>
   <script type="module">
       import * as THREE from 'three';
       import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
       // 创建场景
       const scene = new THREE.Scene();

       // 创建一个BufferGeometry几何体实例
       const geometry = new THREE.BufferGeometry()
       // 三个一组,为一个顶点坐标(图形是由N个三角形组成)
       const vertices = new Float32Array([
           -100.0, -100, 100,
           100, -100, 100,
           100, 100, 100,

           100, 100, 100,
           -100, 100, 100,
           -100, -100, 100
       ]);

       // 设置几何体的钉钉位置
       geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

       // 创建一个基础网格材质(双面可见)
       const material = new THREE.MeshBasicMaterial({ color: 'orange', side: THREE.DoubleSide });
       const cube = new THREE.Mesh(geometry, material);
       // 将物体加到场景中
       scene.add(cube);

       // 创建 三维坐标轴
       const axesHelper = new THREE.AxesHelper(200);
       scene.add(axesHelper);

       // 创建相机
       let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
       camera.position.set(300, 300, 300)
       camera.lookAt(0, 0, 0)

       const renderer = new THREE.WebGLRenderer();
       renderer.setSize(window.innerWidth, window.innerHeight);
       // 执行渲染
       renderer.render(scene, camera);
       document.body.appendChild(renderer.domElement);

       // 创建轨道控制器对象
       const controls = new OrbitControls(camera, renderer.domElement)
       controls.addEventListener('change', function () {
           // 重新执行渲染操作
           renderer.render(scene, camera);
       });
   </script>
</body>
</html>

顶点索引

我们前面设置定点坐标的时候,用的值是这样的:

const vertices = new Float32Array([
 -100, -100, 100, // 第0组
 100, -100, 100, // 第1组
 100, 100, 100, // 第2组
 100, 100, 100, // 第3组
 -100, 100, 100, // 第4组
 -100, -100, 100 // 第5组
]);

这里面的坐标点数据有些是重复的,比如:第0组和第5组重复,第2组和第3组重复。如果我们将重复的点删除,可以吗?就像这样:

const vertices = new Float32Array([
 -100, -100, 100, // 第0组
 100, -100, 100, // 第1组
 100, 100, 100, // 第2组
 -100, 100, 100, // 第3组
]);

其实是可以的,不过这样删除后,还需要设置定点分组,才能获得同样的效果

const indexes = new Uint16Array([0, 1, 2, 2, 3, 0])
geometry.setIndex(new THREE.BufferAttribute(indexes, 1));

完整的代码

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=100">
   <title>Document</title>
</head>
<body>
   <script type="importmap">
       {
           "imports": {
               "three": "./three.module.min.js",
               "three/addons/": "./jsm/"
           }
       }
   </script>
   <script type="module">
       import * as THREE from 'three';
       import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
       // 创建场景
       const scene = new THREE.Scene();

       // 创建一个BufferGeometry几何体实例
       const geometry = new THREE.BufferGeometry()

       // 三个一组,为一个顶点坐标(图形是由N个三角形组成)
       const vertices = new Float32Array([
           -100, -100, 100, // 第0组
           100, -100, 100, // 第1组
           100, 100, 100, // 第2组
           -100, 100, 100, // 第3组
       ]);

       // 设置几何体的顶点位置
       geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
       // 创建定点索引
       const indexes = new Uint16Array([0, 1, 2, 2, 3, 0])
       // 设置索引属性
       geometry.setIndex(new THREE.BufferAttribute(indexes, 1));


       // 创建一个基础网格材质(双面可见)
       const material = new THREE.MeshBasicMaterial({ color: 'orange', side: THREE.DoubleSide });
       const cube = new THREE.Mesh(geometry, material);
       // 将物体加到场景中
       scene.add(cube);


       // 创建 三维坐标轴
       const axesHelper = new THREE.AxesHelper(200);
       scene.add(axesHelper);

       // 创建相机
       let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
       camera.position.set(300, 300, 300)
       camera.lookAt(0, 0, 0)

       const renderer = new THREE.WebGLRenderer();
       renderer.setSize(window.innerWidth, window.innerHeight);
       // 执行渲染
       renderer.render(scene, camera);
       document.body.appendChild(renderer.domElement);

       // 创建轨道控制器对象
       const controls = new OrbitControls(camera, renderer.domElement)
       controls.addEventListener('change', function () {
           // 重新执行渲染操作
           renderer.render(scene, camera);
       })

   </script>
</body>
</html>


本节参考文章:

https://threejs.org/docs/?q=Geometry#api/zh/core/BufferGeometry

https://juejin.cn/post/7231080269501956155

微信 遇到疑问可加微信进行反映