views:

133

answers:

3

When I have a QUAD at a certain position, how can I rotate it in such a way that its normal points toward a given point? Imagine the colored blocks are just rectangular quads, then this image shows a bit what I mean. The quads are all oriented in such a way they point toward the center of the sphere.

alt text

Maybe this second image shows a bit more what I'm trying to do: alt text

I'm using openGL / C++ (and the Eigen lib). And I have this code to draw a simple quad:

#include "ofMain.h"
#include "Quad.h"
Quad::Quad(Vector3f oPosition):position(oPosition) {
}

void Quad::update() {
}

void Quad::draw() {
    float size = 1.3;
    glColor3f(1.0f, 0.0f, 0.6f);
    glPushMatrix();
        glTranslatef(position.x(), position.y(), position.z());
        glScalef(size, size,size);
        glBegin(GL_QUADS);
            glVertex3f(0,0,0);
            glVertex3f(1,0,0);
            glVertex3f(1,1,0);
            glVertex3f(0,1,0);
        glEnd();
    glPopMatrix();
}

Update 17-07 Dear reader,

Just got a little bit further with rotating the quads. I'm positioning a couple of quads randomly and then I rotate them towards a look_at vector3f using this code using the descriptions from the replies below:

void Quad::draw() {
    float size = 0.5;
    glColor3f(1.0f, 0.0f, 0.6f);
    glPushMatrix();
        Vector3f center = look_at - position;
        Vector3f center_norm = center.normalized();
        float r_angle   = acos(center_norm.dot(normal));
        Vector3f axis = normal.normalized().cross(center_norm);

        glPointSize(8);
        glLineWidth(4.0f);

        // draw the center point
        glColor3f(1.0f, 0.0f, 0.0f);
        glBegin(GL_POINTS); 
            glVertex3fv(look_at.data());
        glEnd();

        // draw the quad
        glColor4f(0.0f, 0.0f, 0.0f, 0.85f); 
        glTranslatef(position.x(), position.y(), position.z());
        glRotatef(r_angle * RAD_TO_DEG, axis.x(), axis.y(), axis.z());
        glScalef(size, size,size);
        glBegin(GL_QUADS);
            glVertex3f(-0.5,-0.5,0);
            glVertex3f(0.5,-0.5,0);
            glVertex3f(0.5,0.5,0);
            glVertex3f(-0.5,0.5,0);
        glEnd();

    glPopMatrix();
}

The result looks like this: alt text

As you can see I'm almost there, though the rotation of the quads is still a bit "strange". I you see the image below with the colored quads you clearly see the difference in rotation. How can I rotate the quad in such a way I get the same result as the colored sphere below?

Thanks in advance

+2  A: 

You may have already found this - http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation - but I found it useful when I last looked into this topic.

Michael Repucci
+1  A: 

Rotation axis = normalize(crossproduct(currentNormal, desiredNormal))

Rotation angle = acos(dotproduct(normalize(currentNormal), normalize(desiredNormal)).

You can build either rotation matrix or quaternion from axis and angle. Exact formula can be found in any resource about quaternions.

You may need to flip angle or axis depending on whether you rotate normal around its' base or around its' tip.

Also THIS resource seems to have enough information about quaternions, rotations, and 3d space in general.

SigTerm
Hi SigTerm, but how do I solve this when I don't know my currentNormal? I only got the code I pasted (the `Quad` class).
pollux
For a quad abcd normal can be found using using cross product = normalize(cross(c-a, d-b)) or normalize(Crossproduct(b-a, c-a)). Any two non-parallel vectors from quad can be used to make perpendicular. In your example normal is either (0, 0, 1) or (0, 0, -1). (depends on whether quads use same winding order, one-sided or double-sided, etc).
SigTerm
SigTerm, what do you mean with rotating around it's 'base' or 'tip'? Could this cause the result I've got now (see the black quads above)
pollux
@pollux: I could explain everything if I had a chalkboard, few minutes of time and you were physically present in the room. In pure text it is a bit difficult. Right now you get your behavior, because you try to align quads using just one rotation. It IS possible, but it is much easier to use two rotations - first you rotate quad so its' normal is parallel (or opposite, depends on what you want) to vector pointing towards center of the sphere. If I understand your screenshot correctly, you already did that. Second you rotate quad around the normal so its' "up" vector is properly aligned.
SigTerm
@SigTerm, thanks! I indeed think I'm doing step one already. How can I rotate the quad around the normal so it's properly aligned? i.e. how do I know it's properly aligned? And, as a sidenode I've been googling for this problem but can't really find anything similar (aligning normals in such a way). I'm probably using wrong keywords.. is there a name for what I'm trying to accomplish?Kind regards,pollux
pollux
@pollux: Step #2: in quad you need to find "local up" vector. I.e. direction which is pointing from quad's center to quad's "top". And you need a "global up" vector, which points up in the world. To find "proper up" for a quad, you'll need to make two cross-products - first "vec3 side = normalize(cross(global_up, direction_to_center))" - this will get vector that points "sideways". Then you can get "proper_up = normalize(cross(direction_to_center, side))". This will give you required "up" vector for a quad. Now you can calculate rotation angle (acos(dot(local_up, proper_up)), and use ...
SigTerm
@pollux: .. direction_to_sphere as rotation axis (don't forget to normalize).
SigTerm
@pollux: problem can be solved differently. In THIS case quad's position/rotation can be as yaw, pitch and distance. I.e. two rotation angles and distance from center of the sphere. You can make just one quad, then draw it using one glTranslate and two glRotate calls. Distance can be calculated as length(quad_center-sphere_center). pitch - acos(dot3(global_up, normalize(quad_center - sphere_center))), etc. It isn't difficult.
SigTerm
@pollux: anyway, if you're having difficulties, i'd recommend to get trigonometry books, draw everything on paper, and see how would you rotate quads yourself, and how you would calculate rotation. Or you could probably ask some kind of geometry teacher/tutor for help. I *use* and understand 3d stuff like this somewhat intuitively, but I'm not a teacher, and I'm not good at *explaining* it remotely without pen/paper or chalkboard. I probably won't be able to help you further.
SigTerm
Hi SigTerm, thank a bunch! You helped me a lot with this! And you're the only one who understands and explains this problem very clear. Again thanks; I'll try to get the rotations correctly now. I'll try both solutions.
pollux
A: 

If "at a certain position" means that you know your current normal, than here is the thing:

  1. Dot product of an old and new normal is a cosine of an angle between them.
  2. Their cross product is an axis around which you should perform desired rotation
  3. Construction of rotation quaternion from given axis and angle is well documented and basic feature.
  4. Rotating the quad itself is tricky and depends on how what exactly you want it to be rotated.
Dark