I have a function that draws a circle.
glBegin(GL_LINE_LOOP);
for(int i = 0; i < 20; i++)
{
float theta = 2.0f * 3.1415926f * float(i) / float(20);//get the current angle
float rad_x = ratio*(radius * cosf(theta));//calculate the x component
float rad_y = radius * sinf(theta);//calculate the y component
glVertex2f(x + rad_x, y + rad_y);//output vertex
}
glEnd();
This works dandy. I save the x, y and radius values in my object.
However when I try and draw a square with the following function call:
newSquare(id, red, green, blue, x, (x + radius), y, (y + radius));
I get the following image.
As you see, the square is nearly double as wide (looks more like the diameter). The following code is how I create my square box. As you can see it starts in the center of the circle in which it should. And should stretch out to the edge of the circle.
glBegin(GL_QUADS);
glVertex2f(x2, y2);
glVertex2f(x2, y1);
glVertex2f(x1, y1);
glVertex2f(x1, y2);
glEnd();
I can't seem to understand why this is!
If you're correcting the x-position for one object, you have to do it for all others as well.
However, if you continue this, you'll get into trouble very soon. In your case, only the width of objects is corrected but not their positions. You can solve all your problems by setting an orthographic projection matrix and you won't ever need to correct positions again. E.g. like so:
glMatrixMode(GL_PROJECTION); //switch to projection matrix
glOrtho(-ratio, ratio, -1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW); //switch back to model view
where
ratio = windo width / window height
This constructs a coordinate system where the top edge has y=1, the bottom edge y=-1 and the left and right sides have x=-ratio and x=ratio, respectively.
Related
I am having trouble rotating an ellipse in OpenGL. So, I have some code to draw an ellipse as follows:
glPushAttrib(GL_CURRENT_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
glPushMatrix();
glTranslatef(0, 0, 0); // ellipse centre
glBegin(GL_LINE_LOOP);
float inc = (float) M_PI / 500.0;
for (GLfloat i = 0; i < M_PI * 2; i+=inc)
{
float x = cos(i) * 0.4;
float y = sin(i) * 0.4;
glVertex2f(x, y);
}
glEnd();
glPopMatrix();
glPopAttrib();
This produces a picture as so:
Now what I want to do is rotate this ellipse clockwise. So I added a glrotate in between but the result was not what I had expected.
So, I did something like:
glPushAttrib(GL_CURRENT_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
glPushMatrix();
glTranslatef(0, 0, 0);
glRotatef(-90, 1, 1, 0);
glBegin(GL_LINE_LOOP);
float inc = (float) M_PI / 500.0;
for (GLfloat i = 0; i < M_PI * 2; i+=inc)
{
float x = cos(i) * 0.4;
float y = sin(i) * 0.4;
glVertex2f(x, y);
}
glEnd();
glPopMatrix();
glPopAttrib();
This produced an image which was simply collapsed. What I wanted to do was rotate the ellipse along its center by the specified degrees. Also, I tried playing around with the various parameters of glRotatef but could not get it do as I expected. The resulting image looks like:
You're working in the XY plane, so you can't really rotate around a vector in XY. Instead, you want to rotate along the unit Z axis (glRotate (angle, 0, 0, 1);). Imagine your screen being the XY coordinate system and the Z axis pointing inwards. What you want is to rotate around the Z axis, so your XY plane remains in the XY plane.
I'm trying to draw only a sector/part of a circle, but currently I always get a full circle.
I use this to draw a circle:
glColor3f (0.25, 1.0, 0.25);
GLfloat angle, raioX=0.3f, raioY=0.3f;
GLfloat circle_points = 100.0f;
glBegin(GL_LINE_LOOP);
for (int i = 0; i < circle_points; i++) {
angle = 2*PI*i/circle_points;
glVertex2f(0.5+cos(angle)*raioX, 0.5+sin(angle)*raioY);
}
glEnd();
Assuming you want a sector as illustrated in the following diagram:
You will need to re-write your code this way:
glBegin (GL_LINE_LOOP);
glVertex2f (0.5f, 0.5f);
for (int i = 0; i < circle_points; i++) {
angle = 2*PI*i/circle_points;
glVertex2f (0.5+cos(angle)*raioX, 0.5+sin(angle)*raioY);
}
glEnd ();
The only thing I changed was the addition of the point 0.5,0.5 at the center of your circle. WIthout that point, you wind up drawing a segment instead of a sector.
As BDL points out, your original code drew a full circle. Your angle for 1/4 of a circle should be Pi/2 rather than 2*Pi. So at minimum, you would also need to re-write this line:
angle = PI * 0.5f * i / circle_points;
BDL's answer shows a more efficient approach to this. Though it draws an arc, which may or may not be what you want. Either way, you have enough code now to draw all three things in the diagram above.
The code you will see frequently using a cos() and sin() call for each point is correct, but very inefficient. Those are fairly expensive functions, and it's easy to write the code so that they are only needed once.
The idea is that you obtain each point from the previous point by rotating it by the angle increment. The rotation itself can be performed by a 2x2 transformation matrix. This reduced the calculation of each point to a few additions and multiplications.
The code will then look something like this:
// Calculate angle increment from point to point, and its cos/sin.
float angInc = 0.5f * PI / (circle_points - 1.0f);
float cosInc = cos(angInc);
float sinInc = sin(angInc);
// Start with vector (1.0f, 0.0f), ...
float xc = 1.0f;
float yc = 0.0f;
// ... and then rotate it by angInc for each point.
glBegin(GL_LINE_LOOP);
for (int i = 0; i < circle_points; i++) {
glVertex2f(0.5f + xc, 0.5f + yc);
float xcNew = cosInc * xc - sinInc * yc;
yc = sinInc * xc + cosInc * yc;
xc = xcNew;
}
glEnd();
As a subtle detail, note that if you want to draw a quarter circle with circle_points points, including the start and end point, you need to divide the angle range by circle_points - 1 to obtain the angle increment. It's the thing with the number of fence posts and number of gaps between them...
This will draw a circle segment. Andon already elaborated on the difference between a segment and a sector.
The above shared code with my own answer here: https://stackoverflow.com/a/25321141/3530129, which shows how to draw a circle with modern OpenGL.
When drawing a fraction of a circle, one needs to limit the angle in which the points should be placed. circle_points defines then in how many subparts this circle arc should be devided. In addition (and as pointed out by #Andon M. Coleman) using a GL_LINE_LOOP might not be the correct choice, since it will always close the line from the last to the first point.
You're code could be modified somehow like this:
glColor3f (0.25, 1.0, 0.25);
GLfloat angle, raioX=0.3f, raioY=0.3f;
GLfloat circle_points = 100;
GLfloat circle_angle = PI / 2.0f;
glBegin(GL_LINE_STRIP);
for (int i = 0; i <= circle_points; i++) {
GLfloat current_angle = circle_angle*i/circle_points;
glVertex2f(0.5+cos(current_angle)*raioX, 0.5+sin(current_angle)*raioY);
}
glEnd();
here is my display method:
void display()
{
GLfloat sphere_vertices[3]={0.0,0.0,0.0};
int theta,phi;
float x,y,z;
int off_set;
off_set=5;
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
for (theta=-90; theta<=90-off_set; theta+=off_set) {
for (phi=0; phi<=360-off_set; phi+=off_set)
{
//calculate X of sphere
x= cos(theta + off_set) * sin(phi + off_set);
//calculate Y of sphere
y = cos(theta + off_set) * cos(theta + off_set);
//calculate Z of sphere
z = sin(theta + off_set);
//store vertices
sphere_vertices[0]=x;
sphere_vertices[1]=y;
sphere_vertices[2]=z;
//plot new point
glVertex3fv(sphere_vertices);
printf("X is %f, Y is %f, Z is %f", x,y,z);
}
}
glEnd();
glFlush();
}
I am calculating the points on the surface of a sphere and then plotting each point. But the only thing I get are some pixel at the bottom-left corner of the screen
It seems like you are trying to render a sphere with radius of 1.0 consisting of about 180 / off_set slices of circles with 360 / off_set points. How did you come up with your x, y and z?
For each point, you could construct a unit length vector on, for example, the xy-plane from theta and then rotate it about the z-axis by phi and scale the resulting vector by the radius of the sphere.
After reviewing your math, make sure you have specified the model-view and projection matrices and note if you are using the standard cos/sin functions, they take radians, not degrees.
I have a quad on the y = -50 plane. At the moment, all I want to do is obtain the coordinates of a mouse click on the quad. I've managed to do this to a limited extent. The problem is that the transformations I applied when drawing the quad aren't accounted for. I can add in some constants and make it work, but I let the user rotate the scene about the x and y axes with glRotatef(), so the coordinates get messed up as soon as a rotation happens.
Here's what I'm doing now:
I call gluUnProject() twice, once with z = 0, and once with z = 1.
gluUnProject( mouseX, WINDOW_HEIGHT - mouseY, 0, modelView, projection, viewport, &x1, &y1, &z1);
gluUnProject( mouseX, WINDOW_HEIGHT - mouseY, 1, modelView, projection, viewport, &x2, &y2, &z2);
Normalized ray vector:
x = x2 - x1;
y = y2 - y1;
z = z2 - z1;
mag = sqrt(x*x + y*y + z*z);
x /= mag;
y /= mag;
z /= mag;
Parametric equation:
float t = -(camY) / y;
planeX = camX + t*x;
planeY = camY + t*y;
planeZ = camZ + t*z;
where (camX, camY, camZ) is the camera position passed to gluLookAt().
I want planeX, planeY, and planeZ to be the coordinates of the click on the quad, in the same coordinate system I used to draw the quad. How can I achieve this?
You are not supposed to pass in an explicit z-depth of your choosing. In order to find the world coordinate, you need to pass in the depth buffer value at that particular mouse coordinate.
GLfloat depth;
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
Passing that into your gluUnProject should yield the values you are looking for. Plus, as genpfault said in his comment, make sure you are grabbing the model view matrix data at the right moment. Otherwise, you have the wrong matrix.
I want to know how to draw a spiral.
I wrote this code:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT);
GLfloat x,y,z = -50,angle;
glBegin(GL_POINTS);
for(angle = 0; angle < 360; angle += 1)
{
x = 50 * cos(angle);
y = 50 * sin(angle);
glVertex3f(x,y,z);
z+=1;
}
glEnd();
glutSwapBuffers();
}
If I don't include the z terms I get a perfect circle but when I include z, then I get 3 dots that's it. What might have happened?
I set the viewport using glviewport(0,0,w,h)
To include z should i do anything to set viewport in z direction?
You see points because you are drawing points with glBegin(GL_POINTS).
Try replacing it by glBegin(GL_LINE_STRIP).
NOTE: when you saw the circle you also drew only points, but drawn close enough to appear as a connected circle.
Also, you may have not setup the depth buffer to accept values in the range z = [-50, 310] that you use. These arguments should be provided as zNear and zFar clipping planes in your gluPerspective, glOrtho() or glFrustum() call.
NOTE: this would explain why with z value you only see a few points: the other points are clipped because they are outside the z-buffer range.
UPDATE AFTER YOU HAVE SHOWN YOUR CODE:
glOrtho(-100*aspectratio,100*aspectratio,-100,100,1,-1); would only allow z-values in the [-1, 1] range, which is why only the three points with z = -1, z = 0 and z = 1 will be drawn (thus 3 points).
Finally, you're probably viewing the spiral from the top, looking directly in the direction of the rotation axis. If you are not using a perspective projection (but an isometric one), the spiral will still show up as a circle. You might want to change your view with gluLookAt().
EXAMPLE OF SETTING UP PERSPECTIVE
The following code is taken from the excellent OpenGL tutorials by NeHe:
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
Then, in your draw loop would look something like this:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity();
glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
glBegin(GL_TRIANGLES); // Drawing Using Triangles
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd();
Of course, you should alter this example code your needs.
catchmeifyoutry provides a perfectly capable method, but will not draw a spatially accurate 3D spiral, as any render call using a GL_LINE primitive type will rasterize to fixed pixel width. This means that as you change your perspective / view, the lines will not change width. In order to accomplish this, use a geometry shader in combination with GL_LINE_STRIP_ADJACENCY to create 3D geometry that can be rasterized like any other 3D geometry. (This does require that you use the post fixed-function pipeline however)
I recommended you to try catchmeifyoutry's method first as it will be much simpler. If you are not satisfied, try the method I described. You can use the following post as guidance:
http://prideout.net/blog/?tag=opengl-tron
Here is my Spiral function in C. The points are saved into a list which can be easily drawn by OpenGL (e.g. connect adjacent points in list with GL_LINES).
cx,cy ... spiral centre x and y coordinates
r ... max spiral radius
num_segments ... number of segments the spiral will have
SOME_LIST* UniformSpiralPoints(float cx, float cy, float r, int num_segments)
{
SOME_LIST *sl = newSomeList();
int i;
for(i = 0; i < num_segments; i++)
{
float theta = 2.0f * 3.1415926f * i / num_segments; //the current angle
float x = (r/num_segments)*i * cosf(theta); //the x component
float y = (r/num_segments)*i * sinf(theta); //the y component
//add (x + cx, y + cy) to list sl
}
return sl;
}
An example image with r = 1, num_segments = 1024:
P.S. There is difference in using cos(double) and cosf(float).
You use a float variable for a double function cos.