So I have a 3D Plane described by 2 Vectors:
P : a point which lies on the Plane
N : the surface normal for the Plane
And i have a very large, flat square Polygon, which I want to render to represent this Plane. I can easily translate the polygon to the given point, but then I need to find the proper rotation to apply to make the surface normal actually be the surface normal.
I tried a method mentioned else where which was:
1) Take any none parallel vector (V) to the normal (N), and take the cross product (W1)
2) Take the cross product of (W1) and (N) now (W2) and that is a Vector (V') which lies on the Plane
I then generate a rotation matrix based on (V') laying on the Plane, so that my polygon would be aligned with (V'). that worked, but it's clear that this method is not working correctly as a whole. The Polygon is not perfectly perpendicular to the surface normal.
Any ideas on how to generate the proper rotation?
Normally rotating vectors involves matrix math, but there's a really simple trick for rotating a 2D vector by 90° clockwise: just multiply the X part of the vector by -1, and then swap X and Y values.
Some useful things about rotations:
So, the problem is to find any set of three orthonormal vectors and arrange them as
| x1 x2 x3 0 |
| y1 y2 y3 0 |
| z1 z2 z3 0 |
| 0 0 0 1 |
this is exactly what the method you described tries to do, if it doesn't work then there is a problem with your implementation.
We can obviously use your normal as (x1,y1,z1), but the problem is the system has infinitely many solutions for the remaining two vectors (although knowing one of them gives you the other, as the cross product). The following code ought to give a stable vector perpendicular to (x1,y1,z1):
float normal[3] = { ... };
int imin = 0;
for(int i=0; i<3; ++i)
if(std::abs(normal[i]) < std::abs(normal[imin]))
imin = i;
float v2[3] = {0,0,0};
float dt = normal[imin];
v2[imin] = 1;
for(int i=0;i<3;i++)
v2[i] -= dt*normal[i];
This basically uses Gram-Schmidt orthogonalisation with the dimension that is already most orthogonal to the normal vector. v3 can then be obtained by taking the cross product of normal
and v2
.
You may need to take some care setting up the rotation, it's about the origin so you need to apply the translation after the rotation and it's for column vectors rather than row vectors. If you're using OpenGL watch that OpenGL takes arrays in column major order (rather than C's row major order) so you may need to transpose.
I'm afraid I haven't tested the above, I've merely nabbed it from some code I wrote a while ago and adapted it to your problem! Hopefully I haven't forgotten any details.
Edit: I did forget something :)
The matrix above assumes your normal to the polygon is along the x-axis, and I have a sneaking suspicion it won't be, all you need to do is put the "normal" vector in the correct column of the rotation matrix, and v2/v3 in the other two columns. So if the normal to your polygon is along the z axis, then the normal goes in the 3rd column and v2/v3 go in the first two columns.
Sorry if that causes any confusion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With