Modeling
– how to draw objects –
1. Very simple program
The program “modeling1.c” is a program that just draws one red square on the center of a
window as shown in fig.11.
fig.1 output of modeling1.c
Even though most of the time we draw a graphics in 3-D space, since it is easier to
understand how to draw object in 2-D space, let us start from 2-D object and later extend to
3-D object.
The following is the explanation of the program to draw the picture above. This program is
modified from a sample program in the text book, “gasket.c”.
#include <GL/glut.h>
The very first line includes one header file of OpenGL to connect C program and OpenGL
functions. This is the line you should write whenever you use OpenGL. Actually there are
three header files of OpenGL, gl.h, glu.h and gult.h, however you don’t have to include
those three since glut.h includes the other two header files.
The first function, myinit() sets up the environment of the graphics. There are three
functionality in this function, decide the background color, set the projection, and change
1
You can print one selected window by Alt+Prt Sc, if you need whole display by Prt Sc
1
the matrix to model and view’s one.
void myinit(void)
{
/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
/* set up viewing */
/* 500 x 500 window with origin lower left */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
}
glClearColor() decides the color of the background of the window in which you are going to
draw objects. There are four parameters in glClearColor(), the first one is how much red
you need, the second one is how much blue you need, the third one is how much green you
need, and the last one is alpha channel which you don’t have to worry about as long as the
value is 1.0.
The next three lines sets the projection matrix. First assign which matrix is going to be set,
then initialize the matrix by calling glLoadIdentity(), and finally assign what kind of
projection we want to use. gluOrtho2D decides how to project the objects we are going to see
other type of projections later.
2
void display( void )
{
/* define a point data type */
typedef GLfloat point2[2];
point2 vertices[4]={{125.0,125.0},{375.0,125.0},{375.0,375.0},{125.0,375.0}};
glClear(GL_COLOR_BUFFER_BIT); /*clear the window */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(1.0, 0.0, 0.0); /* draw in red */
glBegin(GL_QUADS);
glVertex2fv(vertices[0]);
glVertex2fv(vertices[1]);
glVertex2fv(vertices[2]);
glVertex2fv(vertices[3]);
glEnd();
glFlush(); /* clear buffers */
}
This function display() is the function that decides what kind of objects are going to be
drawn, in other words this is the function you must write. The first and second lines are
defining the vertices and its data type. The third line, glClear() is always needed to draw
objects, without this line nothing is going to be displayed.
The last line of myinit() sets the matrix mode to modeling and view since from this line,
usually we don’t have to touch with any other matrix.
The next line glColor3f() decides the color of the object which is going to be drawn. The
three parameters indicate how much red , green, and blue are needed in the range of 0.0 to
1.0. The next block is where you must decide to draw an object.
glBegin(GL_QUADS);
glVertex2fv(vertices[0]);
glVertex2fv(vertices[1]);
glVertex2fv(vertices[2]);
glVertex2fv(vertices[3]);
glEnd();
assign the object type
wherever the vertices are ,
this is where you assign them
tell OpenGL all vertices are assigned.
3
Every time you draw an object this block is necessary to assign vertices. In the program
GL_QUADS is assigned to draw a square. Because it draws a square in total four vertices
are needed to be assigned. Here the last three characters of glVertex2fv means, 2
dimensional float number as vector. glVertex() has many options like this, you can choose
what you like. The coordinates are assigned as shown below.
(0,500)
(500,500)
(125,375)
(375,375)
(125,125)
(375,125)
(0,0)
(500,0)
fig.2 coordinate of fig.1
int main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); /* default, not needed */
glutInitWindowSize(500,500); /* 500 x 500 pixel window */
glutInitWindowPosition(0,0); /* place window top left on display */
glutCreateWindow("Very Simple Modeling"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
return 0;
}
The last function is main() which is needed as any other C program. The functionality of
main is the setting the connection the drawing window and some other devices such as
4
display, mouse, keyboard and so on 2 . The first six lines are initializing the window
environment.
Initializing
environment(glutInit(&argc,argv)),
GLUT
(glutInitDisplayMode(GLUT_SINGLE
|
GLUT_RGB)),
the
size
display
of
mode
drawing
window(glutInitWindowSize(500,500)), location of the drawing window by the left up corner
of the drawing window(glutInitWindowPosition(0,0)), the title of the drawing window
(glutCreateWindow("Very Simple Modeling")), and which function is going to be called to
draw objects(glutDisplayFunc(display)) 3 . Then myinit() is called to setup. Finally
glutMainLoop() is called to enter an event-loop which means that if an event, such as the
window is moved, happens, whole lines are executed again.
As long as you need to draw some 2-D objects, these setups are enough, all you have to do
is write the contents of the function display().
2. 3-D objects
Now let us jump into drawing 3-D objects. Fig.3 shows you the output of a program
“modeling2.c” which draws one cube4. Since the program “modeling2_1.c” is written by
modifying “modeling1.c”, we are going to see only the difference.
fig.3 output of modeling2_1.c
Sometimes the contents might be different, to tell the truth there is no absolutely correct
program.
3 The function whose name is given to an OpenGL function is called callback function.
4 let us leave the problem whether it looks 3-D object or not
2
5
/* define a point data type */
typedef GLfloat point3[3];
point3 vertices[8]={{125.0,125.0,125.0},{375.0,125.0,125.0},
{375.0,375.0,125.0},{125.0,375.0,125.0},
{125.0,125.0,-125.0},{375.0,125.0,-125.0},
{375.0,375.0,-125.0},{125.0,375.0,-125.0}};
The first and biggest difference between modeling1.c and modeling2_1.c is, of course the
dimension we draw. Since this time the object is 3-D object, each vertices need three
coordinates. The eight coordinates have an index shown as below.
7
6
3
2
4
0
5
1
fig.4 index of all eight coordinates
void myinit(void)
{
…
glOrtho(0.0, 500.0, 0.0, 500.0, -500.0, 500.0);
…
}
The difference in myinit() is only how we project objects. What glOrtho() does is to decide a
box in which objects are going to be appeared. Since the drawing space is 3-D this time, we
need 3-D projection box which needs 6 points to decide the size of the projection box.
void draw_face(int a, int b, int c, int d)
{
glColor3f(1.0, 0.0, 0.0); /* draw in red */
glBegin(GL_QUADS);
glVertex3fv(vertices[a]);
glVertex3fv(vertices[b]);
glVertex3fv(vertices[c]);
glVertex3fv(vertices[d]);
glEnd();
}
6
Because how to draw a square is exactly the same, I put one function to draw one square
which is going to be called six times to draw a cube. Like other programs, it might be better
to have a function if you call the same lines of code. Here the four parameters a, b, c and d
are the index of the eight vertices which are given at the beginning of the code. This
function is called in display().
void display( void )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /*clear the window */
glPushMatrix();
glRotatef(45.0, 1.0, 1.0, 0.0);
draw_face(0,1,2,3);
draw_face(1,5,6,2);
draw_face(5,4,7,6);
draw_face(4,0,3,7);
draw_face(3,2,6,7);
draw_face(1,0,4,5);
glPopMatrix();
…
}
Here the underlined lines are the topics of the next tutorial, you just don’t care this time.
The major difference is we have to clear GL_DEPTH_BUFFER_BIT because we are writing
a 3-D object, we need to consider the depth of the drawing window to show 3-D objects. The
other difference we care is draw_face() which draws one face of the cube.
int main(int argc, char** argv)
{
…
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
…
glutCreateWindow("3-D Modeling"); /* window title */
…
glEnable(GL_DEPTH_TEST);
…
}
7
Finally function main() has three differences including one minor difference. First
difference is the parameter in glutInitDisplayMode(), GLUT_DEPTH is needed because as
mentioned before we are drawing 3-D object. The second difference is the parameter to
glutCreateWidow() to change the title of the window. The last difference is adding
glEnable(GL_DEPTH_TEST)5. We will see the effect of glEnable(GL_DEPTH_TEST) later.
3. Real 3-D object
Now let us go back to the question “Does the figure 3 look really 3-D cube?” There is no
doubt that the program is drawing the cube as a 3-D object. However unfortunately unlike
real world, we didn’t put any light6 so far. There is one technique to make the object look
real cube without learning any new stuffs. Look at the figure 5 shown below. Does that look
like a cube? At least it looks much closer to cube than figure 3, doesn’t it? The following is
the difference between “modeling2_1.c” and “modeling2_2.c”.
fig.5 output of modeling2_2.c
5
6
glEnable() enables many features in OpenGL which we are going to see.
which we are going to learn later
8
void draw_face(int a, int b, int c, int d)
{
glBegin(GL_QUADS);
glColor3f(1.0, 0.0, 0.0); /* draw in red */
glVertex3fv(vertices[a]);
glColor3f(0.0, 1.0, 0.0); /* draw in green */
glVertex3fv(vertices[b]);
glColor3f(0.0, 0.0, 1.0); /* draw in blue */
glVertex3fv(vertices[c]);
glColor3f(0.0, 0.0, 0.0); /* draw in black */
glVertex3fv(vertices[d]);
glEnd();
}
The bold lines are the difference. Last time we put glColor3f(1.0, 1.0, 1.0) before
glBegin(GL_QUADS). The difference implemented by this is that in the previous case we
assign color to whole object that means every vertices have the same color. On the other
hands, in this case each vertex has different color which is given before each coordinate is
given. Since each vertex has different color, OpenGL automatically interpolates the color as
you can see in fig.5. This is one of OpenGL’s feature about the color.
Now since the object looks 3-D, let us look at the effect of glEnable(GL_DEPTH_TEST).
Look at the figure 6 which is drawn by deleting glEnable(GL_DEPTH_TEST) from
“modeling2_2.c”.
The problem is even though it looks 3-D object, something is different. What happens
there is that OpenGL overdraw each face on the faces already there without thinking which
face is closer to viewer. In other words, if you need to hide the object behind another object,
you must enable GL_DEPTH_TEST, otherwise you will see an object which you don’t expect
at all.
fig.6 cube without glEnable(GL_DEPTH_TEST)
9
TOPICS: If you get lost …
Sometimes we got lost where we put object even though we write some scratches. That
might be because of moving viewers etc which we are going to see. If you have such problem,
one of the best way to know where you are is draw x, y and z axis from origin.
//red x axis
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(1000.0, 0.0, 0.0);
glEnd();
//blue y axis
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 1000.0, 0.0);
glEnd();
//green z axis
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 1000.0);
glEnd();
Then it is much easier to see what is going on in your program.
10
© Copyright 2026 Paperzz