Three.js 提供了 Plane 概念来表示在 3d 空间中无限延伸的二维表面。 这对于光标交互很有用,因此你可能需要了解如何设置此平面、将其可视化并根据需要进行调整。
推荐:使用 NSDT场景设计器 快速搭建 3D场景。
Three.js 的 Plane 文档很好而且准确,但它肯定假设你是一个“数学人”(我不是),并且如果你从未听说过四元数之类的东西,它不会解释如何让事情正常进行 和平面法线。 我不得不通过老式的艰难方式学习这些东西,所以我为像我这样刚接触 3d 图形的其他开发人员整理了本指南。
首先,最好直观地感受一下什么是平面:你将如何在 3d 空间中表示平面? 我想您可以使用 3 个点定义任何平面,创建一个沿其表面无限延伸的三角形。 三角形的大小无关紧要:只要斜率相同,平面仍然相同。 这是一个 Blender 场景来帮助可视化:
因此,将平面表示为三个点的集合绝对可行,但也许有更好的方法来表示这种结构。 有一个概念叫做表面法线,它是一个垂直于表面的矢量(即指向某个方向的箭头)。 这是维基百科的一张图片,显示了一个带有两个法向量的表面(一个向量由三个参数组成:x、y 和 z):
这是曲面法线的图示:
你可以想象每个法线都有一个平面,如下所示:
这是 three.js 的 Plane 定义的方式,在其构造函数中清晰可见:
Plane( normal : Vector3, constant : Float )
normal - (optional) a unit length Vector3 defining the normal of the
plane. Default is (1, 0, 0).
constant - (optional) the signed distance from the origin to the
plane. Default is 0.
所以要设置一个面朝上的平面,你可以这样做:
var myPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
法向量指向上方,因为 y 有一个值,它根本没有被拉向 x 或 z 方向。 事实上,如果将法向量设置为 (0, 2, 0) 或 (0, 200, 0),你会得到完全相同的平面,因为法向量重要的是它的方向,而不是它的大小。 常量值 0 表示该平面的中心恰好位于场景的中心点。
顺便说一下,默认情况下这个平面在你的 three.js 场景中是不可见的。 要查看它,请将 PlaneHelper 连接到它。 这可能会让人感到困惑,但如果你的目标是实际绘制此表面供用户查看,那么你将使用 PlaneGeometry,它继承了 Object3D 的所有基本方法。 我在本文中讨论的 Plane 类只是一个数学平面,但你需要使用这种平面才能使用 Ray.intersectPlane(),这就是你在three.js中将鼠标事件连接到一个平面的方式。
所以,现在你知道如何初始化平面并移动它了。 如果你需要旋转这个东西怎么办? 好吧,你总是可以只更改平面法向量中的参数,对吗? 不过,这实际上是一种非常困难的平面工作方式。 如果你需要将此平面的旋转与场景中已有的可见对象的旋转相匹配,或者只是应用诸如 45 度旋转偏移之类的东西,那么乱用法向量可能会令人沮丧。 我将介绍一些使用一些工具旋转该平面的基本模式。
你将需要学习如何使用四元数。 它们看起来真的很复杂,但你只需要知道它们是一组定义 three.js 对象当前旋转状态的坐标,每个 Object3D 都有一个。 你可以使用 three.js 的 API 将更改应用于四元数并修改它们以执行需要执行的操作。
// There's an object in the scene - myObject - and
// I want to take its rotation and make my plane
// have the same rotation.
var rotation = myObject.quaternion.clone();
// The default forward vector for 3D objects is (0, 0, 1),
// so first set the normal to match myObject like that,
// and then make the plane's rotation match myObject as well.
myPlane.normal.set(0, 0, 1).applyQuaternion(rotation);
在将四元数应用于平面之前,还可以根据需要对其进行任何更改。 假设你需要在此旋转上进行 90 度偏移:
var offset = new THREE.Quaternion();
offset.setFromAxisAngle(
// This rotation offset is along the X axis,
// so use a vector where X is 1 here.
new THREE.Vector3(1, 0, 0),
// Offset by -90 degrees (in radians)
-Math.PI / 2);
// Modify the rotation
rotation.multiply(offset);
// The 'rotation' quaternion is now ready to be applied to the plane
我知道,对于一些简单的旋转来说,这似乎是很多繁琐的事情。 只需将其视为工具包中的另一种模式即可。 其实three.js的Plane API中加入一些简单的旋转机制已经讨论过了。 你不能像 Object3D 一样旋转 Plane 的原因背后的数学原理有点超出我的理解,但听起来好像是因为 Plane 没有“局部坐标系”。
所以这篇文章有点密集。 但我希望它对进入 three.js 这个领域的任何人都有帮助。 这也可以看作是抽象的证明:确实可以让 3D 图形满足你的需求,而无需理解其背后的所有数学原理,并且你会逐渐感受到使用矢量和各种坐标系。
原文链接:Three.js无限平面 — BimAnt