I'm trying my best to describe it:
I've got a 3D sloped surface, and I wanna know the height(Z) it is at any given point inside of it. I have the surface's vertices' 3D positions, and the point's 2D position. How to know what should be the height it would collide with while at the surface?
I'm using GDScript, making a 3D/2.5D Doom-like engine in Godot's 2D engine. Flat floors and walls work perfectly, but slopes? I've tried everything I could think of for months and nothing worked.
This is what you would do:
We define a line that is vertical and passes through your 2D point.
Let us say our 2D point is
position
. Then:A point on the line is
position
augmented with0
on the height component. I'll call itv0
:And the direction of the line is vertical, so zero on both 2D components, and
1
on the height component. I'll call itdir
:We define a plane by the three points that make up your 3D triangle.
Let us say our 3D points are
v1
,v2
andv3
.By definition they are all on the plane.
We can find the normal of the plane using cross product, like this:
For this use case we don't care if we got the normal flipped.
Ah, but it will be convenient to ensure it is of unit length:
We find the interception of the line and the plane. That is our solution.
We want to find a point on the plane, I'll call it
r
. That is a point such that the vector that goes from one of the points on the plane to it is perpendicular to the normal of the plane. Meaning that(r - v1).dot(normal) == 0
.Please notice that I'm using
==
, which is the equality comparison operator. I'm using that because it is an equation, not an assigment.The point
r
must also belong to the line. We can use the parametric form of the line, which is like this:r = v0 + dir * t
. And we will have to first find what parametert
must be, so we can computer
.So we replace
r
here:Which gives us this:
Rearrange:
By distributive property of the dot product:
Since
t
is an scalar we can take it out of the dot product:Subtract
(v0 - v1).dot(normal)
on both sides:We can move that negative sign inside the dot product:
And divide both sides by
dir.dot(normal)
:Thus, our point
r
is:Then you can read the height component of
r
, which is your answer.By the way Godot has a method that is almost this. But it intersects a ray, not a line:
intersect_ray
of thePlane
class.