Given a triangle vertex defined with three 3D points, how do you calculate the angle between it and a given point.
class Point3D
{
double x, y, z;
}
class Vertex
{
Point3D P1, P2, P3;
}
Point3D LightPoint;
http://www.ianquigley.com/iq/RandomImages/vextor.png
Light point in Red. Blue points – triangle with the surface normal shown.
I need to calculate the surface normal, and the angle between that and the LightPoint. I’ve found a few bits a pieces but nothing which puts it together.
OK, here goes…
You have points A, B, and C, each of which has coordinates x, y, and z. You want the length of the normal, as Matias said, so that you can calculate the angle that a vector between your point and the origin of the normal makes with the normal itself. It may help you to realize that your image is misleading for the purposes of our calculations; the normal (blue line) should be emanating from one of the vertices of the triangle. To turn your point into a vector it has to go somewhere, and you only know the points of the vertices (while you can interpolate any point within the triangle, the whole point of vertex shading is to not have to).
Anyway, first step is to turn your Point3Ds into Vector3Ds. This is accomplished simply by taking the difference between each of the origin and destination points’ coordinates. Use one point as the origin for both vectors, and the other two points as the destination of each. So if A is your origin, subtract A from B, then A from C. You now have a vector that describes the magnitude of the movement in X, Y, and Z axes to go from Point A to point B, and likewise from A to C. It is worth noting that a theoretical vector has no start point of its own; to get to point B, you have to start at A and apply the vector.
The System.Windows.Media.Media3D namespace has a Vector3D struct you can use, and handily enough, the Point3D in the same namespace has a Subtract() function that returns a Vector3D:
Now, the normal is the cross product of the two vectors. Use the following formula:
v1 x v2 = [ y1*z2 – y2*z1 , z1*x2 – z2*x1 , x1*y2 – x2*y1 ]
This is based on matrix math you don’t strictly have to know to implement it. The three terms in the matrix are the X, Y, and Z of the normal vector. Luckily enough, if you use the Media3D namespace, the Vector3D structure has a CrossProduct() method that will do this for you:
Now, you need a third vector, between LightPoint and A:
This is the direction that light will travel to get to PointA from your source.
Now, to find the angle between them, you compute the dot product of these two and the length of these two:
|v| = sqrt(x^2 + y^2 + z^2)
v1 * v2 = x1*x2 + y1*y2 + z1*z2
Or, if you’re using Media3D, Vector3D has a Length property and a DotProduct static method:
Finally, the formula Matias mentioned:
v1 * v2 = |v1||v2|cos(theta)
rearranging and substituting variable names:
Or, if you were smart enough to use Media3D objects, forget all the length and dot product stuff:
Theta is now the angle in degrees. Multiply this by the quantity 2(pi)/360 to get radians if you need it that way.
The moral of the story is, use what the framework gives you unless you have a good reason to do otherwise; using the Media3D namespace, all the vector algebra goes away and you can find the answer in 5 easy-to-read lines [I edited this, adding the code I used — Ian]: