Let's discuss a method for constructing a plane. Using the example provided, you have three vectors that are multiples of the canonical basis i, j, k
, represented as:
x = x_0 * [1 0 0]
y = y_0 * [0 1 0]
z = z_0 * [0 0 1]
A plane requires two important components:
- a normal vector (perpendicular to the plane)
- a distance from the origin to the plane
The normal vector can be obtained using the cross product of two non-parallel vectors lying on the plane, such as y - x
and z - x
. This gives us:
normal = normalize(cross(y - x, z - x))
When rendering the plane, an initial normal vector N
is present. We can create a quaternion that rotates vector N
to normal
, using the axis-angle form:
q_{axis} = cross(N, normal)
q_{angle} = acos(dot(N, normal))
The distance to the plane can be determined using the dot product of the normal vector and any point on the plane, for example:
distance = dot(normal, x)
Notably, this distance value is signed, allowing easy movement of the plane in the normal direction by a distance of distance
units.
Implementation
var plane = new THREE.Mesh(
new THREE.PlaneGeometry(10, 10),
new new THREE.MeshNormalMaterial()
)
// ...
function rotatePlane(x, y, z) {
var xy = new THREE.Vector3().subVectors(y, x)
var xz = new THREE.Vector3().subVectors(z, x)
var normal = new THREE.Vector3().crossVectors(xy, xz).normalize()
// initial normal vector of the plane
var Z = new THREE.Vector3(0, 0, 1)
var axis = new THREE.Vector3().crossVectors(Z, normal).normalize()
var angle = Math.acos(Z.dot(normal))
var q = new THREE.Quaternion().setFromAxisAngle(axis, angle)
plane.rotation.setFromQuaternion(q)
var distanceToPlane = x.dot(normal)
plane.position.copy(normal.clone().multiplyScalar(distanceToPlane))
}
Update 1: To simplify the quaternion calculation, you can use
plane.quaternion.setFromUnitVectors( Z, normal )
. This optimization avoids trigonometric functions, as explained in this insightful article.
Update 2: It's noted that the direction of the normal vector is crucial. In the implementation, both faces of the plane are rendered to address this. If the plane needs to consistently face away from the origin, make sure to adjust the direction of the normal
and the distance
to be positive:
if (distance < 0) {
distance *= -1
normal.multiplyScalar(-1)
}