How to set up (create) sliced cylinder in OpenGL - opengl

How would you create a cylinder such as this?
http://www.eicac.co.uk/Images/SLICED-CYLINDER.png
I am guessing gluCylinder is not an option?

create it with one ribbon and two fans
Lets assume that point [0, 0, 0] is at the center of the shape's base and Z-axis is up. Using constants from the Image.
bottom cap
A simple disc.
glBegin(GL_TRIANGLE_FAN)
glVertex3d(0.0, 0.0, 0.0) // center
for angle from 0 to π (whatever step)
double x = 0.5 * D * cos(angle);
double y = 0.5 * D * sin(angle);
glVertex3d(x, y, 0.0);
glEnd();
side wall
We need to calculate the actual slope function.
It will be of the form y = a * x + b and have points (0.0, H) and (0.5*D, H2).
Thus we have to solve for a and b. We have b = H and a = (H2 - H) / 0.5 * D
double a = (H2 - H) / 0.5 * D;
double b = H;
glBegin(GL_TRIANGLE_STRIP)
for angle from 0 to π (whatever step)
double x = 0.5 * D * cos(angle);
double y = 0.5 * D * sin(angle);
double height = a * x + b;
glVertex3d(x, y, 0.0);
glVertex3d(x, y, height);
glEnd();
top cap
We combine the previous steps and seal the top.
double a = (H2 - H) / 0.5 * D;
double b = H;
glBegin(GL_TRIANGLE_FAN)
glVertex3d(0.0, 0.0, H) // center
for angle from 0 to π (whatever step)
double x = 0.5 * D * cos(angle);
double y = 0.5 * D * sin(angle);
double height = a * x + b;
glVertex3d(x, y, height);
glEnd();

Related

OpenGL semicircular rotation and quarter circle

The following code will create a new semicircular using openGL:
glPointSize(2);
glBegin(GL_POINTS);
for (float i = p; i <= (2 * p); i += 0.001) {
x = 50.0 * cos(i) + 20;
y = 50.0 * sin(i) + 20;
glVertex2f(x, y);
}
glEnd();
Now I want to know how to change this code and create a quarter circle using this format?
Also, is this possible to rotate the shape using this format and without of using GLrotateEF?
Here i is the angle in radians. The loop goes from π to 2π—this is a semicircle (but the second half of it - a bit ill-defined).
To turn it into a quarter circle loop from 0 to π/2. To rotate the circle by x degrees, convert it to radians and add to the angle.
Alternatively you can draw a portion of a circle by simply defining where it should start, and where it should stop, in angles:
double start_angle = 30;
double stop_angle = 30 + 180;
for (double a = start_angle; a <= stop_angle; a += 0.001) {
double a_rad = a / 180.0 * p;
x = 50.0 * cos(a_rad) + 20;
y = 50.0 * sin(a_rad) + 20;
glVertex2f(x, y);
}

How to bevel a stretched rectangle

