# Ray and square/rectangle intersection in 3D

## Question:

Hei. Are making a game and are looking for a ray intersection onto a square or a rectangle only in 3D space. Have search the web and found many solutions but nothing i can understand have a line and line segment intersection script in 2D but i cant figure out have to make it 3D.
It is not important from what side it intersect the square or rectangle but it must be able to retrive the point of intersection vector so that later can be tested for distance to se if it occurred before or after other intersections on the same ray intersection.

Any examples in python or other similar scripting languages will be greatly appreciated

Edit: Dont know have to modify the 2D to show an exaple but made a new and posting both.

``````//this is the exaple it test a ray onto a plane then look to se if that point is in the rectangle and saves it to test for distanse later
list Faces; //triangle faces
list Points; //

vector FindPoint(){
//calcute the point of intersection onto the plane and returns it
//if it can intersect
//else return ZERO_VECTOR
}

//return 1 if the point is in the rectangular on the plane
//else return 0
}

default{

state_entry(){
integer n = (Faces != []); //return number of elements
integer x = 0;
while(x < n){
vector intersection = FindPoint( FromList(Faces, x) ); //take     out a element and runs it trough the function
if(intersection != ZERO_VECTOR){
integer test = point-in-quadrilateral( FromList(Faces,     x) ); //find out if the point is in rectangular
if(test == 1){ //if so
Points += intersection; //save the point
}
}
++x;
}

float first; //the distanse to the box intersection
integer l = (Points != []);
integer d;
while(d < l){
if(Dist( FromList(Points, d) ) < first) //if the new distanse     is less then first
return 0; //then end script
++d;
}
}

}

//this is the 2D version
vector lineIntersection(vector one, vector two, vector three, vector four){
float bx = two.x - one.x;
float by = two.y - one.y;
float dx = four.x - three.x;
float dy = four.y - three.y;
float b_dot_d_perp = bx*dy - by*dx;
if(b_dot_d_perp == 0.0) {
return ZERO_VECTOR;
}
float cx = three.x-one.x;
float cy = three.y-one.y;
float t = (cx*dy - cy*dx) / b_dot_d_perp;
if(LineSeg){ //if true tests for line segment
if((t < 0.0) || (t > 1.0)){
return ZERO_VECTOR;
}
float u = (cx * by - cy * bx) / b_dot_d_perp;
if((u < 0.0) || (u > 1.0)) {
return ZERO_VECTOR;
}
}

return <one.x+t*bx, one.y+t*by, 0.0>;
``````

}

You don’t say whether the square/rectangle in 3D is aligned with the coordinate axes or not.
Assuming the 3D rectangle R is oriented arbitrarily in space, here is one method.
First interesect your ray r with the plane containing R. This can be accomplished by requiring a
scale factor s to multiply r and place it on the plane of R, and solving for s. This gives you a point p on the plane. Now project the plane, and R and p, on to one of the coordinate
planes {xy, yz, zx}. You only have to avoid projecting perpendicular to the normal vector to the plane, which is always possible. And then solve the point-in-quadrilateral problem in the plane of projection.

Before beginning, check if your line segment lies in the 3D plane of R, and if so, handle that separately.

Create a vector equation for a line in R3, then solve for the intersection of that line in the plane of the rectangle that you are testing it against. After that, it’s simple enough to test if that point of solution lies within the bounds.

the parameter t of the solution can be found with:

``````t = (a * (x0 - rx) + b * (y0 - ry) + c * (x0 - rz)) / (a * vx + b * vy + c * vz)
``````

where:

``````a(x - x0) + b(y - y0) + c(z - z0) = 0
``````

is the equation of the plane that your rectangle lies on

and:

``````<x, y, z> = <rx + vx * t, ry + vy * t, rz + vz * t>
``````

is the vector equation of the line in question.

note that:

``````<rx, ry, rz>
``````

is the initial point of the vector equation, and

``````<vx, vy, vz>
``````

is the direction vector of the above equation

After that, plugging the parameter t into your vector equation will give you the point to test for distance.

The solution is very easy when you define a ray with a point(= vector) and a direction vector, and the rectangle with a point(= vector) and two vectors representing the sides.

Suppose the ray is defined as `R0 + t * D`, where `R0` is the origin of the ray, `D` is an unit vector representing its direction and `t` is its length.

The rectangle can be represented with a corner point `P0`, and two vectors `S1` and `S2` which should represent the sides (their length being equal to the length of the sides). You will need another vector `N` normal to its surface, which is equal to the unit vector along the cross product of `S1` and `S2`.

Now, assume the ray intersects the rect at `P`. Then, the direction of the ray, `D` must make a nonzero angle with the normal `N`. This can be verified by checking `D.N < 0`.

To find the intersection point, assume `P = R0 + a * D` (the point must be on the ray). You need to find the value of `a` now. Find the vector `P0P`. This must be perpendicular to `N`, which means `P0P.N = 0` which reduces to `a = ((P0 - R0).N) / (D.N)`.

Now you need to check if the point is inside the rect or not. To do this, take projection `Q1` of `P0P` along `S1` and `Q2` of `P0P` along `S2`. The condition for the point being inside is then `0 <= length(Q1) <= length(S1)` and `0 <= length(Q2) <= length(S2)`.

This method is appropriate for any type of parallelograms, not only for rectangles. [Update: it looks like this statement about parallelograms created some confusions. In case of parallelograms (which also includes rectangles), the projection on one side should be taken along the other side, not just as a perpendicular line on it (quoting from the last paragraph: "take projection `Q1` of `P0P` along `S1` and `Q2` of `P0P` along `S2`"). It is like working with a coordinate system where the axes are not perpendicular to each other.]

Categories: questions
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.