Tuesday, April 21, 2015

Intersection of two non-parallel planes

Plane intersections can solve a number of camera framing optimization problems and is an easy way to for example find the rays along the corners of the view frustum given the screen edge planes.

Any line that lies on a plane is perpendicular to its normal, so the only line that is shared between both is perpendicular to both normals, or the cross product of the normals:

D = n1n2

If the planes are parallel the cross product will be zero since there will be no intersection. This is a rare case when dealing with camera space but worth keeping in mind.

Two parallel planes will not intersect and two non-parallel planes will intersect in a line.

If any point of the line is already known, for example the intersection of any two camera frustum planes will intersect with the camera position, this is all that is needed.

If no point along the intersection is known there are a few more steps.

The intersection will be a line L = P + t D which is perpendicular to the normals in both planes since it is aligned with both. We already have D so to find a point on that line P we can use:

P = ((d1n2 - d2n1) ✕ D) / DD

To explain this, the point P can be found by substituting it in the plane equation:

n1P = d1
n2P = d2

P is some offset from origo along both normals:

P = k1n1+k2n2


n1 ᐧ (k1n1 + k2n2) = d1
n2 ᐧ (k1n1 + k2n2) = d2

vector dot (scalar * vector) = scalar * (vector dot vector):

k1(n1n1) + k2(n1n2) = d1
k1(n1n2) + k2(n2n2) = d2

Solving this by substitutions results in:

k1 = (d2(n1n2) - d1(n2n2)) / ((n1n2)2-(n1n1)(n2n2))
k2 = (d1(n1n2) - d2(n1n1)) / ((n1n2)2-(n1n1)(n2n2))

Not so short but at least the denominator is the same for both values. Let’s start with rewriting the denominator with cosine representation:

denominator = (n1n2)2-(n1n1)(n2n2)
denominator = (||n1|| ||n2|| cos(α))2 - ||n1||2 ||n2||2
denominator = ||n1||2 ||n2||2 cos2(α) - ||n1||2 ||n2||2
denominator = ||n1||2 ||n2||2 (cos2(α) - 1)

We can substitute cos2(α) + sin2(α) = 1:

denominator = -||n1||2 ||n2||2 sin2(α) = -(||n1|| ||n2|| sin(α))2

||n1|| ||n2|| sin(α) = ||n1n2|| = ||D||

denominator = -||D||2
denominator = -DD

k1 = (d2(n1n2) - d1(n2n2)) / -DD
k2 = (d1(n1n2) - d2(n1n1)) / -DD

k1 = (d1(n2n2) - d2(n1n2)) / DD
k2 = (d2(n1n1) - d1(n1n2)) / DD

P = k1n1+k2n2
P = ((d1(n2n2) - d2(n1n2))n1+(d2(n1n1) - d1(n1n2))n2) / DD

Still not short, but the numerator is close to a vector triple product:

v1 ✕ (v2v3) = v2 (v1v3) - v3 (v1v2)

P = ((d1n2 - d2n1) ᐧ n2) n1 + (d2n1 - d1n2) ᐧ n2) n2) / DD
P = ((d1n2 - d2n1) ᐧ n2) n1 - (d1n2 - d2n1) ᐧ n2) n2) / DD
P = (n1 (d1n2 - d2n1) ᐧ n2) - n2 (d1n2 - d2n1) ᐧ n2)) / DD
P = ((d1n2 - d2n1) ✕ (n1n2)) / DD

And substituting the second cross product with D yields:

P = ((d1n2 - d2n1) ✕ D) / DD

For more cross product and dot product properties check out this wikipedia entry. I am sure this can be solved in fewer steps, but it is what it is.

No comments:

Post a Comment