主题
法线
法线是一个向量,它垂直于一个表面,这个“表面”可以是一个三角形平面、一个多边形的面,或者是曲面上的某一点点击下载案例
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 编辑器中点击物体表面时,显示该面的法线方向,帮助用户理解面的朝向和进行相关的编辑操作。