Let’s imagine that you have a line which is defined by two points: l1, l2 and a plane which is defined by three points: p1, p2 and p3.
And for some reason you need to find an intersection between this line and a plane.
Let’s define our variables:
local fold = workspace.LineToPlane
local p1, p2, p3 = fold.p1.Position, fold.p2.Position, fold.p3.Position
local l1, l2 = fold.l1.Position, fold.l2.Position
Now we need to get normal of a plane because it is used in equation of a plane.
To get a normal of a plane you need to find cross product of two vectors which lie in a plane and are not parallel.
Let’s choose vectors p1p2 and p1p3 for this purpose:
local v12,v13 = p2 - p1, p3 - p1
local normal = v12:Cross(v13)
Here is an equation of the plane: ax+by+cz+d=0 (where a, b and c are coordinates of it’s normal vector)
Let’s replace a, b and c with known variables
normal.X*x + normal.Y*y + normal.Z*z + d = 0
Now d is unknown but we can find it by inserting coordinates of a point on a plane into the equation. (replace x, y and z with coordinates of a point)
normal.X*p1.X + normal.Y*p1.Y + normal.Z*p1.Z + d = 0
Let’s solve for d and find it!
local d = -(normal.X*p1.X + normal.Y*p1.Y + normal.Z*p1.Z)
Now we need to get three parametric equations of the line in 3d space.
Position vector of a point on the line (r) can be described as an equation:
r = p + tm
Where p is a position vector of a point on the line, m is direction vector for the line.
And t is a scalar. (For different points on the line t will be different.)
The vector equation of a line in 3d-space is
r = (Xp, Yp, Zp) + t(Xm, Ym, Zm), where p = (Xp, Yp, Zp) is a
position vector of a point on the line, m = (Xm, Ym, Zm) is a
direction vector for the line, and t ∈ R.
We can imagine coordinates of a point on the line as three variables: x, y and z because they are unknown and describe line in 3d space by using three equations for each coordinate:
x = Xp + t*Xm
y = Yp + t*Ym
z = Yp + t*Zm
Let’s put known values into the equations.
(We know coordinate of a point on the line and we can get direction vector for the line with the help of l1 and l2)
local lv = l2 - l1
-- x = l1.X + t*lv.X
-- y = l1.Y + t*lv.Y
-- z = l1.Z + t*lv.Z
Note that the t here is unknown.
So far we have this:
local fold = workspace.LineToPlane
local p1,p2,p3 = fold.p1.Position, fold.p2.Position, fold.p3.Position
local l1,l2 = fold.l1.Position,fold.l2.Position
local v12,v13 = p2 - p1, p3 - p1
local normal = v12:Cross(v13)
local lv = l2 - l1
local d = -(normal.X*p1.X + normal.Y*p1.Y + normal.Z*p1.Z)
Now we have equation of the plane and equations of x, y and z.
That allows us to replace x, y and z in the equation of a plane with our new equations.
Updated equation of a plane:
a*(l1.X + lv.X*t) + b(l1.Y + lv.Y*t) + c*(l1.Z + lv.Z*t) + d = 0
Now we need to solve for t because all of the other values are known to us.
a*(l1.X + lv.X*t) + b(l1.Y + lv.Y*t) + c*(l1.Z + lv.Z*t) + d = 0
a*l1.X + a*lv.X*t + b*l1.Y + b*lv.Y*t + c*l1.Z + c*lv.Z*t + d = 0 -- open the brackets
a*lv.X*t + b*lv.Y*t + c*lv.Z*t + d + a*l1.X + b*l1.Y + c*l1.Z = 0 -- put things with t at the start
t*(a*lv.X + b*lv.Y + c*lv.Z) + d + a*l1.X + b*l1.Y + c*l1.Z = 0
t*(a*lv.X + b*lv.Y + c*lv.Z) = -(d + a*l1.X + b*l1.Y + c*l1.Z) -- dividing everything by (a*lv.X + b*lv.Y + c*lv.Z)
t = -(d + a*l1.X + b*l1.Y + c*l1.Z)/(a*lv.X + b*lv.Y + c*lv.Z)
local t = -(d + normal.X*l1.X + normal.Y*l1.Y + normal.Z*l1.Z)/(normal.X*lv.X + normal.Y*lv.Y + normal.Z*lv.Z)
-- Let's insert our new value t into the parametric equations of the line!
local x_int = l1.X + lv.X*t
local y_int = l1.Y + lv.Y*t
local z_int = l1.Z + lv.Z*t
local intersection = Vector3.new(x_int,y_int,z_int)
local part = fold.INT
part.Position = intersection
Now we need to check two things:
- Check if line and the plane are parallel.
- Check if line lies within the plane.
For the first case we won’t be able to find an intersection of a line and a plane.
For the second case line will intersect plane in infinite amount of points.
To check these two cases we need to find dot product of a line direction vector and a normal of the plane.
If dot product of two vectors is equal to zero then it means that these two vectors are orthogonal hence line will be parallel to the plane or line will lie on the plane.
Let’s consider this and wrap it all in a function.
local fold = workspace.LineToPlane
local p1, p2, p3 = fold.p1.Position, fold.p2.Position, fold.p3.Position
local l1, l2 = fold.l1.Position,fold.l2.Position
local function GetIntersection(l1, l2, p1, p2, p3)
local v12,v13 = p2 - p1, p3 - p1
local normal = v12:Cross(v13)
local lv = l2 - l1
local d = -(normal.X*p1.X + normal.Y*p1.Y + normal.Z*p1.Z)
if lv:Dot(normal) == 0 then -- line and a plane are parallel or line lies on the plane.
-- we plug into equation of the plane coordinates of any point on the line
-- let's use point l1 for this:
-- a*l1.X + b*l1.Y + c*l1.Z + d = 0
-- replace a,b and c by normal coordinates
-- normal.X*l1.X + normal.Y*l1.Y + normal.Z*l1.Z + d = 0
if (normal.X*l1.X + normal.Y*l1.Y + normal.Z*l1.Z + d) == 0 then
return nil -- line lies on the plane.
else
return nil -- line is parallel to the plane.
end
end
local t = -(d + normal.X*l1.X + normal.Y*l1.Y + normal.Z*l1.Z)/(normal.X*lv.X + normal.Y*lv.Y + normal.Z*lv.Z)
local x_int = l1.X + lv.X*t
local y_int = l1.Y + lv.Y*t
local z_int = l1.Z + lv.Z*t
local intersection_point = Vector3.new(x_int,y_int,z_int)
return intersection_point
end
local part = fold.INT
part.Position = GetIntersection(l1, l2, p1, p2, p3)
Great! Everything works as we expected.
As you can see our script returned error because our function returned nil.
And that’s it.
I hope it helped someone.




