Skip to content

法线

法线是一个向量,它垂直于一个表面,这个“表面”可以是一个三角形平面、一个多边形的面,或者是曲面上的某一点点击下载案例

js
import "./style.scss";

import { BoxGeometry, ConeGeometry, MeshMatcapMaterial, MeshNormalMaterial, Mesh, Raycaster, Vector2, Vector3 } from "three";
import { scene, camera, renderer, controls } from "./base.js";

function animate() {
  renderer.render(scene, camera);
  controls.update();
}
renderer.setAnimationLoop(animate);

const geometry = new BoxGeometry(1, 1, 1);
const material = new MeshMatcapMaterial({ color: 0xffffff });
const box = new Mesh(geometry, material);
scene.add(box);

const normalHelperGeom = new ConeGeometry(0.05, 1);
normalHelperGeom.translate(0, 0, 0);
normalHelperGeom.rotateX(Math.PI * 0.5);

const normalHelper = new Mesh(normalHelperGeom, new MeshNormalMaterial());
normalHelper.visible = false;
scene.add(normalHelper);

const raycaster = new Raycaster();
const mouse = new Vector2();
const poi = new Vector3();
const n = new Vector3();
const la = new Vector3();
let intersects = [];

function onMouseMove(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);
  intersects = raycaster.intersectObject(box);

  if (intersects.length > 0) {
    let i0 = intersects[0];
    // 获取相交的3D对象
    let obj = i0.object;
    // 将相交点的世界坐标位置复制到poi变量中 i0.point是射线与物体相交点的三维坐标
    poi.copy(i0.point);
    // 复制相交面的法向量到变量n中 i0.face.normal是该面的局部坐标系下的法向量
    n.copy(i0.face.normal);
    // 将法向量从物体的局部坐标系转换到世界坐标系 transformDirection方法会应用物体的旋转和缩放,但不包括位移
    n.transformDirection(obj.matrixWorld);
    // 计算法向量的终点位置:从相交点poi出发,沿着法向量方向延伸 la现在表示法向量箭头末端的世界坐标位置
    la.copy(poi).add(n);
    // 将法向量辅助对象(通常是一个ArrowHelper)移动到相交点位置
    normalHelper.position.copy(poi);
    // 让法向量辅助对象朝向法向量方向 这样箭头就会正确指向面的法线方向
    normalHelper.lookAt(la);
    normalHelper.visible = true;
  } else {
    normalHelper.visible = false;
  }
}

canvas.addEventListener("mousemove", onMouseMove, false);

应用场景

在 3D 编辑器中点击物体表面时,显示该面的法线方向,帮助用户理解面的朝向和进行相关的编辑操作。