I currently can rotate around a pivot point by first translating to the pivot point then performing the rotation and finally translating back to the origin. I do that easily enough for the shoulder in my example. However I cannot figure out how to also add in a rotation around the elbow for the forearm.
I've tried the following for the forearm rotation around the elbow:
translate to shoulder, rotate, translate to origin, translate to forearm, rotate, translate to origin
translate to shoulder, rotate, translate to forearm, rotate, translate to shoulder, translate to origin
Neither work for me. Any suggestions? I'm really stuck on this one.
I ran into a similar problem when I was doing some skeletal animation. It's very helpful to use recursion for this. Also, structure your bones hierarchically (e.g. shoulder is a parent of forearm which is a parent of hand, etc.). By doing that you can write your code as follows:
void drawBone(Bone *root) {
if (!root) return;
glPushMatrix();
glTranslatef(root->x,root->y,0);
glRotatef(root->a,0,0,1);
// insert code to actually draw bone here
int i;
glTranslatef(root->l,0,0);
for (i=0; i<root->childCount; i++)
drawBone(root->child[i]);
glPopMatrix();
}
My bone struct looked like this:
typedef struct _Bone {
float x,y,a,l; // position, angle, length of bone
int childCound; // number of children for this bone
struct _Bone *child[MAX_CHILD_COUNT], *parent;
} Bone;
This website is a great resource for skeletal animation.
The second approach should work.
I don't really know your model for the human body. Some similar task was
a first assignment in a computer vision course I took.
A helpful thing is to use a scene-graph to build parts that share a common
local coordinate system.
Then you can traverse it and rotate correctly.
It is helpful not to translate but to use
glPushMatrix() and glPopMatrix()
In this way you can think in a local coordinate system and affect all other elements.
Related
I am building a camera class to look arround a scene. At the moment I have 3 cubes just spread arround to have a good impression of what is going on. I have set my scroll button on a mouse to give me translation along z-axis and when I move my mouse left or right I detect this movement and rotate arround y-axis. This is just to see what happens and play arround a bit. So I succeeded in making the camera rotate by rotating the cubes arround the origin but after I rotate by some angle, lets say 90 degrees, and try to translate along z axis to my surprise I find out that my cubes are now going from left to right and not towards me or away from me. So what is going on here? It seems that z axis is rotated also. I guess the same goes for x axis. So it seems that nothing actually moved in regard to the origin, but the whole coordinate system with all the objects was just rotated. Can anyone help me here, what is going on? How coordinate system works in opengl?
You are most likely confusing local and global rotations. Usual cheap remedy is to change(reverse) order of some of your transformation. However doing this blindly is trial&error and can be frustrating. Its better to understand the math first...
Old API OpeGL uses MVP matrix which is:
MVP = Model * View * Projection
Where Model and View are already multiplied together. What you have is most likely the same. Now the problem is that Model is direct matrix, but View is Inverse.
So if you have some transform matrix representing your camera in oder to use it to transform back you need to use its inverse...
MVP = Model * Inverse(Camera) * Projection
Then you can use the same order of transformations for both Model and Camera and also use their geometric properties like basis vectors etc ... then stuff like camera local movements or camera follow are easy. Beware some tutorials use glTranspose instead of real matrix Inverse. That is correct only if the Matrix contains only unit (or equal sized) orthogonal basis vectors without any offset so no scale,skew,offset or projections just rotation and equal scale along all axises !!!
That means when you rotate Model and View in the same way the result is opposite. So in old code there is usual to have something like this:
// view part of matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotate3f(view_c,0,0,1); // ugly euler angles
glRotate3f(view_b,0,1,0); // ugly euler angles
glRotate3f(view_a,1,0,0); // ugly euler angles
glTranslatef(view_pos); // set camera position
// model part of matrix
for (i=0;i<objs;i++)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(obj_pos[i]); // set camera position
glRotate3f(obj_a[i],1,0,0); // ugly euler angles
glRotate3f(obj_b[i],0,1,0); // ugly euler angles
glRotate3f(obj_c[i],0,0,1); // ugly euler angles
//here render obj[i]
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
note the order of transforms is opposite (I just wrote it here in editor so its not tested and can be opposite to native GL notation ... I do not use Euler angles) ... The order must match your convention... To know more about these (including examples) not using useless Euler angles see:
Understanding 4x4 homogenous transform matrices
Here is 4D version of what your 3D camera class should look like (just shrink the matrices to 4x4 and have just 3 rotations instead of 6):
reper4D
pay attention to difference between local lrot_?? and global grot_?? functions. Also note rotations are defined by plane not axis vector as axis vector is just human abstraction that does not really work except 2D and 3D ... planes work from 2D to ND
PS. its a good idea to have the distortions (scale,skew) separated from model and keep transform matrices representing coordinate systems orthonormal. It will ease up a lot of things latter on once you got to do advanced math on them. Resulting in:
MVP = Model * Model_distortion * Inverse(Camera) * Projection
I am in the process of rolling my own openGL framework, and know how to draw 3d objects ... etc...
But how do you define relationships between 3d objects that may have a joint?
Or how do you define the 3d object as being a "bone"?
Are there any good resources?
As OpenGL is only a graphics library and not a 3D modeling framework the task of defining and using "bones" falls onto you.
There are different ways of actually implementing it, but the general idea is:
You treat each part of your model as a bone (e.g. head, torso, lower legs, upper legs, etc).
Each bone has a parent which it is connected to (e.g. the parent of the lower left leg is the upper left leg).
Thus each bone has a number of children.
Now you define each bone's position as a relative position to the parent bone. When displaying a bone you now multiply it's relative position with the parent bone's relative position to get the absolute position.
To visualize:
Think of it as a doll. When you grab the doll's arm and move it around, the relative position (and rotation) of the hand won't change. Its absolute position WILL change because you've moved one of its parents around.
When tried skeletal animations I learnt most of it from this link:
http://content.gpwiki.org/index.php/OpenGL:Tutorials:Basic_Bones_System
But how do you define relationships between 3d objects that may have a joint?
OpenGL does not care about these things. I't a pure drawing API. So it's upon you to unleash your creativity and define such structures yourself. The usual approach to skeletal animatio is having a bone/rig system, where each bone has an orientation (represented by a quaternion or a 3×3 matrix) a length and a list of bones attached to it further, i.e. some kind of tree.
I'd define this structure as
typedef float quaternion[4];
struct Bone {
quaternion orientation;
float length;
int n_subbones;
Bone *subbones;
};
In addition to that you need a pivot from where the rig starts. I'd do it like this
typedef float vec3[3];
struct GeomObjectBase {
vec3 position;
quaternion orientation;
};
struct BoneRig {
struct GeomObjectBase gob;
struct Bone pivot_bone;
}
Next you need some functions that iterate through this structure, generate the matrix palette out of it, so that it can be applied to the model mesh.
note: I'm using freeglut
Totally irrelevant
I am trying to create some rotation animations in my projects with objects.
Currently to animate the objects, I have written some tween functons which take the params as value from, value to, value time and tweens the object from from Param to to Param and tween the objects movements in the given time. However, I am need to creating some animations which look like the following:
The objects have to be tweened in rotation around a certain side. So, if go by this algorithm, something like:
for(int rotationAmount = 0;rotationAmount<=90;rotationAmount++){
glPushMatrix();
glRotatef(rotationAmount,1,0,0);
Rectangle(500,500,200,100);
glPopMatrix();
}
I still don't get the required effect, since the Rectangle instead of rotating around a certain side looks like rotating around the circumfrence of some big circle and coming back. Would really welcome some suggestions here on how to achieve the above?
glRotatef multiplies current matrix by rotation matrix. Rotation matrix rotates around orign of coordinates. You need to transtate orign to the side of the object, perform rotation, translate back.
point_type point_on_the_side;
for(int rotationAmount = 0;rotationAmount<=90;rotationAmount++){
glPushMatrix();
glTranslatef(-point_on_the_side.x, -point_on_the_side.y, -point_on_the_side.z);
glRotatef(rotationAmount,1,0,0);
glTranslatef(point_on_the_side.x, point_on_the_side.y, point_on_the_side.z);
Rectangle(500,500,200,100);
glPopMatrix();
}
I'm trying to implement an application using OpenGL and I need to implement the basic camera movements: orbit, pan and zoom.
To make it a little clearer, I need Maya-like camera control. Due to the nature of the application, I can't use the good ol' "transform the scene to make it look like the camera moves". So I'm stuck using transform matrices, gluLookAt, and such.
Zoom I know is dead easy, I just have to hook to the depth component of the eye vector (gluLookAt), but I'm not quite sure how to implement the other two, pan and orbit. Has anyone ever done this?
I can't use the good ol' "transform the scene to make it look like the camera moves"
OpenGL has no camera. So you'll end up doing exactly this.
Zoom I know is dead easy, I just have to hook to the depth component of the eye vector (gluLookAt),
This is not a Zoom, this is a Dolly. Zooming means varying the limits of the projection volume, i.e. the extents of a ortho projection, or the field of view of a perspective.
gluLookAt, which you've already run into, is your solution. First three arguments are the camera's position (x,y,z), next three are the camera's center (the point it's looking at), and the final three are the up vector (usually (0,1,0)), which defines the camera's y-z plane.*
It's pretty simple: you just glLoadIdentity();, call gluLookAt(...), and then draw your scene as normally. Personally, I always do all the calculations in the CPU myself. I find that orbiting a point is an extremely common task. My template C/C++ code uses spherical coordinates and looks like:
double camera_center[3] = {0.0,0.0,0.0};
double camera_radius = 4.0;
double camera_rot[2] = {0.0,0.0};
double camera_pos[3] = {
camera_center[0] + camera_radius*cos(radians(camera_rot[0]))*cos(radians(camera_rot[1])),
camera_center[1] + camera_radius* sin(radians(camera_rot[1])),
camera_center[2] + camera_radius*sin(radians(camera_rot[0]))*cos(radians(camera_rot[1]))
};
gluLookAt(
camera_pos[0], camera_pos[1], camera_pos[2],
camera_center[0],camera_center[1],camera_center[2],
0,1,0
);
Clearly you can adjust camera_radius, which will change the "zoom" of the camera, camera_rot, which will change the rotation of the camera about its axes, or camera_center, which will change the point about which the camera orbits.
*The only other tricky bit is learning exactly what all that means. To clarify, because the internet is lacking:
The position is the (x,y,z) position of the camera. Pretty straightforward.
The center is the (x,y,z) point the camera is focusing at. You're basically looking along an imaginary ray from the position to the center.
Now, your camera could still be looking any direction around this vector (e.g., it could be upsidedown, but still looking along the same direction). The up vector is a vector, not a position. It, along with that imaginary vector from the position to the center, form a plane. This is the camera's y-z plane.
Using OpenGL I'm attempting to draw a primitive map of my campus.
Can anyone explain to me how panning, zooming and rotating is usually implemented?
For example, with panning and zooming, is that simply me adjusting my viewport? So I plot and draw all my lines that compose my map, and then as the user clicks and drags it adjusts my viewport?
For panning, does it shift the x/y values of my viewport and for zooming does it increase/decrease my viewport by some amount? What about for rotation?
For rotation, do I have to do affine transforms for each polyline that represents my campus map? Won't this be expensive to do on the fly on a decent sized map?
Or, is the viewport left the same and panning/zooming/rotation is done in some otherway?
For example, if you go to this link you'll see him describe panning and zooming exactly how I have above, by modifying the viewport.
Is this not correct?
They're achieved by applying a series of glTranslate, glRotate commands (that represent camera position and orientation) before drawing the scene. (technically, you're rotating the whole scene!)
There are utility functions like gluLookAt which sorta abstract some details about this.
To simplyify things, assume you have two vectors representing your camera: position and direction.
gluLookAt takes the position, destination, and up vector.
If you implement a vector class, destinaion = position + direction should give you a destination point.
Again to make things simple, you can assume the up vector to always be (0,1,0)
Then, before rendering anything in your scene, load the identity matrix and call gluLookAt
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( source.x, source.y, source.z, destination.x, destination.y, destination.z, 0, 1, 0 );
Then start drawing your objects
You can let the user span by changing the position slightly to the right or to the left. Rotation is a bit more complicated as you have to rotate the direction vector. Assuming that what you're rotating is the camera, not some object in the scene.
One problem is, if you only have a direction vector "forward" how do you move it? where is the right and left?
My approach in this case is to just take the cross product of "direction" and (0,1,0).
Now you can move the camera to the left and to the right using something like:
position = position + right * amount; //amount < 0 moves to the left
You can move forward using the "direction vector", but IMO it's better to restrict movement to a horizontal plane, so get the forward vector the same way we got the right vector:
forward = cross( up, right )
To be honest, this is somewhat of a hackish approach.
The proper approach is to use a more "sophisticated" data structure to represent the "orientation" of the camera, not just the forward direction. However, since you're just starting out, it's good to take things one step at a time.
All of these "actions" can be achieved using model-view matrix transformation functions. You should read about glTranslatef (panning), glScalef (zoom), glRotatef (rotation). You also should need to read some basic tutorial about OpenGL, you might find this link useful.
Generally there are three steps that are applied whenever you reference any point in 3d space within opengl.
Given a Local point
Local -> World Transform
World -> Camera Transform
Camera -> Screen Transform (usually a projection. depends on if you're using perspective or orthogonal)
Each of these transforms is taking your 3d point, and multiplying by a matrix.
When you are rotating the camera, it is generally changing the world -> camera transform by multiplying the transform matrix by your rotation/pan/zoom affine transformation. Since all of your points are re-rendered each frame, the new matrix gets applied to your points, and it gives the appearance of a rotation.