How to determine if a point is above or below a plane defined by a triangle
up vote
1
down vote
favorite
I'm doing some 3D graphics stuff and in order to add some simple lighting, the program needs to determine whether or not a point is below a triangle. (For now just the plane defined by the triangle. I'll tackle the point-in-triangle problem later.) Y is up. Thanks!
triangle 3d
add a comment |
up vote
1
down vote
favorite
I'm doing some 3D graphics stuff and in order to add some simple lighting, the program needs to determine whether or not a point is below a triangle. (For now just the plane defined by the triangle. I'll tackle the point-in-triangle problem later.) Y is up. Thanks!
triangle 3d
How do you define “up” relative to the triangle? What do you have to work with (just the vertices or do you have a precomputed normal)?
– amd
Nov 14 at 23:03
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I'm doing some 3D graphics stuff and in order to add some simple lighting, the program needs to determine whether or not a point is below a triangle. (For now just the plane defined by the triangle. I'll tackle the point-in-triangle problem later.) Y is up. Thanks!
triangle 3d
I'm doing some 3D graphics stuff and in order to add some simple lighting, the program needs to determine whether or not a point is below a triangle. (For now just the plane defined by the triangle. I'll tackle the point-in-triangle problem later.) Y is up. Thanks!
triangle 3d
triangle 3d
asked Nov 14 at 21:55
joek204
133
133
How do you define “up” relative to the triangle? What do you have to work with (just the vertices or do you have a precomputed normal)?
– amd
Nov 14 at 23:03
add a comment |
How do you define “up” relative to the triangle? What do you have to work with (just the vertices or do you have a precomputed normal)?
– amd
Nov 14 at 23:03
How do you define “up” relative to the triangle? What do you have to work with (just the vertices or do you have a precomputed normal)?
– amd
Nov 14 at 23:03
How do you define “up” relative to the triangle? What do you have to work with (just the vertices or do you have a precomputed normal)?
– amd
Nov 14 at 23:03
add a comment |
4 Answers
4
active
oldest
votes
up vote
0
down vote
HINT
We can proceed as follow
- find the plane containing the triangle
- find the intersection point $Q$ between the plane and the vertical line through the point $P$
- calculate $z_P-z_Q$
add a comment |
up vote
0
down vote
Suppose the triangle is $ABC$ and the point is $P$.
Calculate the vectors $B-A$, $C-A$ and $P-A$. Then the sign of the vector triple product
$$
(P-A) cdot ((B-A) times (C-A))
$$
determines which side of the plane of the triangle contains $P$.
That triple product is just a determinant, which should make the coding easy.
add a comment |
up vote
0
down vote
Write the equation of the plane of the triangle as $$z=ax+by+d$$
If your point is $p= (x_0, y_0,z_0)$ compare the $z=ax_0+by_0+d$ with $z_0$.
If $z_0 > ax_0+by_0+d$ then $p$ is above otherwise it is either below or on the plane ( in case of equality).
add a comment |
up vote
0
down vote
Although others have already answered the stated question, I'd like to give some advice to those doing similar to what OP is doing.
Precalculate the unit normal vector to the triangle, and store it.
If the triangle vertices are $vec{v}_0$, $vec{v}_1$, and $vec{v}_2$, then the triangle normal is usually defined as
$$vec{n} = bigl(vec{v}_1 - vec{v}_0bigr)timesbigl(vec{v}_2 - vec{v}_0bigr)$$
where $times$ denotes vector cross product. This is scaled to unit length,
$$hat{n} = frac{vec{n}}{leftlVertvec{n}rightrVert} = frac{vec{n}}{sqrt{vec{n} cdot vec{n}}}$$
This is best precalculated and stored, because the square root operation tends to be slow, and it is just one vector per triangle.
A point is "above" the triangle if it is in the same halfspace as the triange normal vector, with respect to the plane formed by the triangle.
(If you extend the triangle plane to infinity, it splits space into two halves. If you look at the triangle sideways, the point is "above" the triangle if it is in the same side as the normal is; and "below" if it is on the other side. If the point is on the triangle plane exactly, I recommend you use a clear and unambigous term for it; I use "exactly on the triangle" myself. I'm sure mathematicians have more precise terms, but for those of us who only use math as a tool for solving problems, making sure the terms are unambiguous suffices.)
This means that point $vec{p}$ has signed distance
$$d = bigl(vec{p} - vec{v}_0bigr) cdot hat{n}$$
from the plane of the triangle. (Because all three triangle vertices are on the plane, you can use $vec{v}_1$ or $vec{v}_2$ in above; you'll still get the exact same result, within rounding error.)
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne 1$, the distance is in units of the normal vector length.
When you know the signed distance $d$ of the point $vec{p}$ from the plane, you can trivially project the point to the plane:
$$vec{p}_text{plane} = vec{p} - d hat{n}$$
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne1$, the right side is actually $vec{p} - hat{n}(d / lVerthat{n}rVert)$, and you need a "slow" square root operation here. Because you probably test many points per each triangle, it is well worth precalculating and storing the $hat{n}$ beforehand.
To determine if $vec{p}_text{plane}$ is within the triangle, find out the barycentric coordinates $(u, v)$ corresponding to $vec{p}_text{plane}$ with respect to that triangle.
To do this, check which axes have the smallest values in magnitude in $hat{n}$. Their order does not matter. (This essentially picks the axis along which to look at the triangle, with the triangle being as large as possible. We do this to minimize numerical errors.) There are three possibilities: $x$ and $y$; $x$ and $z$; and $y$ and $z$. The solution is obtained using the coordinates on those two axes.
The solution for $vec{p}_text{plane} = (x, y, z)$ with $hat{n}$ having $x$ and $y$ components closest to zero, is
$$begin{cases}
displaystyle u = frac{ (x - x_0)(y_2 - y_0) - (y - y_0)(x_2 - x_0)}{ (x - x_2)(y_1 - y_0) - (y - y_2)(x_1 - x_0) } \
displaystyle v = frac{ (y - y_0)(x_1 - x_0) - (x - x_0)(y_1 - y_0)}{ x_0 (y_1 - y_2) + x_1 (y_2 - y_0) + x_2 (y_0 - y_1) } \
end{cases}$$
The solution for the other axis pairs you'll find just by permuting the coordinates ($y$, $y_0$, $y_1$, $y_2$ to $z$, $z_0$, $z_1$, $z_2$ for $x$ and $z$ axes; and also $x$, $x_0$, $x_1$, $x_2$ to $y$, $y_0$, $y_1$, $y_2$ for $y$ and $z$).
Also note that you'll want to calculate the divisor for $u$ first. It will be zero at $vec{v}_2$, where $u = 0$, so when the divisor is very close to zero, just use $u = 0$.
In barycentric coordinates, $vec{v}_0$ is at $(0, 0)$; $vec{v}_1$ is at $(1,0)$, and $vec{v}_2$ is at $(0,1)$. The entire triangle is $0 le u, v, u + v le 1$. The edges are at $u = 0$, $v = 0$, and $u + v = 1$.
In practice, you define the triangle inclusion test as
$$Bigl(u ge -epsilonBigr) text{ and }
Bigl(v ge -epsilonBigr) text{ and }
Bigl(u le 1+epsilonBigr) text{ and }
Bigl(v le 1+epsilonBigr) text{ and }
Bigl(u + v le 1+epsilonBigr)$$
where $epsilon$ represents the precision of your numerical coordinates. It is the largest positive number you consider equal to zero. (Similarly, if $D$ is the divisor for $u$ earlier, if $-epsilon le D le +epsilon$, use $u = 0$.)
To linearly interpolate any value $c$ within the triangle, with $c = c_0$ at $vec{v}_0$, $c_1$ at $vec{v}_1$, and $c_2$ at $vec{v}_2$, you can use
$$c(u,v) = (1 - v)bigl((1-u) c_0 + u c_1bigr) + v c_2$$
All together, this means that you need only 15 (scalar) multiplications and less than thirty additions or subtractions, to find out if a point is within the triangle, or within a triangular prism extending from the triangle along its normal, including the barycentric coordinates needed for texture or color interpolation. (Color interpolation itself is just four multiplications per component, so typically 12 additional multiplications.) Nifty, eh?
add a comment |
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
HINT
We can proceed as follow
- find the plane containing the triangle
- find the intersection point $Q$ between the plane and the vertical line through the point $P$
- calculate $z_P-z_Q$
add a comment |
up vote
0
down vote
HINT
We can proceed as follow
- find the plane containing the triangle
- find the intersection point $Q$ between the plane and the vertical line through the point $P$
- calculate $z_P-z_Q$
add a comment |
up vote
0
down vote
up vote
0
down vote
HINT
We can proceed as follow
- find the plane containing the triangle
- find the intersection point $Q$ between the plane and the vertical line through the point $P$
- calculate $z_P-z_Q$
HINT
We can proceed as follow
- find the plane containing the triangle
- find the intersection point $Q$ between the plane and the vertical line through the point $P$
- calculate $z_P-z_Q$
answered Nov 14 at 22:01
gimusi
86.6k74392
86.6k74392
add a comment |
add a comment |
up vote
0
down vote
Suppose the triangle is $ABC$ and the point is $P$.
Calculate the vectors $B-A$, $C-A$ and $P-A$. Then the sign of the vector triple product
$$
(P-A) cdot ((B-A) times (C-A))
$$
determines which side of the plane of the triangle contains $P$.
That triple product is just a determinant, which should make the coding easy.
add a comment |
up vote
0
down vote
Suppose the triangle is $ABC$ and the point is $P$.
Calculate the vectors $B-A$, $C-A$ and $P-A$. Then the sign of the vector triple product
$$
(P-A) cdot ((B-A) times (C-A))
$$
determines which side of the plane of the triangle contains $P$.
That triple product is just a determinant, which should make the coding easy.
add a comment |
up vote
0
down vote
up vote
0
down vote
Suppose the triangle is $ABC$ and the point is $P$.
Calculate the vectors $B-A$, $C-A$ and $P-A$. Then the sign of the vector triple product
$$
(P-A) cdot ((B-A) times (C-A))
$$
determines which side of the plane of the triangle contains $P$.
That triple product is just a determinant, which should make the coding easy.
Suppose the triangle is $ABC$ and the point is $P$.
Calculate the vectors $B-A$, $C-A$ and $P-A$. Then the sign of the vector triple product
$$
(P-A) cdot ((B-A) times (C-A))
$$
determines which side of the plane of the triangle contains $P$.
That triple product is just a determinant, which should make the coding easy.
answered Nov 14 at 22:02
Ethan Bolker
39.1k543102
39.1k543102
add a comment |
add a comment |
up vote
0
down vote
Write the equation of the plane of the triangle as $$z=ax+by+d$$
If your point is $p= (x_0, y_0,z_0)$ compare the $z=ax_0+by_0+d$ with $z_0$.
If $z_0 > ax_0+by_0+d$ then $p$ is above otherwise it is either below or on the plane ( in case of equality).
add a comment |
up vote
0
down vote
Write the equation of the plane of the triangle as $$z=ax+by+d$$
If your point is $p= (x_0, y_0,z_0)$ compare the $z=ax_0+by_0+d$ with $z_0$.
If $z_0 > ax_0+by_0+d$ then $p$ is above otherwise it is either below or on the plane ( in case of equality).
add a comment |
up vote
0
down vote
up vote
0
down vote
Write the equation of the plane of the triangle as $$z=ax+by+d$$
If your point is $p= (x_0, y_0,z_0)$ compare the $z=ax_0+by_0+d$ with $z_0$.
If $z_0 > ax_0+by_0+d$ then $p$ is above otherwise it is either below or on the plane ( in case of equality).
Write the equation of the plane of the triangle as $$z=ax+by+d$$
If your point is $p= (x_0, y_0,z_0)$ compare the $z=ax_0+by_0+d$ with $z_0$.
If $z_0 > ax_0+by_0+d$ then $p$ is above otherwise it is either below or on the plane ( in case of equality).
answered Nov 14 at 22:23
Mohammad Riazi-Kermani
40.2k41958
40.2k41958
add a comment |
add a comment |
up vote
0
down vote
Although others have already answered the stated question, I'd like to give some advice to those doing similar to what OP is doing.
Precalculate the unit normal vector to the triangle, and store it.
If the triangle vertices are $vec{v}_0$, $vec{v}_1$, and $vec{v}_2$, then the triangle normal is usually defined as
$$vec{n} = bigl(vec{v}_1 - vec{v}_0bigr)timesbigl(vec{v}_2 - vec{v}_0bigr)$$
where $times$ denotes vector cross product. This is scaled to unit length,
$$hat{n} = frac{vec{n}}{leftlVertvec{n}rightrVert} = frac{vec{n}}{sqrt{vec{n} cdot vec{n}}}$$
This is best precalculated and stored, because the square root operation tends to be slow, and it is just one vector per triangle.
A point is "above" the triangle if it is in the same halfspace as the triange normal vector, with respect to the plane formed by the triangle.
(If you extend the triangle plane to infinity, it splits space into two halves. If you look at the triangle sideways, the point is "above" the triangle if it is in the same side as the normal is; and "below" if it is on the other side. If the point is on the triangle plane exactly, I recommend you use a clear and unambigous term for it; I use "exactly on the triangle" myself. I'm sure mathematicians have more precise terms, but for those of us who only use math as a tool for solving problems, making sure the terms are unambiguous suffices.)
This means that point $vec{p}$ has signed distance
$$d = bigl(vec{p} - vec{v}_0bigr) cdot hat{n}$$
from the plane of the triangle. (Because all three triangle vertices are on the plane, you can use $vec{v}_1$ or $vec{v}_2$ in above; you'll still get the exact same result, within rounding error.)
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne 1$, the distance is in units of the normal vector length.
When you know the signed distance $d$ of the point $vec{p}$ from the plane, you can trivially project the point to the plane:
$$vec{p}_text{plane} = vec{p} - d hat{n}$$
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne1$, the right side is actually $vec{p} - hat{n}(d / lVerthat{n}rVert)$, and you need a "slow" square root operation here. Because you probably test many points per each triangle, it is well worth precalculating and storing the $hat{n}$ beforehand.
To determine if $vec{p}_text{plane}$ is within the triangle, find out the barycentric coordinates $(u, v)$ corresponding to $vec{p}_text{plane}$ with respect to that triangle.
To do this, check which axes have the smallest values in magnitude in $hat{n}$. Their order does not matter. (This essentially picks the axis along which to look at the triangle, with the triangle being as large as possible. We do this to minimize numerical errors.) There are three possibilities: $x$ and $y$; $x$ and $z$; and $y$ and $z$. The solution is obtained using the coordinates on those two axes.
The solution for $vec{p}_text{plane} = (x, y, z)$ with $hat{n}$ having $x$ and $y$ components closest to zero, is
$$begin{cases}
displaystyle u = frac{ (x - x_0)(y_2 - y_0) - (y - y_0)(x_2 - x_0)}{ (x - x_2)(y_1 - y_0) - (y - y_2)(x_1 - x_0) } \
displaystyle v = frac{ (y - y_0)(x_1 - x_0) - (x - x_0)(y_1 - y_0)}{ x_0 (y_1 - y_2) + x_1 (y_2 - y_0) + x_2 (y_0 - y_1) } \
end{cases}$$
The solution for the other axis pairs you'll find just by permuting the coordinates ($y$, $y_0$, $y_1$, $y_2$ to $z$, $z_0$, $z_1$, $z_2$ for $x$ and $z$ axes; and also $x$, $x_0$, $x_1$, $x_2$ to $y$, $y_0$, $y_1$, $y_2$ for $y$ and $z$).
Also note that you'll want to calculate the divisor for $u$ first. It will be zero at $vec{v}_2$, where $u = 0$, so when the divisor is very close to zero, just use $u = 0$.
In barycentric coordinates, $vec{v}_0$ is at $(0, 0)$; $vec{v}_1$ is at $(1,0)$, and $vec{v}_2$ is at $(0,1)$. The entire triangle is $0 le u, v, u + v le 1$. The edges are at $u = 0$, $v = 0$, and $u + v = 1$.
In practice, you define the triangle inclusion test as
$$Bigl(u ge -epsilonBigr) text{ and }
Bigl(v ge -epsilonBigr) text{ and }
Bigl(u le 1+epsilonBigr) text{ and }
Bigl(v le 1+epsilonBigr) text{ and }
Bigl(u + v le 1+epsilonBigr)$$
where $epsilon$ represents the precision of your numerical coordinates. It is the largest positive number you consider equal to zero. (Similarly, if $D$ is the divisor for $u$ earlier, if $-epsilon le D le +epsilon$, use $u = 0$.)
To linearly interpolate any value $c$ within the triangle, with $c = c_0$ at $vec{v}_0$, $c_1$ at $vec{v}_1$, and $c_2$ at $vec{v}_2$, you can use
$$c(u,v) = (1 - v)bigl((1-u) c_0 + u c_1bigr) + v c_2$$
All together, this means that you need only 15 (scalar) multiplications and less than thirty additions or subtractions, to find out if a point is within the triangle, or within a triangular prism extending from the triangle along its normal, including the barycentric coordinates needed for texture or color interpolation. (Color interpolation itself is just four multiplications per component, so typically 12 additional multiplications.) Nifty, eh?
add a comment |
up vote
0
down vote
Although others have already answered the stated question, I'd like to give some advice to those doing similar to what OP is doing.
Precalculate the unit normal vector to the triangle, and store it.
If the triangle vertices are $vec{v}_0$, $vec{v}_1$, and $vec{v}_2$, then the triangle normal is usually defined as
$$vec{n} = bigl(vec{v}_1 - vec{v}_0bigr)timesbigl(vec{v}_2 - vec{v}_0bigr)$$
where $times$ denotes vector cross product. This is scaled to unit length,
$$hat{n} = frac{vec{n}}{leftlVertvec{n}rightrVert} = frac{vec{n}}{sqrt{vec{n} cdot vec{n}}}$$
This is best precalculated and stored, because the square root operation tends to be slow, and it is just one vector per triangle.
A point is "above" the triangle if it is in the same halfspace as the triange normal vector, with respect to the plane formed by the triangle.
(If you extend the triangle plane to infinity, it splits space into two halves. If you look at the triangle sideways, the point is "above" the triangle if it is in the same side as the normal is; and "below" if it is on the other side. If the point is on the triangle plane exactly, I recommend you use a clear and unambigous term for it; I use "exactly on the triangle" myself. I'm sure mathematicians have more precise terms, but for those of us who only use math as a tool for solving problems, making sure the terms are unambiguous suffices.)
This means that point $vec{p}$ has signed distance
$$d = bigl(vec{p} - vec{v}_0bigr) cdot hat{n}$$
from the plane of the triangle. (Because all three triangle vertices are on the plane, you can use $vec{v}_1$ or $vec{v}_2$ in above; you'll still get the exact same result, within rounding error.)
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne 1$, the distance is in units of the normal vector length.
When you know the signed distance $d$ of the point $vec{p}$ from the plane, you can trivially project the point to the plane:
$$vec{p}_text{plane} = vec{p} - d hat{n}$$
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne1$, the right side is actually $vec{p} - hat{n}(d / lVerthat{n}rVert)$, and you need a "slow" square root operation here. Because you probably test many points per each triangle, it is well worth precalculating and storing the $hat{n}$ beforehand.
To determine if $vec{p}_text{plane}$ is within the triangle, find out the barycentric coordinates $(u, v)$ corresponding to $vec{p}_text{plane}$ with respect to that triangle.
To do this, check which axes have the smallest values in magnitude in $hat{n}$. Their order does not matter. (This essentially picks the axis along which to look at the triangle, with the triangle being as large as possible. We do this to minimize numerical errors.) There are three possibilities: $x$ and $y$; $x$ and $z$; and $y$ and $z$. The solution is obtained using the coordinates on those two axes.
The solution for $vec{p}_text{plane} = (x, y, z)$ with $hat{n}$ having $x$ and $y$ components closest to zero, is
$$begin{cases}
displaystyle u = frac{ (x - x_0)(y_2 - y_0) - (y - y_0)(x_2 - x_0)}{ (x - x_2)(y_1 - y_0) - (y - y_2)(x_1 - x_0) } \
displaystyle v = frac{ (y - y_0)(x_1 - x_0) - (x - x_0)(y_1 - y_0)}{ x_0 (y_1 - y_2) + x_1 (y_2 - y_0) + x_2 (y_0 - y_1) } \
end{cases}$$
The solution for the other axis pairs you'll find just by permuting the coordinates ($y$, $y_0$, $y_1$, $y_2$ to $z$, $z_0$, $z_1$, $z_2$ for $x$ and $z$ axes; and also $x$, $x_0$, $x_1$, $x_2$ to $y$, $y_0$, $y_1$, $y_2$ for $y$ and $z$).
Also note that you'll want to calculate the divisor for $u$ first. It will be zero at $vec{v}_2$, where $u = 0$, so when the divisor is very close to zero, just use $u = 0$.
In barycentric coordinates, $vec{v}_0$ is at $(0, 0)$; $vec{v}_1$ is at $(1,0)$, and $vec{v}_2$ is at $(0,1)$. The entire triangle is $0 le u, v, u + v le 1$. The edges are at $u = 0$, $v = 0$, and $u + v = 1$.
In practice, you define the triangle inclusion test as
$$Bigl(u ge -epsilonBigr) text{ and }
Bigl(v ge -epsilonBigr) text{ and }
Bigl(u le 1+epsilonBigr) text{ and }
Bigl(v le 1+epsilonBigr) text{ and }
Bigl(u + v le 1+epsilonBigr)$$
where $epsilon$ represents the precision of your numerical coordinates. It is the largest positive number you consider equal to zero. (Similarly, if $D$ is the divisor for $u$ earlier, if $-epsilon le D le +epsilon$, use $u = 0$.)
To linearly interpolate any value $c$ within the triangle, with $c = c_0$ at $vec{v}_0$, $c_1$ at $vec{v}_1$, and $c_2$ at $vec{v}_2$, you can use
$$c(u,v) = (1 - v)bigl((1-u) c_0 + u c_1bigr) + v c_2$$
All together, this means that you need only 15 (scalar) multiplications and less than thirty additions or subtractions, to find out if a point is within the triangle, or within a triangular prism extending from the triangle along its normal, including the barycentric coordinates needed for texture or color interpolation. (Color interpolation itself is just four multiplications per component, so typically 12 additional multiplications.) Nifty, eh?
add a comment |
up vote
0
down vote
up vote
0
down vote
Although others have already answered the stated question, I'd like to give some advice to those doing similar to what OP is doing.
Precalculate the unit normal vector to the triangle, and store it.
If the triangle vertices are $vec{v}_0$, $vec{v}_1$, and $vec{v}_2$, then the triangle normal is usually defined as
$$vec{n} = bigl(vec{v}_1 - vec{v}_0bigr)timesbigl(vec{v}_2 - vec{v}_0bigr)$$
where $times$ denotes vector cross product. This is scaled to unit length,
$$hat{n} = frac{vec{n}}{leftlVertvec{n}rightrVert} = frac{vec{n}}{sqrt{vec{n} cdot vec{n}}}$$
This is best precalculated and stored, because the square root operation tends to be slow, and it is just one vector per triangle.
A point is "above" the triangle if it is in the same halfspace as the triange normal vector, with respect to the plane formed by the triangle.
(If you extend the triangle plane to infinity, it splits space into two halves. If you look at the triangle sideways, the point is "above" the triangle if it is in the same side as the normal is; and "below" if it is on the other side. If the point is on the triangle plane exactly, I recommend you use a clear and unambigous term for it; I use "exactly on the triangle" myself. I'm sure mathematicians have more precise terms, but for those of us who only use math as a tool for solving problems, making sure the terms are unambiguous suffices.)
This means that point $vec{p}$ has signed distance
$$d = bigl(vec{p} - vec{v}_0bigr) cdot hat{n}$$
from the plane of the triangle. (Because all three triangle vertices are on the plane, you can use $vec{v}_1$ or $vec{v}_2$ in above; you'll still get the exact same result, within rounding error.)
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne 1$, the distance is in units of the normal vector length.
When you know the signed distance $d$ of the point $vec{p}$ from the plane, you can trivially project the point to the plane:
$$vec{p}_text{plane} = vec{p} - d hat{n}$$
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne1$, the right side is actually $vec{p} - hat{n}(d / lVerthat{n}rVert)$, and you need a "slow" square root operation here. Because you probably test many points per each triangle, it is well worth precalculating and storing the $hat{n}$ beforehand.
To determine if $vec{p}_text{plane}$ is within the triangle, find out the barycentric coordinates $(u, v)$ corresponding to $vec{p}_text{plane}$ with respect to that triangle.
To do this, check which axes have the smallest values in magnitude in $hat{n}$. Their order does not matter. (This essentially picks the axis along which to look at the triangle, with the triangle being as large as possible. We do this to minimize numerical errors.) There are three possibilities: $x$ and $y$; $x$ and $z$; and $y$ and $z$. The solution is obtained using the coordinates on those two axes.
The solution for $vec{p}_text{plane} = (x, y, z)$ with $hat{n}$ having $x$ and $y$ components closest to zero, is
$$begin{cases}
displaystyle u = frac{ (x - x_0)(y_2 - y_0) - (y - y_0)(x_2 - x_0)}{ (x - x_2)(y_1 - y_0) - (y - y_2)(x_1 - x_0) } \
displaystyle v = frac{ (y - y_0)(x_1 - x_0) - (x - x_0)(y_1 - y_0)}{ x_0 (y_1 - y_2) + x_1 (y_2 - y_0) + x_2 (y_0 - y_1) } \
end{cases}$$
The solution for the other axis pairs you'll find just by permuting the coordinates ($y$, $y_0$, $y_1$, $y_2$ to $z$, $z_0$, $z_1$, $z_2$ for $x$ and $z$ axes; and also $x$, $x_0$, $x_1$, $x_2$ to $y$, $y_0$, $y_1$, $y_2$ for $y$ and $z$).
Also note that you'll want to calculate the divisor for $u$ first. It will be zero at $vec{v}_2$, where $u = 0$, so when the divisor is very close to zero, just use $u = 0$.
In barycentric coordinates, $vec{v}_0$ is at $(0, 0)$; $vec{v}_1$ is at $(1,0)$, and $vec{v}_2$ is at $(0,1)$. The entire triangle is $0 le u, v, u + v le 1$. The edges are at $u = 0$, $v = 0$, and $u + v = 1$.
In practice, you define the triangle inclusion test as
$$Bigl(u ge -epsilonBigr) text{ and }
Bigl(v ge -epsilonBigr) text{ and }
Bigl(u le 1+epsilonBigr) text{ and }
Bigl(v le 1+epsilonBigr) text{ and }
Bigl(u + v le 1+epsilonBigr)$$
where $epsilon$ represents the precision of your numerical coordinates. It is the largest positive number you consider equal to zero. (Similarly, if $D$ is the divisor for $u$ earlier, if $-epsilon le D le +epsilon$, use $u = 0$.)
To linearly interpolate any value $c$ within the triangle, with $c = c_0$ at $vec{v}_0$, $c_1$ at $vec{v}_1$, and $c_2$ at $vec{v}_2$, you can use
$$c(u,v) = (1 - v)bigl((1-u) c_0 + u c_1bigr) + v c_2$$
All together, this means that you need only 15 (scalar) multiplications and less than thirty additions or subtractions, to find out if a point is within the triangle, or within a triangular prism extending from the triangle along its normal, including the barycentric coordinates needed for texture or color interpolation. (Color interpolation itself is just four multiplications per component, so typically 12 additional multiplications.) Nifty, eh?
Although others have already answered the stated question, I'd like to give some advice to those doing similar to what OP is doing.
Precalculate the unit normal vector to the triangle, and store it.
If the triangle vertices are $vec{v}_0$, $vec{v}_1$, and $vec{v}_2$, then the triangle normal is usually defined as
$$vec{n} = bigl(vec{v}_1 - vec{v}_0bigr)timesbigl(vec{v}_2 - vec{v}_0bigr)$$
where $times$ denotes vector cross product. This is scaled to unit length,
$$hat{n} = frac{vec{n}}{leftlVertvec{n}rightrVert} = frac{vec{n}}{sqrt{vec{n} cdot vec{n}}}$$
This is best precalculated and stored, because the square root operation tends to be slow, and it is just one vector per triangle.
A point is "above" the triangle if it is in the same halfspace as the triange normal vector, with respect to the plane formed by the triangle.
(If you extend the triangle plane to infinity, it splits space into two halves. If you look at the triangle sideways, the point is "above" the triangle if it is in the same side as the normal is; and "below" if it is on the other side. If the point is on the triangle plane exactly, I recommend you use a clear and unambigous term for it; I use "exactly on the triangle" myself. I'm sure mathematicians have more precise terms, but for those of us who only use math as a tool for solving problems, making sure the terms are unambiguous suffices.)
This means that point $vec{p}$ has signed distance
$$d = bigl(vec{p} - vec{v}_0bigr) cdot hat{n}$$
from the plane of the triangle. (Because all three triangle vertices are on the plane, you can use $vec{v}_1$ or $vec{v}_2$ in above; you'll still get the exact same result, within rounding error.)
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne 1$, the distance is in units of the normal vector length.
When you know the signed distance $d$ of the point $vec{p}$ from the plane, you can trivially project the point to the plane:
$$vec{p}_text{plane} = vec{p} - d hat{n}$$
If $hat{n}$ is not an unit vector, i.e. $leftlVerthat{n}rightrVertne1$, the right side is actually $vec{p} - hat{n}(d / lVerthat{n}rVert)$, and you need a "slow" square root operation here. Because you probably test many points per each triangle, it is well worth precalculating and storing the $hat{n}$ beforehand.
To determine if $vec{p}_text{plane}$ is within the triangle, find out the barycentric coordinates $(u, v)$ corresponding to $vec{p}_text{plane}$ with respect to that triangle.
To do this, check which axes have the smallest values in magnitude in $hat{n}$. Their order does not matter. (This essentially picks the axis along which to look at the triangle, with the triangle being as large as possible. We do this to minimize numerical errors.) There are three possibilities: $x$ and $y$; $x$ and $z$; and $y$ and $z$. The solution is obtained using the coordinates on those two axes.
The solution for $vec{p}_text{plane} = (x, y, z)$ with $hat{n}$ having $x$ and $y$ components closest to zero, is
$$begin{cases}
displaystyle u = frac{ (x - x_0)(y_2 - y_0) - (y - y_0)(x_2 - x_0)}{ (x - x_2)(y_1 - y_0) - (y - y_2)(x_1 - x_0) } \
displaystyle v = frac{ (y - y_0)(x_1 - x_0) - (x - x_0)(y_1 - y_0)}{ x_0 (y_1 - y_2) + x_1 (y_2 - y_0) + x_2 (y_0 - y_1) } \
end{cases}$$
The solution for the other axis pairs you'll find just by permuting the coordinates ($y$, $y_0$, $y_1$, $y_2$ to $z$, $z_0$, $z_1$, $z_2$ for $x$ and $z$ axes; and also $x$, $x_0$, $x_1$, $x_2$ to $y$, $y_0$, $y_1$, $y_2$ for $y$ and $z$).
Also note that you'll want to calculate the divisor for $u$ first. It will be zero at $vec{v}_2$, where $u = 0$, so when the divisor is very close to zero, just use $u = 0$.
In barycentric coordinates, $vec{v}_0$ is at $(0, 0)$; $vec{v}_1$ is at $(1,0)$, and $vec{v}_2$ is at $(0,1)$. The entire triangle is $0 le u, v, u + v le 1$. The edges are at $u = 0$, $v = 0$, and $u + v = 1$.
In practice, you define the triangle inclusion test as
$$Bigl(u ge -epsilonBigr) text{ and }
Bigl(v ge -epsilonBigr) text{ and }
Bigl(u le 1+epsilonBigr) text{ and }
Bigl(v le 1+epsilonBigr) text{ and }
Bigl(u + v le 1+epsilonBigr)$$
where $epsilon$ represents the precision of your numerical coordinates. It is the largest positive number you consider equal to zero. (Similarly, if $D$ is the divisor for $u$ earlier, if $-epsilon le D le +epsilon$, use $u = 0$.)
To linearly interpolate any value $c$ within the triangle, with $c = c_0$ at $vec{v}_0$, $c_1$ at $vec{v}_1$, and $c_2$ at $vec{v}_2$, you can use
$$c(u,v) = (1 - v)bigl((1-u) c_0 + u c_1bigr) + v c_2$$
All together, this means that you need only 15 (scalar) multiplications and less than thirty additions or subtractions, to find out if a point is within the triangle, or within a triangular prism extending from the triangle along its normal, including the barycentric coordinates needed for texture or color interpolation. (Color interpolation itself is just four multiplications per component, so typically 12 additional multiplications.) Nifty, eh?
answered Nov 16 at 7:48
Nominal Animal
6,5402517
6,5402517
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmath.stackexchange.com%2fquestions%2f2998875%2fhow-to-determine-if-a-point-is-above-or-below-a-plane-defined-by-a-triangle%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
How do you define “up” relative to the triangle? What do you have to work with (just the vertices or do you have a precomputed normal)?
– amd
Nov 14 at 23:03