I'm using Opengl as the foundations for a small car simulation.
I've imported a model car and it drives around fine and the camera follows it. Unfortunately I can't seem to get the camera's position to move (or stay behind the car) when the car turns. It just rotates on the spot.
eg if the car turns left, the camera rotates to follow it but doesn't move to directly behind the car.
I've looked at these questions here and here but still can't seem to get it working.
This is how I calculate the position of the car (it just drives on the XZ plane for now):
velocity.x = sin(rotX_rad);
velocity.z = cos(rotX_rad);
globalPos.x + velocity.x*delta;
globalPos.z + velocity.z*delta;
glTranslatef(globalPos.x,globalPos.y,globalPos.z);
glRotatef(rotX, 0.0, 1.0, 0.0);
And this is currently how I have my lookAt function:
gluLookAt(camX+globalPos.x,
camY+globalPos.y,
camZ+globalPos.z,
lookX+globalPos.x+sin(rotX_rad),
lookY+globalPos.y+cos(rotX_rad),
lookZ+globalPos.z-cos(rotX_rad),
camNX, camNY, camNZ);
I would like the camera to be like this: (where Y is Z)
The way I see it, it should be:
camX + globalPos.x+ sin(rotX_rad)*(distFromCar),
camY,
camZ + globalPos.z- cos(rotX_rad)*(distFromCar),
but it behaves strangely....
What am I not doing?
Give this a shot, it makes sense in my head but it might not in reality :)
Ok, so we can represent your car's position and velocity as 2-element vectors (in the case of position it is a point, and in the case of velocity it is a true vector.)
Now that we have that, to calculate the position of the camera we can just take the negative of your velocity vector (this means just make all elements of the vector negative, yielding a vector of the same magnitude but exactly opposite direction) and add that vector to your car's position.
For example, say your car is at position (1,1) and your speed vector is (1,2). The negative speed vector would be (-1,-2) and the position of your camera would be (1,1) + (-1,-2) to be (0,-1). You will probably want to normalize the negative speed vector so that your camera stays a constant distance from the car, otherwise the faster you go the further the camera will get :)
Now that you have the camera's position, just call gluLookAt:
gluLookAt(camPos.x,camPos.y,camPos.z,carPos.x,carPos.y,carPos.z,0,1,0);
As you can see, we are passing in the camera's position (which we just calculated in the previous step) and telling the camera to look at the car. You may want to tweak some values (for example, have the camera be floating a few units off the ground, instead of directly behind the car, or maybe have the camera look at a point a few units above the car, etc.)
Let me know how this goes! Again, this is just something I thought might work for you, no guarantees that my math is right though :) But this should be faster and easier to understand than messing around with angles and such. One thing to keep in mind: this will not work if the car is completely stationary (no velocity vector)
Related
I'm working on a simple little game/simulation where I want to bounce a ball. I'm trying to make the ball bounce not quite realistically, but more in a "game universe" way.
I have these variables to work with:
Vector ball_direction; // Direction the ball was moving in prior to impact
Vector ball_bounce_direction; // New direction of the ball computed from the collided face's normal
Vector collide_face_normal; // The normal of the collided face
Vector collide_face_perp; // perpendicular to the normal of the collided face
Vector gravity; // The gravity of the world-- doesn't really factor in since I want to do this operation based on the collision normal
So basically what I want to do is:
multiply ball_bounce_direction by .6 in the direction of collide_face_normal.
multiply ball_bounce_direction by 1.0 in the direction of collide_face_perp.
So a bouncing ball on a flat surface, I want the bounces to get smaller, while it completely maintains its sideways velocity.
Cans someone tell me what I need to do to ball_bounce_direction to achieve this?
If you think of the dot product as "the magnitude of a vector in the direction of another vector", you can break ball_bounce_direction into two parts (I'm assuming you have a dot function):
Vector bbd_norm = ball_bounce_direction.dot(collide_face_normal)*ball_bounce_direction;
Vector bbd_perp = ball_bounce_direction.dot(collide_face_perp)*ball_bounce_direction;
This works because collide_face_* vectors are perpendicular, then you can build a new vector:
ball_bounce_direction = 0.6*bbd_norm + bbd_perp;
So, I have a Triangle->AABB collision algorithm and I have it returning the triangle that the AABB collided with. I was hoping with the 3 vectors of the triangle and the direction/magnitude of the movement would let me determine a deflected vector so that when you run against the wall at an angle you move slower, depending on the angle of collision, but along side the wall. This would remove the sticky collision problem with only moving when there is not a collision. Any suggestions or references would be greatly appreciated! Thanks.
First, I would convert magnitude/direction to a vector (it's much more convenient).
Then (c++):
float towards=dot(velocity,norm); // velocity component into triangle
if(towards<0) // is moving into triangle
velocity-=towards*norm; // remove component
Then it can't move into the triangle. towards<0 might need to be reversed depending on your normal. It's also nice to have a spring force pushing it out.
Remove the component of the velocity along the normal of the triangle.
The idea is that you can represent the movement as the part that's moving "into" the triangle and the remainder (which will be in perpendicular directions). If you then just move with the remainder, you will no longer be getting any closer to the triangle by the movement (or further, but you shouldn't be detecting a collision in that case).
In pseudo-code:
// v := velocity vector of moving object
// p[3] := points that make up the triangle
triangle_normal = cross(p[2]-p[0], p[1]-p[0])
problematic_v = project(v, onto=triangle_normal)
safe_movement = v - problematic_movement
Note that this intentionally doesn't preserve the magnitude of the movement vector, as doing so would make you slide along a wall very quickly when running straight at it.
For more details and some nice pictures, see Pool Hall Lessons: Fast, Accurate Collision Detection Between Circles or Spheres at Gamasutra. You're not using spheres, but you are essentially doing a perfectly plastic (since you don't bounce) collision.
I am trying to understand the glLookAt function.
It takes 3 triplets. The first is the eye position, the second is the point at which the eye stares. That point will appear in the center of my viewport, right? The third is the 'up' vector. I understand the meaning of the 'up' vector if it is perpendicular to the vector from eye to starepoint. The question is, is it allowed to specify other vectors for up, and, if yes, what's the meaning then?
A link to a graphical detailed explanation of gluPerstpective, glLookAt and glFrustum would be also much appreciated. The official OpenGL documentation appears not to be intended for newbies.
Please note that I understand the meaning of up vector when it is perpendicular to eye->object vector. The question is what is the meaning (if any), if it is not. I can't figure that out with playing with parameters.
It works as long as it is "sufficiently perpendicular" to the up vector. What matters is the plane between the up-vector and the look-at vector.
If these two become aligned the up-direction will be more or less random (based on the very small bits in your values), as a small adjustment of it will leave it pointing above/left/right of the look-at vector.
If they have a sufficiently large separating angle (in 32-bit floating point math) it will work well. This angle needs usually not be more than a degree or so, so they can be very close. But if the difference is down to a few bits, each changed bit will yield a huge direcitonal change.
It comes down to numerical precision.
(I'm sure there are more mathematical terms & definitions for this, but it's been a few years since college.. :)
final word: If the vectors are parallel, then the up-direction is completely undefined and you'll get a degenerate view matrix.
The up vector lets openGL know what way your have your camera.
Think in the really world, if you have to points in space, you can draw a line from one to the other. You can then align an object, such as a camera so that it points from one to the other. But you have no way of knowing how you object should be rotated around this axis that the line makes. The up vector dictates which direction the camera should be standing.
most of the time, your up vector will be (0,1,0) which means that the camera will be rotated just like you would normally hold a camera, or if you held your head up straight. if you set your up vector (1,0,0) it would be like holding your head on its side, so from the base of your head to the top of your head it pointing to the right. You are still looking from the same point (more or less) to the same point, but your 'up' has changed. A look vector of(0,-1,0) would make the camera be up side down, like if you where doing a hand stand.
One way you could think about this, your arm is a vector from the camera position (your shoulder) to the camera look at point (your index finger) if you stick you thumb out, this is your up vector.
This picture may help you http://images.gamedev.net/features/programming/oglch3excerpt/03fig11.jpg
EIDT
Perpendicular or not.
I see what you are asking now. example, you at (10,10,10) looking at (0,0,0) the resulting vector for your looking direction is (-10,-10,-10) the vector perpendicular to this does not matter for the purpose of you up vector glLookAt, if you wanted the view to orientated so that you are like a normal person just looking down a bit, just set you up vector to (0,1,0) In fact, unless you want to be able to roll the camera, you don't need this to be nay thing else.
In this website you have a great tutorial
http://www.xmission.com/~nate/tutors.html
http://users.polytech.unice.fr/~buffa/cours/synthese_image/DOCS/www.xmission.com/Nate/tutors.html
Download the executables and you can change the values of the parameters to the glLookAt function and see what happens "in real-time".
The up vector does not need to be perpendicular to the looking direction. As long as it is not parallel (or very close to being parallel) to the looking direction, you should be fine.
Given that you have a view plane normal, N (the looking direction) and a up vector (which mustn't be parallel to N), UV you calculate the actual up vector which will be used in the camera transform by first calculating the vector V = UV - (N * UV)N. V is in turn used to calculate the actual up vector used by creating a vector which is perpendicular to both N and V as U = N x V.
Yes. It is arbitrary, which lets you make the camera "roll", i.e. appear as if the scene is rotating around the eye axis.
I am trying to prototype a space flight sim in OpenGL, but after reading many articles online I still have difficulty with getting the rotations to work correctly (I did have a quaternion camera that I didn't understand well, but it drifts and has other odd behaviors).
I am trying to do the following:
1) Local rotation - when the user presses arrow keys, rotation occurs relative to the viewport (rotating "up" is toward the top of the screen, for example). Two keys, such as Z and X, will control the "roll" of the ship (rotation around the current view).
2) The rotations will be stored in Axis-angle format (which is most natural for OpenGL and a single rotate call with the camera vector should rotate the scene properly). Therefore, given the initial Angle-axis vector, and one or more of the local rotations noted above (we could locally call "X" the left/right axis, "Y" the top/bottom axis, and "Z" the roll axis), I would like the end result to be a new Axis-angle vector.
3) Avoid quarternions and minimize the use of matrices (for some reason I find both unintuitive). Instead of matrix notation please just show in psuedocode the vector components and what's happening.
4) You should be able to rotate in a direction (using the arrow keys) 360 degrees and return to the starting view without drifting. Preferably, if the user presses one combination and then reverses it, they would expect to be able to return to near their original orientation.
5) The starting state for the camera is at coordinates (0,0,0) facing the Axis-angle vector (0,0,1,0 - z-axis with no starting rotation). "up" is (0,1,0).
Using Euler angles approach is wrong with spacesim. I have tried that approach and quickly had to give up. Player wants all degrees of freedom, and Euler's angles don't provide that, or complicate it enormously.
What you really, really want are quaternions. This is a part of my update code.
Quaternion qtmp1, qtmp2, qtmp3;
Rotation r(........);
qtmp1.CreateFromAxisAngle(1., 0., 0., r.j*m_updatediff);
qtmp2.CreateFromAxisAngle(0., 1., 0., r.i*m_updatediff);
qtmp3.CreateFromAxisAngle(0., 0., 1., r.k*m_updatediff);
m_rotq = qtmp1 * qtmp2 * qtmp3 * m_rotq;
r.i, r.j and r.k contain the current speed of rotation around a certain axis. Getting a spacesim-like feel is just a matter of multiplying these quaternions.
Everything else is just a complication. With Euler's angles, you can play all day long -- in fact, all year long -- but you will just make loads of messy code.
Your daily recommendation: quaternions.
I am writing a program that will draw a solid along the curve of a spline. I am using visual studio 2005, and writing in C++ for OpenGL. I'm using FLTK to open my windows (fast and light toolkit).
I currently have an algorithm that will draw a Cardinal Cubic Spline, given a set of control points, by breaking the intervals between the points up into subintervals and drawing linesegments between these sub points. The number of subintervals is variable.
The line drawing code works wonderfully, and basically works as follows: I generate a set of points along the spline curve using the spline equation and store them in an array (as a special datastructure called Pnt3f, where the coordinates are 3 floats and there are some handy functions such as distance, length, dot and crossproduct). Then i have a single loop that iterates through the array of points and draws them as so:
glBegin(GL_LINE_STRIP);
for(pt = 0; pt<=numsubsegements ; ++pt) {
glVertex3fv(pt.v());
}
glEnd();
As stated, this code works great. Now what i want to do is, instead of drawing a line, I want to extrude a solid. My current exploration is using a 'cylinder' quadric to create a tube along the line. This is a bit trickier, as I have to orient openGL in the direction i want to draw the cylinder. My idea is to do this:
Psuedocode:
Push the current matrix,
translate to the first control point
rotate to face the next point
draw a cylinder (length = distance between the points)
Pop the matrix
repeat
My problem is getting the angles between the points. I only need yaw and pitch, roll isnt important. I know take the arc-cosine of the dot product of the two points divided by the magnitude of both points, will return the angle between them, but this is not something i can feed to OpenGL to rotate with. I've tried doing this in 2d, using the XZ plane to get x rotation, and making the points vectors from the origin, but it does not return the correct angle.
My current approach is much simpler. For each plane of rotation (X and Y), find the angle by:
arc-cosine( (difference in 'x' values)/distance between the points)
the 'x' value depends on how your set your plane up, though for my calculations I always use world x.
Barring a few issues of it making it draw in the correct quadrant that I havent worked out yet, I want to get advice to see if this was a good implementation, or to see if someone knew a better way.
You are correct in forming two vectors from the three points in two adjacent line segments and then using the arccosine of the dot product to get the angle between them. To make use of this angle you need to determine the axis around which the rotation should occur. Take the cross product of the same two vectors to get this axis. You can then build a transformation matrix using this axis-angle or pass it as parameters to glRotate.
A few notes:
first of all, this:
for(pt = 0; pt<=numsubsegements ; ++pt) {
glBegin(GL_LINE_STRIP);
glVertex3fv(pt.v());
}
glEnd();
is not a good way to draw anything. You MUST have one glEnd() for every single glBegin(). you probably want to get the glBegin() out of the loop. the fact that this works is pure luck.
second thing
My current exploration is using a
'cylinder' quadric to create a tube
along the line
This will not work as you expect. the 'cylinder' quadric has a flat top base and a flat bottom base. Even if you success in making the correct rotations according to the spline the edges of the flat tops are going to pop out of the volume of your intended tube and it will not be smooth. You can try it in 2D with just a pen and a paper. Try to draw a smooth tube using only shorter tubes with a flat bases. This is impossible.
Third, to your actual question, The definitive tool for such rotations are quaternions. Its a bit complex to explain in this scope but you can find plentyful information anywhere you look.
If you'd have used QT instead of FLTK you could have also used libQGLViewer. It has an integrated Quaternion class which would save you the implementation. If you still have a choice I strongly recommend moving to QT.
Have you considered gluLookAt? Put your control point as the eye point, the next point as the reference point, and make the up vector perpendicular to the difference between the two.