OpenGL Programming/Basics/2DObjects
Drawing Triangles and Quads
[edit | edit source]glRectf(), while useful, doesn't allow us very much control over the individual vertices of our rectangle. To give us more control, and the ability to draw more complicated shapes, we have to use different functions.
Stand-Alone Vertex-Defined Shapes
[edit | edit source]Starting a Vertex-Defined Shape
[edit | edit source]To start a shape defined by vertices, we use the glBegin() function. glBegin takes one argument: the type of shape you want to make. Here are some possible arguments:
- GL_TRIANGLES
- GL_QUADS
- GL_POLYGON
A quad is any shape with 4 vertices: a rectangle, a square, a trapezoid, etc. The position of the vertices will define what type of shape it is.
While polygon sounds ideal for drawing complicated shapes, scroll down for a warning on the limitations of polygons: there are quite a few, and you might be better off using a series of connected quads or triangles in certain cases.
Defining Vertices
[edit | edit source]After you have called glBegin, we actually define the vertices using glVertex2f(float xPosition, float yPosition):
glBegin(GL_XYZ); glVertex2f(-1.0f,-0.5f); glVertex2f(1.0f,-0.25f); ...
Important Note: The order in which you define vertices is important! In general, if you define the vertices in counter-clockwise order, the front face will be facing towards you, which is usually what you want. The distinction becomes very important once we go into 3D, so make sure to define your vertices counter-clockwise unless you know what you're doing! If you would prefer to define your vertices in clockwise order, make sure to include this function in your setup() function:
glFrontFace(GL_CW);
which will allow you to draw only in clockwise order.
Finishing Up
[edit | edit source]To end a vertex-defined shape, simply call glEnd(), which takes no arguments.
Example
[edit | edit source]This display function will draw a black trapezoid centered in our screen.
void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(0.0f, 0.0f, 0.0f); // sets color to black. glBegin(GL_QUADS); glVertex2f(-0.25f, 0.25f); // vertex 1 glVertex2f(-0.5f, -0.25f); // vertex 2 glVertex2f(0.5f, -0.25f); // vertex 3 glVertex2f(0.25f, 0.25f); // vertex 4 glEnd(); glutSwapBuffers(); }
Note on Style: Calls to glVertex() are sometimes indented to separate them from the glBegin and glEnd. The indentation in the previous example was not a mistake.
Drawing a Series of Connected Shapes Efficiently
[edit | edit source]If we're going to draw a series of shape where every one shares an edge or vertex with the other, there's no reason to repeat so many calls to glVertex2f(). Instead, we call glBegin with a special argument to signal that we want a "strip" of these objects.
Using glBegin with GL_TRIANGLE_STRIP or GL_QUAD_STRIP
[edit | edit source]When we call glBegin with either of these two arguments, we can draw a series of triangles or quads, each of which shares one edge with another triangle or quad. One good use for this is drawing complicated shapes, e.g. a 2D Christmas tree.
A triangle strip is defined by 3 initial vertices for the triangle, and then one vertex for each additional triangle. Any given triangle is formed by its one vertex and the two vertices immediately before.
A quad strip is defined by 4 initial vertices for the quad, and then two vertices for each additional quad. Any given quad is formed by its two vertices and the two vertices that come immediately before.
Example
[edit | edit source]The following code defines a house shape, with a slanted roof, using triangle strips:
void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(0.0f, 0.0f, 0.0f); // sets color to black. glBegin(GL_TRIANGLE_STRIP); // draw in triangle strips glVertex2f(0.0f, 0.75f); // top of the roof glVertex2f(-0.5f, 0.25f); // left corner of the roof glVertex2f(0.5f, 0.25f); // right corner of the roof glVertex2f(-0.5f, -0.5f); // bottom left corner of the house glVertex2f(0.5f, -0.5f); //bottom right corner of the house glEnd(); glutSwapBuffers(); }
Here, three triangles are defined, one for the roof, one for the upper left corner of the house, and one for the lower right corner of the house.
Using glBegin with GL_TRIANGLE_FAN
[edit | edit source]If we want to draw a bunch triangles where every triangle shares a predefined vertex (for example, at the origin), we can use a triangle fan. Triangle fans define a shape through an odd number of vertices. The first vertex defines a center point which every triangle will have as a vertex. Every two vertices are then used with the initial vertex to define a triangle.
#include <GL/glut.h>
void init(){
glClearColor(0,0,0,0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0,100,0,200);
}
void Display(){
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLE_FAN);
glColor3f(1,0,0);
glVertex2f(0,0.5);
glVertex2f(-0.4,0);
glVertex2f(0.4,0);
glColor3f(0,1,0);
glVertex2f(0,-0.5);
glEnd();
glFlush();
}
int main(int argc, char **argv){
glutInit(& argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(200,200);
glutCreateWindow("line");
glutDisplayFunc(Display);
init();
glutMainLoop();
return 0;
}
Shapes Built In to GLUT
[edit | edit source]GLUT has a few built-in objects that can be used just by calling a simple function. The most interesting and useful of these are:
Function | 2D Shape | 3D Shape | Comments |
glutSolidSphere(float radius, int slices, int stacks) | Circle | Sphere | Choose an integer 20-100 for the slices and stacks arguments; the higher the number, the more accurate the sphere/circle. |
glutSolidCube(double size) | Square | Cube | |
glutSolidCone(double base, double height, int slices, int stacks) | Triangle | Cone | The greater the slices argument is, the smoother the cone will appear. |
glutSolidTorus(double innerRadius, double outerRadius, int nSides, int rings) | Torus | ||
glutSolidTeapot(float radius) | Teapot | Teapot | Yes, a teapot. See the Wikipedia article "Utah Teapot" to find out why a teapot was chosen. |