OpenGL Rotate an Object around It's Local Axes - c

Imagine a 3D rectangle at origin. It is first rotated along Y-axis. So good so far. Now, it is rotated around X-axis. However, OpenGL (API: glrotatef) interprets the X-axis to be the global X-axis. How can I ensure that the "axes move with the object"?
This is very much like an airplane. For example, if yaw (Y rotation) is applied first, and then pitch (X-rotation), a correct pitch would be X-rotation along the plane's local axes.
EDIT: I have seen this called gimbal lock problem, but I don't think it is though.

You cannot consistently describe an aeroplane's orientation as one x rotation and one y rotation. Not even if you also store and one z rotation. That's exactly the gimbal lock problem.
The crux of it is that you have to apply the rotations in some order. Say it's x then y then z for the sake of argument. Then what happens if the x rotation is by 90 degrees? That folds the y axis onto where the z axis was. Then say the y rotation is also by 90 degrees. That's now bent the z axis onto where the x axis was. So now what effect does any z rotation have?
That's just an easy to grasp example. It's not a special case. You can't wave your hands out of it by saying "oh, I'll detect when to do z rotations first" or "I'll do 90 degree rotations with a special pathway" or any other little hack. Trying to store and update orientations as three independent scalars doesn't work.
In classic OpenGL, a call to glRotatef means "... and then rotate the current matrix like this". It's not relative to world coordinates or to model coordinates or to any other space that you're thinking in.

Related

Most efficient way to determine circle coordinates?

