网格 · Grid · ▶ 在线运行案例

网格

你将学到什么

  • WebGL 只画三角形 — Mesh 由三角面拼接
  • 手写 BufferGeometry + Float32Array 定义顶点
  • MeshBasicMaterialside: DoubleSide 双面渲染

效果说明

X-Z 平面上出现一个 蓝色三角形(实为两个三角形组成的矩形,本案例只定义一个三角面)。配合 OrbitControls 可旋转观察。

核心概念

GPU 渲染的基本图元是 三角形。一个矩形需要 2 个三角形 = 6 个顶点(无索引时)或 4 个顶点 + 索引。

顶点布局(Y=0 平面):

  (0,0,50) ---- (50,0,50)
     |    ╲       |
     |      ╲     |
  (0,0,0) ---- (50,0,0)

三角面1: (0,0,0) → (50,0,0) → (50,0,50)
三角面2: (0,0,0) → (0,0,50)  → (50,0,50)

本案例 只写 6 个顶点(2 个三角形) 构成完整矩形:

const vertices = new Float32Array([
    0, 0, 0,   50, 0, 0,   50, 0, 50,   // 三角面 1
    0, 0, 0,   0, 0, 50,   50, 0, 50,   // 三角面 2
]);
geometry.attributes.position = new THREE.BufferAttribute(vertices, 3);
//                                                      itemSize=3 (x,y,z)

背面剔除: 默认只渲染正面(法线朝向相机的一侧)。side: THREE.DoubleSide 双面可见,适合平面/薄片。

实现步骤

  1. new THREE.BufferGeometry()
  2. Float32Array 填入 6 顶点 × 3 分量
  3. BufferAttribute(vertices, 3) 绑定到 attributes.position
  4. MeshBasicMaterial + DoubleSide → Mesh

代码要点


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,
]);

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

// 网格
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

小结