So I am drawing a sphere not using the "subdividing icosahedron" approach but using triangle strips and parameteric equation of the sphere.
Here is my code
glBegin(GL_TRIANGLE_SRIP);
for(float i = -PI/2; i < PI/2; i+= 0.01f)
{
temp = i+0.01f;
for(float j = 0; j < 2*PI; j+=0.01f)
{
temp -= 0.01f;
glVertex3f( cx + rad * cos(j) * cos(temp), cy + rad * cos(temp) * sin(j), cz + rad * sin(temp));
temp += 0.01f;
glVertex3f( cx + rad * cos(j) * cos(temp), cy + rad * cos(temp) * sin(j), cz + rad * sin(temp));
}
}
glEnd();
The approach is as followes. Imagine a Circle in the XY plane. This is drawn using the inner loop. Now imagine the XY plane moved above or below in the Z-axis and the radius changed cause it's a sphere. This is done using the outer loop.
The first triangle coordinate is given for the Circle when XY plane is at its initial position. After temp+=0.01f the plane moved up by 0.01 and the second triangle vertex coordinate is given. This is how the strip is calculated.
The problem is if cx = cy = cz = 0 or any low value like 2 or 3 the sphere seems fine. However if I put for e.g cx = 15, cy = 15, cz = -6 the sphere gets deformed. Here is the picture.
If i use GL_POINTS this is what im getting
Sorry a very stupid mistake, I wasn't converting the values i put in glFrustum correctly hence a weird FOV was being generated. Solved the issue now. Thanks
Related
I'm basically trying to create 2D lines based on points from bezier curves.
All the points of the bezier curves are well placed and everything seems in order.
Starting with these points I'm creating 2 other points on the z axis which will be the border of the line :
glm::vec3 p1 = pos[i];
p1.z = p1.z + (size / 2);
glm::vec3 p2 = pos[i];
p2.z = p2.z - (size / 2);
Then I change these points positions by rotating them around the main point :
pm is the mobile point rotating around the fix point pf
glm::vec3 rotP = glm::vec3(0.0f, 0.5f, 0.0f);
float co = cos(angle);
float si = sin(angle);
// CLOCKWISE
rotP.x = (pf.x - pm.x) * co + (pf.z - pm.z) * si + pm.x;
rotP.z = -(pf.x - pm.x) * si + (pf.z - pm.z) * co + pm.z;
angle is the angle between the backward and forward point on the bezier curve :
depForward is x, glm::vec3(1.0f, 0.0f, 0.0f)
glm::vec3 normForwardUnit = normalize(p2 - p1);
float angle = (acos(dot(depForward, normForwardUnit)));
The problem that I get is that the rotations are wrong. Some of my lines are correct but it seems to depend on the orientation of the lines.
not correct example
correct example
I think the problem comes from the format of the rotation but I'm still unable to understand.
I tried to normalize the angle to different ranges :
//0 to 2PI
if (angle < 0) { angle += 2 * PI; }
//-PI to PI
if (angle > PI) { angle -= 2 * PI; }
else if (angle <= -PI) { angle += 2 * PI; }
Other ways to calculate the angle :
float angle = atan2(p2.z - p1.z, p2.x - p1.x);
To rotate the points counter-clockwise :
//COUNTER CLOCKWISE
rotP.x = (pf.x - pm.x) * co - (pf.z - pm.z) * si + pm.x;
rotP.z = (pf.x - pm.x) * si + (pf.z - pm.z) * co + pm.z;
In case anyone needs it, here's the implementation of paddy's approach.
You could use the point between backP and nextP instead of midPoint to place your new points.
backP and nextP being the point before and the point after of the b curve
// VEC FORWARD VECTOR
glm::vec3 forwardVec = normalize(backP - nextP);
//PERPENDICULAR VEC
glm::vec3 perpVec = cross(forwardVec, glm::vec3(0.0f, 1.0f, 0.0f));
perpVec = normalize(perpVec);
//MID POINT
glm::vec3 midP = midPoint(backP, nextP);
// GEN POINTS
glm::vec3 p1 = midP + (width * perpVec);
glm::vec3 p2 = midP - (width * perpVec);
I think you should definately look at this:
Is it possible to express "t" variable from Cubic Bezier Curve equation?
In case you insist on your way you do not need to use any angles nor rotations...
You have line p0,p1 which is sampled from your polynomial curve so:
tangent = p1-p0
However its better to have better approximation of tangent so either take it by 1st derivation of your curve or use 2 consequent lines (p0,p1) , (p1,p2) then tangent at point p1 is:
tangent = p2-p1
For more info see:
How do i verify the gradient at midpoint coordinate which i calculate by using cubic bezire curve equation
Now take bitangent (z axis of your camera which can be extracted from camera matrix) and use cross product to get normal
normal = normalize(cross(tangent,binormal))
now you just displace the p1 by normal:
p1' = p1 + 0.5*curve_thickness*normal
p1'' = p1 - 0.5*curve_thickness*normal
do the same for all points of your curve ... after that you just render quads using p' and p'' points ...
However with this approach you might run into problems that might need further tweaking see:
draw outline for some connected lines
I have a camera set up with the coordinates of 0, 0, 1000 and a cube at 0, 0, 0. There is a camera position vector, rotation vector and target vector.
When finding the target, in 2d space I would use:
newx = cos(angle); // this will be very small so i would multiply it by 100 or something idk
newy = sin(angle); // same and so on
So in 3d space I'm assuming that I would use:
newx = cos(angle);
newy = sin(angle);
newz = tan(angle);
But because I'm using the mouse to find the x and y direction the z rotation is always 0:
float x_diff = (WIDTH/2) - mousePos.x;
x_diff /= WIDTH;
float y_diff = (HEIGHT/2)- mousePos.y;
y_diff /= HEIGHT;
cameraRotation.x += /* too small of a number so multiply by 5 */ 5 * (FOV * x_diff);
cameraRotation.y += 5 * (FOV * y_diff);
cameraRotation.z += ???;
and so the target z will always be 0.
I could be doing this whole thing completely wrong I don't know.
But to sum it, up i need help calculating the cameras target (FOV: 90) for its rotation in 3D space.
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();
I'm using C++, Allegro5, and codeblocks. I'm trying to write a test program before I write a very basic Asteroids knock-off. The only rules are use C++, Allegro, and no sprites or bitmaps (this specifically has to use primitives like lines and shapes).
I'm drawing the shape in quadrant1, redrawing it in quadrant2 translated from a relative origin, redrawing it in three rotated by certain number of degrees, and finally drawing it rescaled in quadrant4.
Parts 1 2 and 4 work fine. My problem is the rotate function. It is not rotating the correct amount, or not rotating at all. At less than 90 it rotates half of the entered degrees. After that it doesn't rotate or doesnt draw at all.
I'll post rotation method code below. I know it's bloated and needs to be cleaned up (I just overhauled some of the logic to fix 1, 2, and 4), but I really need help with rotation.
I think I'm using atan2 correctly and I've turned
void rotation (float degrees)
{
ALLEGRO_COLOR color_black = al_map_rgb(0,0,0);
ALLEGRO_COLOR color_blue = al_map_rgb(150,150,150);
ALLEGRO_COLOR color_orange = al_map_rgb(255,135,135);
ALLEGRO_COLOR color_red = al_map_rgb(255,0,0);
al_clear_to_color(al_map_rgb(255,255,255)); //clear screen to white
//draw black grid
al_draw_line(400,0, 400,600, color_black, 4.0);
al_draw_line(0,300, 800,300, color_black, 4.0);
al_draw_line(200,0, 200,600, color_black, 1.0);
al_draw_line(600,0, 600,600, color_black, 1.0);
al_draw_line(0,150, 800,150, color_black, 1.0);
al_draw_line(0,450, 800,450, color_black, 1.0);
float rx[13], ry[13];
float phi, theta, radius; //phi original angle theta added angle of rotation
float ycenter = 0, xcenter = 0; //later will be used with varying object position
theta = degrees * PI/180.0;
for (int i = 0; i < 13; i++)
{
phi = atan2(yarray[i], xarray[i]);
radius = sqrt(pow((xarray[i]-xcenter),2.0) + pow((yarray[i]-ycenter),2.0));
rx[i] = xarray[i] + radius * cos(phi + theta);
ry[i] = yarray[i] + radius * sin(phi + theta);
}
float x = quad[2][0];
float y = quad[2][1];
al_draw_triangle(x+rx[0],y+ry[0], x+rx[1],y+ry[1], x+rx[2],y+ry[2], color_red, 10);
al_draw_filled_triangle(x+rx[3],y+ry[3], x+rx[4],y+ry[4], x+rx[5],y+ry[5], color_orange);
al_draw_filled_triangle(x+rx[6],y+ry[6], x+rx[7],y+ry[7], x+rx[8],y+ry[8], color_blue); //body
al_draw_filled_triangle(x+rx[9],y+ry[9], x+rx[10],y+ry[10], x+rx[11],y+ry[11],color_blue); //wing
al_draw_filled_ellipse(x+rx[12],y+ry[12], 4, 8, color_black); //cockpit
al_flip_display();
}
I found teh answser after working it all out with paper and LOTS of print statements. I had to remove the xarray and yarray addition for rx and ry. See below.
rx[i] = radius * cos(phi + theta);
ry[i] = radius * sin(phi + theta);
replaces
rx[i] = xarray[i] + radius * cos(phi + theta);
ry[i] = yarray[i] + radius * sin(phi + theta);
I was just wondering how would I go about clipping a circle in a rectangular boundary box? I am currently using the Cohen–Sutherland algorithm for line clipping in my program and so far I've managed to get rectangles and polygons to clip. However, for circle clipping, I have no idea how I would accomplish this. I'm using the following to construct my circle:
glBegin(GL_POLYGON);
double radius = 50;
for(int angle = 0; angle <= 360; angle++ ){
float const curve = 2 * PI * (float)angle / (float)360;
glVertex2f(point.x + sin(curve) * radius, point.y + cos(curve) * radius);
}
glEnd();
My clipping algorithm is the same as the one here: http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm. However, it returns 2 points representing a new line to later be used to draw the clipped shape. So basically I've tried to do this:
line Lines[360] // an array with size 360 with data type line, which is a struct holding two points (x1, y1, x2, y2) of the new line returned by my clipping function.
double radius = 50;
for(int angle = 0; angle < 360; angle++){
float const currentCurve = 2 * PI * (float)angle / (float)360;
float const nextCurve = 2 * PI * (float)(angle+1) / (float)360;
int x1 = (int)(point[i].x + sin(currentCurve) * radius); // point is another struct holding only a single point.
y1 = (int)(point[i].y + cos(currentCurve) * radius);
x2 = (int)(point[i+1].x+ sin(nextCurve) * radius);
y2 = (int)(point[i+1].y + cos(nextCurve) * radius);=
// Clip the points with the clipping algorithm:
Lines[i] = Clipper(x1, y1, x2, y2);
}
// Once all lines have been clipped or not, draw:
glBegin(GL_POLYGON);
for(int i = 0; i < 360; i++){
glVertex2f(Lines[i].x1, Lines[i].y1);
glVertex2f(Lines[i].x2, Lines[i].y2);
}
glEnd();
Note that, I've drawn a circle on the screen with a mouse and and stored each 360 points into a struct array called point, which is apart of a linked list. So I have like 1 node representing one circle on the screen.
Anyway, with the above, my circle is not drawing clipped (or drawing at all for that matter) and my application crashes after a few mouse clicks.
Use the scissor test - read up on glScissor(): http://www.opengl.org/sdk/docs/man/xhtml/glScissor.xml