OpenGL Glut C - want to render curved cylinder - c

The following code shows a straight cylinder/pipe in OpenGL C language.
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
#define PI 3.1415927
void draw_cylinder(GLfloat radius, GLfloat height, GLubyte R, GLubyte G, GLubyte B)
{
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat angle = 0.0;
GLfloat angle_stepsize = 0.1;
// Draw the tube
glColor3ub(R-40,G-40,B-40);
glBegin(GL_QUAD_STRIP);
angle = 0.0;
while( angle < 2*PI ) {
x = radius * cos(angle);
y = radius * sin(angle);
glVertex3f(x, y , height);
glVertex3f(x, y , 0.0);
angle = angle + angle_stepsize;
}
glVertex3f(radius, 0.0, height);
glVertex3f(radius, 0.0, 0.0);
glEnd();
// Draw the circle on top of cylinder
glColor3ub(R,G,B);
glBegin(GL_POLYGON);
angle = 0.0;
while( angle < 2*PI ) {
x = radius * cos(angle);
y = radius * sin(angle);
glVertex3f(x, y , height);
angle = angle + angle_stepsize;
}
glVertex3f(radius, 0.0, height);
glEnd();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-0.5,0.0,-2.5);
glRotatef(100.0, 0.725, 1.0, 1.0);
draw_cylinder(0.15, 1.0, 255, 160, 100);
glFlush();
}
void reshape(int width, int height)
{
if (width == 0 || height == 0) return;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(35.0, (GLdouble)width/(GLdouble)height,0.5, 20.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0, 0, width, height);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640,580);
glutCreateWindow("Create Cylinder");
glClearColor(0.0,0.0,0.0,0.0);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
At the moment it draws a straight cylinder/pipe. And I wanted to curve it to look like this.

First I recommend to split the cylinder into slices. The following cone will draw exactly the same cylinder, but it splits the cylinder int slices. The slices have different colors to visualize the effect.
GLfloat h0, h1, angle, x, y;
int i, j;
int slices = 8;
for ( i = 0; i < slices; i++ )
{
h0 = (float)i / (float)slices;
h1 = (float)(i+1) / (float)slices;
glColor3f( 1.0f-h0, 0.0, h1 );
glBegin(GL_QUAD_STRIP);
for ( j = 0; j <= 360; ++ j )
{
angle = PI * (float)j * PI / 180.0f;
x = radius * cos(angle);
y = radius * sin(angle);
glVertex3f( x, y, h0 );
glVertex3f( x, y, h1 );
}
glEnd();
}
Then you have to define a bend radius and a bend start and end angle. The following code draw a bended pipe form bend_ang0 to bend_ang1, with a radius bend_radius. The bend angles can be calculated in relation to the bend radius and the length of the pipe:
GLfloat w0, w1, ang0, ang1, angle, x, y, xb, yb, zb;
int i, j;
int slices = 8;
GLfloat bend_radius = 1.0f;
GLfloat bend_angle, bend_ang0, bend_ang1;
bend_angle = bend_radius * height;
bend_ang0 = -bend_angle/2.0f;
bend_ang1 = bend_angle/2.0f;
for ( i = 0; i < slices; i++ )
{
w0 = (float)i / (float)slices;
w1 = (float)(i+1) / (float)slices;
ang0 = bend_ang0 + (bend_ang1-bend_ang0) * w0;
ang1 = bend_ang0 + (bend_ang1-bend_ang0) * w1;
glColor3f( 1.0f-w0, 0.0, w1 );
glBegin(GL_QUAD_STRIP);
for ( j = 0; j <= 360; ++ j )
{
angle = PI * (float)j * PI / 180.0f;
x = radius * cos(angle) + bend_radius;
y = radius * sin(angle);
xb = sin( ang0 ) * x;
yb = y;
zb = cos( ang0 ) * x;
glVertex3f( xb, yb, zb );
xb = sin( ang1 ) * x;
yb = y;
zb = cos( ang1 ) * x;
glVertex3f( xb, yb, zb );
}
glEnd();
}
For the following image I activated the depth test and changed the model view matrix:
void display(void)
{
glEnable( GL_DEPTH_TEST );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f, -0.5f, -4.0f);
glRotatef(-90.0f, 1.0f, 0.0, 0.0f);
draw_cylinder(0.15, 2.0, 255, 160, 100);
glFlush();
}