I am able to bevel the corner of a rectangle.
When i strech the rectangle and than try to bevel it then the result does not look smooth , it should look like the rectangle on the right side.
How do i calculate the points for the trianlgle fan when the rectangle is streched ?
currently this is the way i am calculating the points for the Quarter circle.
std::vector<float> bevelData;
bevelData.push_back(0.0); // First set the centre of the rectangle to the data
bevelData.push_back(0.0);
bevelData.push_back(0.0);
bevelData.push_back(0);
bevelData.push_back(0);
bevelData.push_back(1);
bevelData.push_back(0);
bevelData.push_back(0);
for (int i = 0; i <= segments; ++i) {
float x, y;
float angle = start_angle + 0.5 * M_PI * i / static_cast<float>(segments);
x = circX + cos(angle) * rad; // circX is the centre of the circle as marked in yellow in the first image
y = circY + sin(angle) * rad; // circY is the centre of the circle as marked in yellow in the first image , rad is the radius of the circle
bevelData.push_back(x);
bevelData.push_back(y);
bevelData.push_back(0.0);
bevelData.push_back(0);
bevelData.push_back(0);
bevelData.push_back(1);
bevelData.push_back(0);
bevelData.push_back(0);
}
After applying soultion this is the result i get.
//Bevel Bottom Right
float rightWidthBottom = (width / 2) - rightBottomBevel;
float rightHeightBottom = (height / 2) - rightBottomBevel;
std::vector<float> bottomRightBevelData = draw_bevel(rightWidthBottom, rightHeightBottom, rightBottomBevel, 1, -1, iSegmentsRightBottom);
std::vector<float> SuperRectangle::draw_bevel(float p_x, float p_y, float rad, int dir_x, int dir_y , int segments)
{
std::vector<float> bevelData;
float c_x, c_y; // the center of the circle
float start_angle; // the angle where to start the arc
bevelData.push_back(0.0);
bevelData.push_back(0.0);
bevelData.push_back(0.0);
bevelData.push_back(0);
bevelData.push_back(0);
bevelData.push_back(1);
bevelData.push_back(0);
bevelData.push_back(0);
c_x = p_x * dir_x;
c_y = p_y * dir_y;
if (dir_x == 1 && dir_y == 1)
start_angle = 0.0;
else if (dir_x == 1 && dir_y == -1)
start_angle = -M_PI * 0.5f;
else if (dir_x == -1 && dir_y == 1)
start_angle = M_PI * 0.5f;
else if (dir_x == -1 && dir_y == -1)
start_angle = M_PI;
for (int i = 0; i <= segments; ++i) {
float x, y;
float angle = start_angle + 0.5 * M_PI * i / static_cast<float>(segments);
x = c_x + cos(angle) * rad;
y = c_y + sin(angle) * rad;
float fscale = (y / (float)(height / 2.0f));
x = (x + (strech * fscale));
bevelData.push_back(x);
bevelData.push_back(y);
bevelData.push_back(0.0);
bevelData.push_back(0);
bevelData.push_back(0);
bevelData.push_back(1);
bevelData.push_back(0);
bevelData.push_back(0);
}
return bevelData;
}
//////////////////////////////////////////////////////////////////
float xWidth = width / 2;
float yHeight = height / 2;
float TriangleRight[] = {
// positions // Normals // Texture Coord
0.0f , 0.0f , 0.0f , 0.0f,0.0,1.0, 0.0,0.0,
xWidth + strech , yHeight - rightTopBevel,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
xWidth - strech , -yHeight + rightBottomBevel,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
};
float TriangleLeft[] = {
// positions
0.0f , 0.0f , 0.0f , 0.0f,0.0,1.0, 0.0,0.0,
-xWidth + strech , yHeight - leftTopBevel ,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
-xWidth - strech , -yHeight + leftBottomBevel,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
};
float TriangleTop[] = {
// positions
0.0f , 0.0f , 0.0f , 0.0f,0.0,1.0, 0.0,0.0,
xWidth - rightTopBevel + strech , yHeight ,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
-xWidth + leftTopBevel + strech , yHeight,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
};
float TriangleBottom[] = {
// positions
0.0f , 0.0f , 0.0f , 0.0f,0.0,1.0, 0.0,0.0,
xWidth - rightBottomBevel - strech , -yHeight ,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
-xWidth + leftBottomBevel - strech , -yHeight,0.0f, 0.0f,0.0,1.0 , 0.0,0.0,
};
You've a rectangle with a width w and a height h
(-w/2, h/2) (w/2, h/2)
+----------------+
| |
| |
| |
| |
+----------------+
(-w/2, -h/2) (w/2, -h/2)
The points for the rounded corner of the rectangle are calculated by:
x = circX + cos(angle) * rad;
y = circY + sin(angle) * rad;
Then the rectangle is displaced by d. At the top d is add to the x component of the corner points and at the bottom d is subtracted from the x component of the corner points:
(-w/2 + d, h/2) (w/2 + d, h/2)
+----------------+
/ /
/ /
/ /
/ /
+----------------+
(-w/2 - d, -h/2) (w/2 - d, -h/2)
You have to apply the displacement d to the points along the arc, too. The displacement has to be scaled, in relation to the y coordinate of the point.
Points near the bottom edge have to be displaced by a larger scale, than points near the center of the left edge:
x = circX + cos(angle) * rad
y = circY + sin(angle) * rad
scale = y / (h/2)
x = x - d * scale

Rotation: Quaternion to matrix