I am making a function for drawing a circle in 2d space.
For this, I have identified 2 approaches:
go through all the possible pixels and run them through a formula that will return a value that shows whether the pixel coordinates are inside the circle, outside (bonus: or intersecting it)
get all the circle pixels (basically draw the circle)
I tried to look at some math sources, but I have met with some problems:
in the second approach, the resolution at which I am incrementing the angle matters, so if it is too little, or radius is too small, there will be unnecessary duplication. On the other hand, if the angle gets incremented by more, or radius is too large, there will be gaps.
The formula I was using is:
struct vec2{int x; int y;};
void get_circle(int x, int y, int r, int angle, struct vec2 *coordinates) {
coordiantes->x = x + r * cos(angle);
coordinates->y = y + r * sin(angle);
}
This is obviously a bit much to run a lot of times.
I also want to make some kind of primitive anti-aliasing, so if I can get a value where a pixel only intersects the circle line by a half, it would be drawn as a half-pixel.
My final goal is to draw a nice circle with a line that can be thick. The thickness can be achieved with the area approach where I fill all pixels in a circle area, and then I remove pixels in the inner circle. Or it can be several iterations of the circle. I didn't write the array part of the computation, but yes, I would like each pixel identified. If we take a pixel as a rectangle, then I would like no pixel to be drawn if the theoretical circle goes through <33% of the surface, half-pixel 33-66, and full if >66%.
Please advise. I need some approach that will be computationally efficient.
First, "most efficient" depends on quite a few things. For most modern OpenGL systems you can usually get away with just computing points around the circumference using sine and cosine (and an appropriate aspect scale) with the native floating-point type, then plotting the points using any decent polyline algorithm.
Once you have things working, profile.
If profiling shows your algorithm to be holding things up (and compared to other normal and common computations, it shouldn't be), only then should you spend time and effort on trickier (read: more complicated) stuff, like the Midpoint Circle Algorithm to generate points to send to your polyline.
Also, don't forget to memoize into a sprite or texture or pixmap or whatever is appropriate for your hardware/software IFF profiling shows a worthwhile improvement.

Rotate Camera in the Direction behind object in OpenGL

I'm making a game in OpenGL, using freeglut.
I have a car, which I am able to move back and forward using keys and the camera follows it. Now, when I turn the car(glRotate in xz plane), I want the camera to change the Camera position(using gluLookAt) so it always points to the back of the car.
Any suggestions how do I do that?
For camera follow I use the object transform matrix
get object transform matrix
camera=object
use glGetMatrix or whatever for that
shift rotate the position so Z axis is directing where you want to look
I use object aligned to forward on Z axis, but not all mesh models are like this so rotate by (+/-)90 deg around x,y or z to match this:
Z-axis is forward (or backward depends on your projection matrix and depth function)
X-axis is Right
Y-axis is Up
with respect to your camera/screen coordinate system (projection matrix). Then translate to behind position
apply POV rotation (optional)
if you can slightly rotate camera view from forward direction (mouse look) then do it at this step
camera*=rotation_POV
convert matrix to camera
camera matrix is usually inverse of the coordinate system matrix it represents so:
camera=Inverse(camera)
For more info look here understanding transform matrices the OpenGL inverse matrix computation in C++ is included there.

OpenGL: How do I avoid rounding errors when specifying UV co-ordinates

I'm writing a 2D game using OpenGL. When I want to blit part of a texture as a sprite I use glTexCoord2f(u, v) to specify the UV co-ordinates, with u and v calculated like this:
GLfloat u = (GLfloat)xpos_in_texture/(GLfloat)width_of_texture;
GLfloat v = (GLfloat)ypos_in_texture/(GLfloat)height_of_texture;
This works perfectly most of the time, except when I use glScale to zoom the game in or out. Then floating point rounding errors cause some pixels to be drawn one to the right of or one below the intended rectangle within the texture.
What can be done about this? At the moment I'm subtracting an 'epsilon' value from the right and bottom edges of the rectangle, and it seems to work but this seems like a horrible kludge. Are there any better solutions?
Your issue is most likely not coming from rounding errors, but a misunderstanding on how OpenGL maps texels to pixels. If you notice off-by-one errors, it's probably because your UVs, your vertex positions or your projection matrix/viewport pair are not aligned to where they ought to be.
To simplify, I'll just talk about 1D, and be assuming you use a projection and a viewport that map X,Y coordinates to the equivalent pixel location (i.e. a glOrtho(0,width,0,height,zmin,zmax) and a glViewport(0,width,0,height).
Say you want to draw 5 texels (starting at 0 for simplicity) of your 64-wide texture showing on the 10 pixels (scale of 2) of your screen starting at pixel 20.
To get there, draw the triangle with X coordinates 20 and 30, and U (of the UV pair) of 10/64 and 15/64. The rasterization of OpenGL will generate 10 pixels to shade, with X coordinates 20.5, 21.5, ... 29.5. Note that the positions are not full integers. OpenGL rasterizes in the middle of the pixel.
Likewise, it will generate U coordinates of 10.25/64, 10.75/64, 11.25/64, 11.75/64 ... 14.25/64, 14.75/64. Note again that texel coordinates, brought back to texel positions in the texture space, are not full integers. OpenGL samples from the middle of texel locations, so this is fine.
How the samplers use these UVs to generate texel values depend on filtering modes, but be it nearest or linear, the pixels should be contained solely inside the texels of interest (0.25 with a size of 0.5 should only use color from 0 to 0.5, which is all inside the first texel).
In general, if you follow the general principles I laid out, you should never see artifacts.
Use Ortho and Viewport of exactly your frame buffer size
Use positions of X, X+width exactly
Use UVs that correspond to exactly the texels you want (if you want the 10 texels starting from the texel 0, use U=0 to U=10.
If you ever have a -1 somewhere in your math, it's likely not correct (for position or UVs).
To get back to your example, it's unclear how you link the uvs you compute to positions (since you don't show the position computation).
It's also unclear how you got xpos_in_texture (you should explain how you computed them for the corners of your sprite). My guess is that you computed that wrong.
A bit late, but for posterity I was having the same problem, with the pixels from adjacent regions of a texture atlas bleeding into sprites/tiles when scaling or zooming the view. I had my glOrtho, glViewport, etc dimensions all set correctly, then I realized the problem was I was scaling the view before translating the camera, which meant that even though I was snapping to integer pixels pre-zoom, after the zoom it would align to a fraction of a pixel and introduce the texel problem.
So if your code looks something like this, where camera.zoom is a non-integer (i.e. 0.75):
glScalef(camera.zoom, camera.zoom, 1.0f);
glTranslatef(camera.x, camera.y, 0.0f);
You'll want to make sure the result of the translation after scaling aligns to whole pixels on the screen, so you can do something like:
glScalef(camera.zoom, camera.zoom, 1.0f);
glTranslatef(
floor(camera.x * camera.zoom) / camera.zoom,
floor(camera.y * camera.zoom) / camera.zoom,
0.0f);
Do the division as a double, round the result down yourself to the desired level of precision, then cast it to GLFloat.
Your xpos/ypos must be based on 0 to (width or height) - 1 and then:
GLfloat u = (GLfloat)xpos_in_texture/(GLfloat)(width_of_texture - 1);
GLfloat v = (GLfloat)ypos_in_texture/(GLfloat)(height_of_texture - 1);

Pathfinding Algorithm for Robot

I have a robot that uses an optical mouse as a position track. Basically, as the robot moves it is able to track change in X and Y directions using the mouse. The mouse also tracks which direction you are moving - ie negative X or positive X. These values are summed into separate X and Y registers.
Now, the robot rotates in place and moves forward only. So the movement of the robot is ideally in straight lines (although the mouse tracking can pickup deviations if you veer off) at particular angles. A particular set of movements of the robot would be like:
A: Rotate 45 degrees, move 3 inches
B: Rotate 90 degrees, move 10 inches
C: Rotate -110 degrees, move 5 inches
D: Rotate 10 degrees, move 1 inch
But each time the mouse X and mouse Y registers give the real distances you moved in each direction.
Now, if I want to repeat the movement set going from A to D only, how can I do this using the information I have already gathered. I know I can basically sum all the angles and distances I feed into it already, but this would prove to be inaccurate if there were large errors in each movement orders. How can I use the raw information from my mouse? A friend provided an idea that I could continuously sine and cosine the mouse values and calculate the final vector but I'm not really sure how this would work.
The problem is that the mouse only gives relative readings so rotating or moving backwards, you are potentially erasing information. So yeah, what I am wondering is how you can implement the algorithm so it can continually track changes to give you a shortest path if you moved in zigzags to get there originally.
I think the basic algorithm you need to do is this:
currentX = currentY = 0;
heading = 0; // radians
while (true)
{
deltas = SampleMouseDeltas();
heading += deltas.Heading;
currentX += Math.Cos(heading) * deltas.Distance;
currentY += Math.Sin(heading) * deltas.Distance;
}
You are right in your idea that this won't be precise. It is called "dead reckoning" for a reason.
Where you can get your deltas.Heading based on the "X" coordinate (the formula will be (deltax in inches) / (mouse sensor distance in inches from center of rotation). Also, the deltas.Distance would come from the "Y" sensor, after you convert it from pixels to inches.
Then to perform the steps, you could do something like:
robot.RotateLeft();
heading = 0;
while (heading < 45 degrees)
heading += SampleMouseDeltas.Heading;
robot.StopRotateLeft();
... etc ...
Not an answer to your question, but perhaps a cautionary tale...
I did exactly this kind of robot as a school project a year back. It was an utter failure, though I learnt quite a bit while doing it.
As for using the mouse for tracking how far you have driven: It did not work well for us at all, or any of the other groups. Probably because the camera in the mouse was out of focus due to the fact that we needed to have the mouse a few mm above the floor. The following year no group doing the same project used this methid. They instead put markings on the weels and used a simple ir-sensor to calculate how many revolutions the wheels made.
I know I'm somewhat necroing this thread, but if you wanted more accurate angle tracking, two optical mice would be ideal. Basically if you cancelled out the motion in the same direction, you would be left with the motion that the mice made relative to eachother. From there, it would just be some simple math to accurately determine how far the 'bot has turned.

Finding center of 2D triangle?

I've been given a struct for a 2D triangle with x and y coordinates, a rotation variable, and so on. From the point created by those x and y coordinates, I am supposed to draw a triangle around the point and rotate it appropriately using the rotation variable.
I'm familiar with drawing triangles in OpenGl with GL_TRIANGLES. My problem is somehow extracting the middle of a triangle and drawing the vertices around it.
edit: Yes, what I am looking for is the centroid.
There are different "types" of centers of a triangle. Details on: The Centers of a Triangle. A quick method for finding a center of a triangle is to average all your point's coordinates. For example:
GLfloat centerX = (tri[0].x + tri[1].x + tri[2].x) / 3;
GLfloat centerY = (tri[0].y + tri[1].y + tri[2].y) / 3;
When you find the center, you will need to rotate your triangle about the center. To do this, translate so that the center is now at (0, 0). Perform your rotation. Now reverse the translation you performed earlier.
I guess you mean the centroid of the triangle!?
This can be easily computed by 1/3(A + B + C) where A, B and C are the respective points of the triangle.
If you have your points, you can simply multiply them by your rotation matrix as usual. Hope i got you right.
There are several points in a triangle that can be considered to be its center (orthocenter, centroid, etc.). This section of the Wikipedia article on triangles has more information. Just look at the pictures to get a quick overview.
By "middle" do you mean "centroid", a.k.a. the center of gravity if it were a 3D object of constant thickness and density?
If so, then pick two points, and find the midpoint between them. Then take this midpoint and the third point, and find the point 1/3 of the way between them (closer to the midpoint). That's your centroid. I'm not doing the math for you.

Resources