索引 · Index · ▶ 在线运行案例

索引

你将学到什么

  • 索引绘制 vs 非索引绘制 的区别
  • geometry.index 如何用 4 个顶点拼出 2 个三角形
  • 同一 Geometry 可同时用于 Points、Line、Mesh

效果说明

同一组顶点数据,同时以 黄色点红色线蓝色面 三种方式渲染,展示 WebGL 不同 图元模式(points / lines / triangles)。

核心概念

非索引 vs 索引

方式 顶点数(矩形) 说明
非索引 6(每三角独立 3 顶点) 网格 案例
索引 4 顶点 + 6 索引值 顶点可复用,节省内存
// 4 个唯一顶点
const vertices = new Float32Array([
    0, 0, 0,    // 索引 0
    50, 0, 0,   // 索引 1
    50, 0, 50,  // 索引 2
    0, 0, 50,   // 索引 3
]);

// 索引表:每 3 个索引构成一个三角形
const indexes = new Uint16Array([
    0, 1, 2,   // 三角面 1
    0, 3, 2,   // 三角面 2
]);
geometry.index = new THREE.BufferAttribute(indexes, 1);
geometry.attributes.position = new THREE.BufferAttribute(vertices, 3);

同一 Geometry,三种 Object

Object Material 渲染模式
Points PointsMaterial GL_POINTS
Line LineBasicMaterial GL_LINE_STRIP 等
Mesh MeshBasicMaterial GL_TRIANGLES

实现步骤

  1. 定义 4 顶点 + 6 索引
  2. 分别创建 Points、Line、Mesh 加入 scene
  3. OrbitControls 交互

代码要点


import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

const scene = new THREE.Scene();

// 网格模型Mesh其实就一个一个三角形(面)拼接构成
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
    0, 0, 0,
    50, 0, 0,
    50, 0, 50,

    // 0, 0, 0,
    0, 0, 50,
    // 50, 0, 50,
]);

// 下面索引值对应顶点位置数据中的顶点坐标
// 第 0、1、2这三个点构成一个三角形
// 第 0、3、2这三个点构成一个三角形
const indexes = new Uint16Array([
    0, 1, 2, 0, 3, 2,
])

geometry.index = new THREE.BufferAttribute(indexes, 1);

geometry.attributes.position = new THREE.BufferAttribute(vertices, 3);


// 点渲染模式
const material2 = new THREE.PointsMaterial({
    color: 0xffff00,
    size: 10.0 //点对象像素尺寸
});
const points = new THREE.Points(geometry, material2); //点模型对象
scene.add(points);

// 线材质对象
const material1 = new THREE.LineBasicMaterial({
    color: 0xff0000 //线条颜色
});
// 创建线模型对象
const line = new THREE.Line(geometry, material1);
scene.add(line);

// 网格
const material = new THREE.MeshBasicMaterial({
    color: 0x0000ff,
    side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// AxesHelper
const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);

// 相机
const camera = new THREE.PerspectiveCamera();  //相机
camera.position.set(200, 200, 200); //相机位置
camera.lookAt(0, 0, 0);   //相机观察位置

// 渲染器
const renderer = new THREE.WebGLRenderer(); // 创建渲染器
const box = document.getElementById('box');
renderer.setSize(box.clientWidth, box.clientHeight); //渲染区域
renderer.render(scene, camera); //执行渲染
box.appendChild(renderer.domElement);;

const controls = new OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', function () {
    renderer.render(scene, camera);
});

完整源码:GitHub

小结