Dan Karron@UCBVAX.BERKELEY.EDU (03/24/91)
Has anyone have an algoritm for removing the annoying twist when you use lookat() to view an object from arbitrary locations ? I need the formulas given two points that define an eye vector will return the euler angles (Z,Y,X is my preferred order) that will (when inverted) give a view of an object with the world space +Z vector always pointing up (+y in screen space) as much as possible. I am hard coding values for the 24 cardinal points of a cube surrounding an object for eye positions looking at the origin, and there must be a formula to calculate the roll (Z euler angle) to keep the object right side up. Cheers! (I will post the values that look good, but what is the formula for arbitrary locations ?) | karron@nyu.edu (e-mail alias ) Dan Karron, Research Associate | | Phone: 212 263 5210 Fax: 212 263 7190 New York University Medical Center | | 560 First Avenue Digital Pager <1> (212) 397 9330 | | New York, New York 10016 <2> 10896 <3> <your-number-here> |
blbates@AERO36.LARC.NASA.GOV (Brent Bates ViGYAN AAD/TAB) (03/25/91)
A while back Stefan Farestam <farestam@orion.cerfacs.fr> posted some equations for finding the proper twist angle and I just recently added them to something I'm working on. Here is part of his note: >* view_point is the point you are looking from > >* ref_point is the point you are looking towards > >* up_vec is a vector that represents the direction up (i.e. if you would > plot up_vec after lookat was applied it would be a vertical vector > pointing upwards on the screen) > >* v = view_point - ref_point > >* w = (up_vec) x (v) where 'x' signifies the vector product > >* v and w are normalized > >then the twist angle used in lookat can be calculated by: > > swy = (int) copysign(1.0, wy) ; > > twist = swy * acos((wx*vz - wz*vx) / sqrt(vx*vx + vz*vz) > / sqrt(wx*wx + wy*wy + wz*wz)) ; > >and the call to lookat would look like: > > lookat(view_point->x, view_point->y, view_point->z, > ref_point->x, ref_point->y, ref_point->z, twist * 180/PI * 10) ; Below is my implemention in C: /* I am looking from origin to a point in space, however the look vector is in opposite direction */ look_x=(-x); look_y=(-y); look_z=(-z); /* Non ambiguous direction vector in same x/y direction as REAL look vector */ ra_x=x; ra_y=y; ra_z=0.0; /* up_vec = look_vec X (unit_z_vec X ra_vec) (unit_z_vec X ra_vec) creates a vector perpendicular to look vector with the general "up" direction I want. */ up_x=(-ra_x*z); up_y=(-ra_y*z); up_z=x*ra_x+y*ra_y; /* Now up vector is perpendicular to look vector */ /* w_vec = up_vec X look_vec */ w_x=up_y*look_z-up_z*look_y; w_y=up_z*look_x-up_x*look_z; w_z=up_x*look_y-up_y*look_x; mag=sqrt(look_x*look_x+look_y*look_y+look_z*look_z); look_x=look_x/mag; look_y=look_y/mag; look_z=look_z/mag; mag=sqrt(w_x*w_x+w_y*w_y+w_z*w_z); w_x=w_x/mag; w_y=w_y/mag; w_z=w_z/mag; swy=copysign(1.0,w_y); twist=(Angle) (swy*acos((w_x*look_z-w_z*look_x)/ sqrt(look_x*look_x+look_z*look_z)/ sqrt(w_x*w_x+w_y*w_y+w_z*w_z))*1800.0/pi); lookat(0.0,0.0,0.0,(Coord) x,(Coord) y,(Coord) z,twist); The important thing to note is that the up vector MUST be perpendicular to the look vector. I kept getting incorrect results until did this. This seems to work for all look vectors. I have tried various look vectors that could give problems and the results were still correct. Hope this helps. Brent L. Bates NASA-Langley Research Center M.S. 361 Hampton, Virginia 23665-5225 Phone:(804) 864-2854 FAX:(804) 864-6792 E-mail: blbates@aero36.larc.nasa.gov or blbates@aero8.larc.nasa.gov
andru@electron.lcs.mit.edu (Andrew Myers) (03/30/91)
In article <9103232036.AA05543@karron.med.nyu.edu> karron@cmcl2.nyu.edu writes: > >Has anyone have an algoritm for removing the annoying twist when you >use lookat() to view an object from arbitrary locations ? Contrary to popular belief, lookat has no "annoying twist" problem. Rather, it has an "annoying axis" problem. lookat aligns things so that the Y axis is up, not the Z axis as you might expect. You can compensate for this by simply putting 90 degree rotations around your lookat command. Andrew
thant@horus.esd.sgi.com (Thant Tessman) (04/04/91)
Here is my twice-yearly posting of an alternative to the lookat command: To compile: cc example.c upat.c -lgl_s -lm -o example ----------------------cut here-------------------------- #!/bin/sh -v # this is a shell archive (once) named upat.mail # created by thant@horus at Thu Jan 17 08:59:48 PST 1991 # # The rest of this file is a shell script which will extract: # example.c # upat.c # # to use, type sh upat.mail # echo x - example.c cat > example.c << 'EndOfRecord' #include <gl.h> #include <device.h> extern void upat(float vx, float vy, float vz, float px, float py, float pz, float ux, float uy, float uz); main() { int dev; short val; float i, j, k; initialize(); /* first flyby */ printf("Y is up. (Just like lookat.)\n"); j = 2.0; for (i = -8.0, k=12.0; i<12.0; i+=0.05, k-=0.05) { color(BLACK); clear(); perspective(400, 5.0/4.0, 1.0, 50.0); upat(i, j, k, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); draw_axes(); swapbuffers(); } /* second flyby */ printf("Z is up, but same path.\n"); j = 2.0; for (i = -8.0, k=12.0; i<12.0; i+=0.05, k-=0.05) { color(BLACK); clear(); perspective(400, 5.0/4.0, 1.0, 50.0); upat(i, j, k, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); draw_axes(); swapbuffers(); } /* third flyby */ printf("(1, 1, 1) is up. Different path.\n"); for (i = -8.0, j=10.0, k=12.0; i<12.0; i+=0.05, k-=0.05, j-=0.05) { color(BLACK); clear(); perspective(400, 5.0/4.0, 1.0, 50.0); upat(i, j, k, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0); draw_axes(); swapbuffers(); } } initialize() { keepaspect(5, 4); winopen(""); doublebuffer(); gconfig(); qdevice(ESCKEY); } draw_axes() { color(RED); move(0.0, 0.0, 0.0); draw(1.0, 0.0, 0.0); cmov(1.2, 0.0, 0.0); charstr("x"); color(GREEN); move(0.0, 0.0, 0.0); draw(0.0, 1.0, 0.0); cmov(0.0, 1.2, 0.0); charstr("y"); color(BLUE); move(0.0, 0.0, 0.0); draw(0.0, 0.0, 1.0); cmov(0.0, 0.0, 1.2); charstr("z"); color(WHITE); move(0.5, 0.5, 0.5); draw(0.5, 0.5, 0.0); move(0.5, 0.0, 0.0); draw(0.5, 0.5, 0.0); draw(0.0, 0.5, 0.0); move(0.5, 0.5, 0.5); draw(0.0, 0.5, 0.5); move(0.0, 0.5, 0.0); draw(0.0, 0.5, 0.5); draw(0.0, 0.0, 0.5); move(0.5, 0.5, 0.5); draw(0.5, 0.0, 0.5); move(0.5, 0.0, 0.0); draw(0.5, 0.0, 0.5); draw(0.0, 0.0, 0.5); } EndOfRecord len=`wc -c < example.c ` if [ $len != 1993 ] ; then echo error: example.c was $len bytes long, should have been 1993 fi echo x - upat.c cat > upat.c << 'EndOfRecord' #include "math.h" #include "gl.h" #include "stdio.h" #define X 0 #define Y 1 #define Z 2 void normalize(float *); void cross(float *result, float *v1, float *v2); void upat(float vx, float vy, float vz, float px, float py, float pz, float ux, float uy, float uz) { int i; float forward[3], side[3], up[3]; float m[4][4]; forward[X] = px - vx; forward[Y] = py - vy; forward[Z] = pz - vz; up[X] = ux; /* temporarily use view-up to hold world-up */ up[Y] = uy; up[Z] = uz; normalize(forward); /* make side from view forward and world up */ cross(side, forward, up); normalize(side); /* make view up from view forward and view side */ cross(up, side, forward); m[0][0] = side[X]; m[1][0] = side[Y]; m[2][0] = side[Z]; m[3][0] = 0.0; m[0][1] = up[X]; m[1][1] = up[Y]; m[2][1] = up[Z]; m[3][1] = 0.0; m[0][2] = -forward[X]; m[1][2] = -forward[Y]; m[2][2] = -forward[Z]; m[3][2] = 0.0; m[0][3] = 0.0; m[1][3] = 0.0; m[2][3] = 0.0; m[3][3] = 1.0; multmatrix(m); translate(-vx, -vy, -vz); } void normalize(float *v) { float r; r = sqrt( v[X]*v[X] + v[Y]*v[Y] + v[Z]*v[Z] ); v[X] /= r; v[Y] /= r; v[Z] /= r; } void cross(float *result, float *v1, float *v2) { result[X] = v1[Y]*v2[Z] - v1[Z]*v2[Y]; result[Y] = v1[Z]*v2[X] - v1[X]*v2[Z]; result[Z] = v1[X]*v2[Y] - v1[Y]*v2[X]; } EndOfRecord len=`wc -c < upat.c ` if [ $len != 1480 ] ; then echo error: upat.c was $len bytes long, should have been 1480 fi