Currently you are drawing the entire height of the cylinder in one go ... to create a curved surface you must instead take your existing code and have it create a succession of tiny cylinders each with a tiny height then stack them up to consume the original height.
One approach would be to introduce a new function which becomes the parent of your
void draw_cylinder(GLfloat radius, GLfloat height, GLubyte R, GLubyte G, GLubyte B)
perhaps call it
draw_curved_cylinder
inside this new function you have a loop where you make calls to draw_cylinder giving it the parameters of each of these tiny cylinders ... currently your draw function blindly stretches the height from 0 to your given height ... replace that with settings for the given tiny cylinder ... also to make the final cylinder curved each tiny cylinder must have its X and Y coordinates follow the curved trajectory so in that new function draw_curved_cylinder increment those so they vary as your synthesize each new tiny cylinder
PS - be aware that you are not using modern OpenGL - glBegin is obsolete and should be avoided

Related

Curved cylinder in a 3D space OpenGL (C) [duplicate]

The following code shows a straight cylinder/pipe in OpenGL C language.
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
#define PI 3.1415927
void draw_cylinder(GLfloat radius, GLfloat height, GLubyte R, GLubyte G, GLubyte B)
{
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat angle = 0.0;
GLfloat angle_stepsize = 0.1;
// Draw the tube
glColor3ub(R-40,G-40,B-40);
glBegin(GL_QUAD_STRIP);
angle = 0.0;
while( angle < 2*PI ) {
x = radius * cos(angle);
y = radius * sin(angle);
glVertex3f(x, y , height);
glVertex3f(x, y , 0.0);
angle = angle + angle_stepsize;
}
glVertex3f(radius, 0.0, height);
glVertex3f(radius, 0.0, 0.0);
glEnd();
// Draw the circle on top of cylinder
glColor3ub(R,G,B);
glBegin(GL_POLYGON);
angle = 0.0;
while( angle < 2*PI ) {
x = radius * cos(angle);
y = radius * sin(angle);
glVertex3f(x, y , height);
angle = angle + angle_stepsize;
}
glVertex3f(radius, 0.0, height);
glEnd();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-0.5,0.0,-2.5);
glRotatef(100.0, 0.725, 1.0, 1.0);
draw_cylinder(0.15, 1.0, 255, 160, 100);
glFlush();
}
void reshape(int width, int height)
{
if (width == 0 || height == 0) return;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(35.0, (GLdouble)width/(GLdouble)height,0.5, 20.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0, 0, width, height);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640,580);
glutCreateWindow("Create Cylinder");
glClearColor(0.0,0.0,0.0,0.0);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
At the moment it draws a straight cylinder/pipe. And I wanted to curve it to look like this.
First I recommend to split the cylinder into slices. The following cone will draw exactly the same cylinder, but it splits the cylinder int slices. The slices have different colors to visualize the effect.
GLfloat h0, h1, angle, x, y;
int i, j;
int slices = 8;
for ( i = 0; i < slices; i++ )
{
h0 = (float)i / (float)slices;
h1 = (float)(i+1) / (float)slices;
glColor3f( 1.0f-h0, 0.0, h1 );
glBegin(GL_QUAD_STRIP);
for ( j = 0; j <= 360; ++ j )
{
angle = PI * (float)j * PI / 180.0f;
x = radius * cos(angle);
y = radius * sin(angle);
glVertex3f( x, y, h0 );
glVertex3f( x, y, h1 );
}
glEnd();
}
Then you have to define a bend radius and a bend start and end angle. The following code draw a bended pipe form bend_ang0 to bend_ang1, with a radius bend_radius. The bend angles can be calculated in relation to the bend radius and the length of the pipe:
GLfloat w0, w1, ang0, ang1, angle, x, y, xb, yb, zb;
int i, j;
int slices = 8;
GLfloat bend_radius = 1.0f;
GLfloat bend_angle, bend_ang0, bend_ang1;
bend_angle = bend_radius * height;
bend_ang0 = -bend_angle/2.0f;
bend_ang1 = bend_angle/2.0f;
for ( i = 0; i < slices; i++ )
{
w0 = (float)i / (float)slices;
w1 = (float)(i+1) / (float)slices;
ang0 = bend_ang0 + (bend_ang1-bend_ang0) * w0;
ang1 = bend_ang0 + (bend_ang1-bend_ang0) * w1;
glColor3f( 1.0f-w0, 0.0, w1 );
glBegin(GL_QUAD_STRIP);
for ( j = 0; j <= 360; ++ j )
{
angle = PI * (float)j * PI / 180.0f;
x = radius * cos(angle) + bend_radius;
y = radius * sin(angle);
xb = sin( ang0 ) * x;
yb = y;
zb = cos( ang0 ) * x;
glVertex3f( xb, yb, zb );
xb = sin( ang1 ) * x;
yb = y;
zb = cos( ang1 ) * x;
glVertex3f( xb, yb, zb );
}
glEnd();
}
For the following image I activated the depth test and changed the model view matrix:
void display(void)
{
glEnable( GL_DEPTH_TEST );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f, -0.5f, -4.0f);
glRotatef(-90.0f, 1.0f, 0.0, 0.0f);
draw_cylinder(0.15, 2.0, 255, 160, 100);
glFlush();
}
Currently you are drawing the entire height of the cylinder in one go ... to create a curved surface you must instead take your existing code and have it create a succession of tiny cylinders each with a tiny height then stack them up to consume the original height.
One approach would be to introduce a new function which becomes the parent of your
void draw_cylinder(GLfloat radius, GLfloat height, GLubyte R, GLubyte G, GLubyte B)
perhaps call it
draw_curved_cylinder
inside this new function you have a loop where you make calls to draw_cylinder giving it the parameters of each of these tiny cylinders ... currently your draw function blindly stretches the height from 0 to your given height ... replace that with settings for the given tiny cylinder ... also to make the final cylinder curved each tiny cylinder must have its X and Y coordinates follow the curved trajectory so in that new function draw_curved_cylinder increment those so they vary as your synthesize each new tiny cylinder
PS - be aware that you are not using modern OpenGL - glBegin is obsolete and should be avoided

