Here is a nice strategy that utilizes the vector slerp function for the interpolated plane normal and any point on the common line of the two planes.
Start with the definition of each plane, having normal vectors n_1 = (nx_1,ny_1,nz_1)
, n_2 = (nx_2,ny_2,nz_2)
and distance from origin (measured in the direction of the normal) as d_1
and d_2
.
The common line of the two planes is along the (non-unit) direction e = cross(n_1, n_2)
. The point on this line closest to the origin is given by the calculation
point = (d_2*cross(n_1,e)-d_1*cross(n_2,e))/dot(e,e)
Notation is in pseudo-code with elements from most common languages
Keep this to the side for now, and focus on interpolating the normals. I you use a n = slerp(n_1, n_2, t)
function it will interpolate along the minimum arc and have equal spacings
vector slerp(vector n_1, vector n_2, float t)
// Assume n_1, n_2 are unit vectors
// Result is always a unit vector
float g = dot(n_1, n_2)
float angle = acos(g)
float f = sin(angle)
return (sin((1-t)*angle)/f)*n_1 + (sin(t*angle)/f)*n_2
end
So now we can define the interpolated plane using the normal n = slerp(n_1, n_2, t)
and the distance d = dot(n, point)
from the projection of the common point to along the new normal.
The algorithm below extends the slerp
function to work with planes also:
plane slerp(plane p_1, plane p_2, float t)
// extract properties from plane
vector n_1 = p_1.normal, n_2 = p_2.normal
float d_1 = p_1.distance, d_2 = p_2.distance
// interpolate
vector e = cross(n_1, n_2))
vector n = slerp(n_1, n_2, t)
vector r = (d_2*cross(n_1,e)-d_1*cross(n_2,e))/dot(e,e)
// construct new plane from normal and distance
return plane(n, dot(r, n))
end
Some helper functions as expected:
float dot(vector a, vector b)
return a.x*b.x + a.y*b.y + a.z*b.z
end
float hypot(vector a)
return sqrt(dot(a,a))
end
vector cross(vector a, vector b)
return vector( a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x)
end
vector operator * (float f, vector a)
return vector(f*a.x, f*a.y, f*a.z)
end
vector operator + (vector a, vector b)
return vector(a.x+b.x, a.y+b.y, a.z+b.z)
end