I am trying to display a 360 panorama using an IMU for head tracking.
Yaw works correctly but the roll and pitch are reverse. I also notice that the pitch contains some roll (and maybe vice-versa).
I am receiving (W, X, Y, Z) coordinate from the IMU that I am storing in an array as X, Y, Z, W.
The next step is converting the quaternion to a rotation matrix. I have looked at many examples, and can't seem to find anything wrong with the following code:
static GLfloat rotation[16];
// Quaternion (x, y, z, w)
static void quaternionToRotation(float* quaternion)
{
// Normalize quaternion
float magnitude = sqrt(quaternion[0] * quaternion[0] +
quaternion[1] * quaternion[1] +
quaternion[2] * quaternion[2] +
quaternion[3] * quaternion[3]);
for (int i = 0; i < 4; ++i)
{
quaternion[i] /= magnitude;
}
double xx = quaternion[0] * quaternion[0], xy = quaternion[0] * quaternion[1],
xz = quaternion[0] * quaternion[2], xw = quaternion[0] * quaternion[3];
double yy = quaternion[1] * quaternion[1], yz = quaternion[1] * quaternion[2],
yw = quaternion[1] * quaternion[3];
double zz = quaternion[2] * quaternion[2], zw = quaternion[2] * quaternion[3];
// Column major order
rotation[0] = 1.0f - 2.0f * (yy + zz);
rotation[1] = 2.0f * (xy - zw);
rotation[2] = 2.0f * (xz + yw);
rotation[3] = 0;
rotation[4] = 2.0f * (xy + zw);
rotation[5] = 1.0f - 2.0f * (xx + zz);
rotation[6] = 2.0f * (yz - xw);
rotation[7] = 0;
rotation[8] = 2.0f * (xz - yw);
rotation[9] = 2.0f * (yz + xw);
rotation[10] = 1.0f - 2.0f * (xx + yy);
rotation[11] = 0;
rotation[12] = 0;
rotation[13] = 0;
rotation[14] = 0;
rotation[15] = 1;
}
The rotation matrix is then used in the draw call as such:
static void draw()
{
// Get IMU quaternion
float* quaternion = tracker.getTrackingData();
if (quaternion != NULL)
{
quaternionToRotation(quaternion);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
// TODO: Multiply initialRotation quaternion with IMU quaternion
glMultMatrixf(initialRotation); // Initial rotation to point forward
glMultMatrixf(rotation); // Rotation based on IMU
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
gluSphere(quad, 0.1, 50, 50);
glBindTexture(GL_TEXTURE_2D, 0);
glPopMatrix();
glFlush();
glutSwapBuffers();
}
I tried to set all but one fields in the quaternion to 0, and I notice that they all work individually, except roll and pitch is swapped around. I tried swapping X and Y but this does not seem to help.
Any help would be really appreciated. Please let me know as well if you have any steps that can let me debug my issue. Thanks!

Texture mapping a circle made using GL_POLYGON

I am trying to map a texture to a circle using GL_POLYGON using this code:
void drawCircleOutline(Circle c, int textureindex)
{
float angle, radian, x, y; // values needed by drawCircleOutline
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureLib[textureindex]);
glBegin(GL_POLYGON);
for (angle=0.0; angle<360.0; angle+=2.0)
{
radian = angle * (pi/180.0f);
x = (float)cos(radian) * c.r + c.pos.x;
y = (float)sin(radian) * c.r + c.pos.y;
glTexCoord2f(x, y);
glVertex2f(x, y);
}
glEnd();
glDisable(GL_TEXTURE_2D);
}
it looks like this when running.
And should look like this:
Try:
radian = angle * (pi/180.0f);
xcos = (float)cos(radian);
ysin = (float)sin(radian);
x = xcos * c.r + c.pos.x;
y = ysin * c.r + c.pos.y;
tx = xcos * 0.5 + 0.5;
ty = ysin * 0.5 + 0.5;
glTexCoord2f(tx, ty);
glVertex2f(x, y);

Efficient way to draw Ellipse with OpenGL or D3D

There is a fast way to draw circle like this
void DrawCircle(float cx, float cy, float r, int num_segments)
{
float theta = 2 * 3.1415926 / float(num_segments);
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = r;//we start at angle = 0
float y = 0;
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x + cx, y + cy);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
I am wondering if there is a similar way to draw ellipse where its major/minor axes vector and size are both known.
If we take your example we can use an internal radius of 1 and apply horizontal/vertical radius separately in order to get an ellipse:
void DrawEllipse(float cx, float cy, float rx, float ry, int num_segments)
{
float theta = 2 * 3.1415926 / float(num_segments);
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = 1;//we start at angle = 0
float y = 0;
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
//apply radius and offset
glVertex2f(x * rx + cx, y * ry + cy);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
There is no way to draw a curve in openGL, just a lot of straight lines. But if you used vertex buffer objects then you won't have to send each vertex to the graphics card which will be much faster.
My Java Example
If the ellipse is ((x-cx)/a)^2 + ((y-cy)/b)^2 = 1 then change the glVertex2f call to
glVertext2d(a*x + cx, b*y + cy);
To simplify the sums, lets suppose for a while that the ellipse is centred at the origin.
If the ellipse is rotated so that the semi-major axis (of length a) makes an angle theta with the x axis, then the ellipse is the set of points p so that p' * inv(C) * p = 1, where C is the matrix R(theta) * D * R(theta)' where ' denotes transpose and D is the diagonal matrix with entries a*a,b*b (b the length of the semi-minor axis). If L is the cholesky factor (eg here) of C then the ellipse is the set of points p so that (inv(L) * p)'*(inv(L) *p ) = 1, so that L maps the unit circle to the ellipse. If we have computed L as ( u 0 ; v w) (just once, before the loop) then the glVertexf call becomes glVertex2f( u*x + cx, v*x + w*y + cy);
L can be calculated like this (where C is cos(theta) and S is sin(theta)):
u = sqrt( C*C*a*a + S*S*b*b); v = C*S*(a*a-b*b); w = a*b/u;