Rotate about Y-Axis gluLookAt

I am trying to rotate the viewer about the y-axis. I have a function called tranform_eye() which will calculate the next position of eyex, eyey and eyez after each update.
Can anyone help me figure out how to calculate the values for eyex, eyey and eyez?
My Code:
float eyex = 5;
float eyey = 5;
float eyez = 5;
void display() {
transform_eye();
glMatrixMode(GL_PROJECTION); // To operate on model-view matrix
glLoadIdentity();
gluPerspective(40.0, 1.0, 1.0, 10000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eyex, eyey, eyez,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers
drawTriangles();
glutSwapBuffers(); // Swap the front and back frame buffers (double buffering)
}
void transform(){
/// calculate new eyex, y z.
}
Applying the math from e.g. this answer gives us:
void transform()
{
float theta = 0.01; //angle in radians to rotate every frame
float cosTheta = cos(theta);
float sinTheta = sin(theta);
float newX = cosTheta * eyeX + sinTheta * eyeZ;
eyeZ = -sinTheta * eyeX + cosTheta * eyeZ;
eyeX = newX;
}

Drawing a diagonal semicircle in OpenGL

I'm trying to draw a diagonal semicircle. So far I've only been able to draw ones that begin and end on a horizontal or vertical axis, like this:
I've tried modifying the code to tilt the circle, but it doesn't work. Can someone please tell me where I've gone wrong, this is infuriating!
float theta, tanTheta, x, y, dx, dy;
int circle_points = 1000, radius = 70;
glBegin(GL_POLYGON);
for(int i = 0; i < circle_points; i++)
{
dx = pts[1].x - pts[0].x;
dy = pts[1].y - pts[0].y;
tanTheta = tan(dy / dx);
// get the inverse
theta = atan(tanTheta);
x = radius * cos(theta);
y = radius * sin(theta);
glVertex2f(x, y);
}
glEnd();
I recommend to calculate the angle to the start point and the angle to the end point by atan2.
Interpolate the angle between the start angle and the end angle and draw a line along the corresponding points on the circe:
float ang_start, ang_end, theta, x, y;
ang_start = atan2( pts[0].y, pts[0].x );
ang_end = atan2( pts[1].y, pts[1].x );
if ( ang_start > ang_end )
ang_start -= 2.0f * M_PI;
glBegin(GL_LINE_STRIP);
for(int i = 0; i <= circle_points; i++)
{
float w = (float)i / (float)circle_points;
float theta = ang_start + w * ( ang_end - ang_start );
x = radius * cos(theta);
y = radius * sin(theta);
glVertex2f(x, y);
}
glEnd();

Translating a single object opengl

I am writing code to draw the figure
but my code gives
as you can see the middle circle is missing.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
float width, height, r = 0.3, change = 0;
void draw(float tx, float ty)
{
glBegin(GL_LINE_LOOP);
for(int i = 1; i <= 1200; i++)
{
float x1, y1, theta;
theta = (2 * 3.14159 * i) / 1200;
x1 = r * cosf(theta) * height / width;
y1 = r * sinf(theta);
glVertex3f(x1 , y1 ,0);
}
glEnd();
glTranslatef(tx, ty, 0);
}
void display()
{
float p[6][2];
int j = 0;
if (change == 0)
change = 1;
else if (change == 1)
change = 0;
width = glutGet(GLUT_WINDOW_WIDTH);
height = glutGet(GLUT_WINDOW_HEIGHT) ;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glMatrixMode(GL_MODELVIEW);
glBegin(GL_LINE_LOOP);
for(int i = 1; i <= 1200; i++)
{
float theta, x1, y1;
theta = (2 * 3.14159 * i) / 1200;
x1 = r * cosf(theta) * height / width;
y1 = r * sinf(theta);
glVertex3f(x1, y1, 0);
if (i == 100 | i == 300 | i == 500 | i == 700 | i == 900 | i == 1100)
{
if(change == 0){
p[j][0] = x1;
p[j][1] = y1;
j++;
}
}
}
glEnd();
for(int i=0;i<6 && change == 0;i++){
draw(p[i][0],p[i][1]);
}
glutSwapBuffers();
}
void main(int argc,char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(700,500);
glutCreateWindow("circles");
glutDisplayFunc(display);
glutMainLoop();
}
Issue is when i translate first circle in draw function the center circle drawn is also translated to that point which is merged with other circle.My doubt is how to translate only one circle not the center one i tried translating by using push and pop matrix but it doesn't work.
Thank you.
glTranslatef() changes the current matrix by appending a translation. So your translations will just accumulate. And since you do not have a transform between the first two circles, they will appear at the same positions. Your program basically does the following:
Draw Circle
draw()
Draw Circle
Move up, right (p[0])
draw()
Draw Circle
Move up (p[1])
draw()
Draw Circle
Move up left (p[2])
...
If you want absolute positioning, you have to reset the transform in between. This can either be done with glLoadIdentity() or with the matrix stack. And be sure to draw after setting the transform.
I guess you know, but in any case a little reminder: The entire matrix stack functionality is deprecated in modern OpenGL and you will need to manage the matrices yourself. I assume, when you do this, everything gets a bit clearer. So I'm not sure if there is a good reason to try to understand the interface of the matrix stack functionalities.
If you want to place each circle at a specific location, you can do something like the following:
void drawCircle()
{
glBegin(GL_LINE_LOOP);
for(int i = 1; i <= 1200; i++)
{
float x1, y1, theta;
theta = (2 * 3.14159 * i) / 1200;
x1 = r * cosf(theta) * height / width;
y1 = r * sinf(theta);
glVertex3f(x1 , y1 ,0);
}
glEnd();
}
void display()
{
// ...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glMatrixMode(GL_MODELVIEW);
drawCircle();
for(int i = 0; i < 6; ++i)
{
float angle = M_PI / 3 * i;
float tx = r * sin(angle);
float ty = r * cos(angle);
glPushMatrix(); //save the current matrix
glTranslatef(tx, ty, 0); //move to the desired location
drawCircle();
glPopMatrix(); //restore the old matrix
}
glutSwapBuffers();
}

Using the following function that draws a filled circle in opengl, how do I make it show at different coordinates of the window?

I have got the following code to draw a filled circle in opengl. The problem is that it draws at the center of the screen. How do I make it draw in another position of it?
Here is the code:
#define CIRCLE_RADIUS = 0.15f
int circle_points = 100;
void draw()
{
glClear(GL_COLOR_BUFFER_BIT);
double angle = 2* PI/circle_points ;
glPolygonMode( GL_FRONT, GL_FILL );
glColor3f(0.2, 0.5, 0.5 );
glBegin(GL_POLYGON);
double angle1 = 0.0;
glVertex2d( CIRCLE_RADIUS * cos(0.0) , CIRCLE_RADIUS * sin(0.0));
int i;
for (i = 0; i < circle_points; i++)
{
glVertex2d(CIRCLE_RADIUS * cos(angle1), CIRCLE_RADIUS *sin(angle1));
angle1 += angle ;
}
glEnd();
glFlush();
}
The obvious way would be to call glTranslate first. Note, however, that you can already accomplish the same a bit more easily with a combination of glPointSize and glPoint:
glPointSize(CIRCLE_RADIUS/2.0f);
glPoint(center_x, center_y, center_z);
Before you start drawing the circles, you'll want something like:
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
Otherwise, your "circles" could end up as squares.
Edit: Without knowing how you've set up your coordinates, it's impossible to know what the "top-left" position is, but you could do something like this:
void draw_circle(float x, float y, float radius) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(x, y, 0.0f);
static const int circle_points = 100;
static const float angle = 2.0f * 3.1416f / circle_points;
// this code (mostly) copied from question:
glBegin(GL_POLYGON);
double angle1=0.0;
glVertex2d(radius * cos(0.0) , radius * sin(0.0));
int i;
for (i=0; i<circle_points; i++)
{
glVertex2d(radius * cos(angle1), radius *sin(angle1));
angle1 += angle;
}
glEnd();
glPopMatrix();
}
You could then call (for example):
draw_circle(0.0f, 0.0f, 0.2f); // centered
draw_circle(1.0f, 0.0f, 0.2f); // right of center
draw_circle(1.0f, 1.0f, 0.2f); // right and up from center
Of course, the directions I've given assume haven't (for example) rotated your view, so x increases to the right and y increases upward.

Resources