wiki:tutorial

Version 9 (modified by leon, 11 years ago) (diff)

Modern GL

OpenGL hands-on tutorial

Running this tutorial on Linux desktop one requires at least OpenGL 2.0 graphics with OpenGL Shading Language (GLSL) 1.1 and supporting libraries GL, GLU, GLUT, GLEW. This can be verified with commands:

$ glxinfo |grep OpenGL.*version
OpenGL version string: 2.1 Mesa 8.0.5
OpenGL shading language version string: 1.20
$ ls /usr/include/GL/{glut.h,glew.h,gl.h,glu.h}
/usr/include/GL/glew.h  /usr/include/GL/glu.h
/usr/include/GL/gl.h    /usr/include/GL/glut.h

Legacy OpenGL

Create the following first.c using your favourite editor.

#include <GL/glut.h>

void display()
{
  glClear(GL_COLOR_BUFFER_BIT);
  glColor3f(1.0, 0.4, 1.0);
  glBegin(GL_LINES);
    glVertex2f(0.1, 0.1);
    glVertex3f(0.8, 0.8, 1.0);
  glEnd();
  glutSwapBuffers();
}

int main(int argc, char *argv[])
{
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_DOUBLE);
  glutCreateWindow("first.c GL code");
  glutDisplayFunc(display);
  glutMainLoop();
  return 0;
}

Create Makefile to build your program. Legacy sample

CFLAGS=-Wall
LDFLAGS=-lGL -lGLU -lglut -lGLEW

ALL=first
default: $(ALL)

first : first.o

clean:
      rm -rf *~ *.o $(ALL)

Beware that Makefile is TAB aware. So the last line should contain TAB indentation and not spacing.

Make and run the program with

make
./first

Try the same program in Python

from OpenGL.GLUT import *
from OpenGL.GL import *
import sys

def display():
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1.0, 0.4, 1.0)
    glBegin(GL_LINES)
    glVertex2f(0.1, 0.1)
    glVertex3f(0.8, 0.8, 1.0)
    glEnd()
    glutSwapBuffers()

if __name__ == "__main__":
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_DOUBLE)
    glutCreateWindow("first.py GL code")
    glutDisplayFunc(display)
    glutMainLoop()

and run it with

python first.py

Exercise #1:

  1. Add RGB color to vertices with glColor3f(0.0, 0.4, 1.0);.
  2. Replace single line drawing in display() with the following snippet
       GLfloat vertices[][2] = {
        { -0.90, -0.90 }, // Triangle 1
        {  0.85, -0.90 },
        { -0.90,  0.85 },
        {  0.90, -0.85 }, // Triangle 2
        {  0.90,  0.90 },
        { -0.85,  0.90 }
       };
    
    and try to draw two wireframe triangles in a loop. Change primitive to GL_LINE_LOOP.
  3. Draw two primitives with GL_TRIANGLES. Exercise #1.5
  4. Add different color to each vertex.
     GLfloat color[][3] = {
      {1, 0, 0}, {0, 1, 0}, {0, 0, 1},
      {1, 1, 0}, {0, 1, 1}, {1, 0, 1}};
    
  5. Replace loop with the following
      glVertexPointer(2, GL_FLOAT, 0, &vertices[0][0]);
      glEnableClientState(GL_VERTEX_ARRAY);
      glDrawArrays(GL_TRIANGLES, 0, 6);
      glDisableClientState(GL_VERTEX_ARRAY);
    
    How can we add color to vertices? See glColorPointer and glEnableClientState.
  6. Change background to glClearColor(0.9,1,1,1.0);

Modern OpenGL

Create triangle.c and update Makefile First GLSL example We extend previous exercise with example that introduces OpenGL 3.x techniques:

  • OpenGL Shading Language
  • Vertex Buffer Objects stored in GPU
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>

static const GLchar * vertex_shader[] =
  {"void main()"
   "{"
   "  gl_Position = ftransform();"
   "}"
  };
static const GLchar * fragment_shader[] =
  {"void main()"
   "{"
   " gl_FragColor = vec4(0.4,0.4,0.8,1.0);"
   "}"
  };

void setShaders()
{
  GLuint v, f, p;

  v = glCreateShader(GL_VERTEX_SHADER);
  f = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(v, 1, vertex_shader, NULL);
  glShaderSource(f, 1, fragment_shader, NULL);
  glCompileShader(v);
  glCompileShader(f);
  p = glCreateProgram();
  glAttachShader(p,f);
  glAttachShader(p,v);
  glLinkProgram(p);
  glUseProgram(p);
}


enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs {ArrayBuffer,NumBuffers};
enum Attrib_IDs { vPosition = 0 };
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
#define NumVertices  6 

void init(void)
{
  glGenVertexArrays(NumVAOs, VAOs);
  glBindVertexArray(VAOs[Triangles]);
  GLfloat vertices[NumVertices][2] = {
    { -0.90, -0.90 }, // Triangle 1
    {  0.85, -0.90 },
    { -0.90,  0.85 },
    {  0.90, -0.85 }, // Triangle 2
    {  0.90,  0.90 },
    { -0.85,  0.90 }
  };
  glGenBuffers(NumBuffers, Buffers);
  glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
  glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, (const void*)0);
  glEnableVertexAttribArray(vPosition);
}


void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glBindVertexArray(VAOs[Triangles]);
  glDrawArrays(GL_TRIANGLES, 0, NumVertices);
  glutSwapBuffers();
}

int main(int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
  glutCreateWindow("GLSL Intro");
  glutDisplayFunc(display);
  glewInit();
  if (!glewIsSupported("GL_VERSION_2_0"))
   {
     printf("GLSL not supported\n");
     exit(EXIT_FAILURE);
   }
  glClearColor(0.9,1.0,1.0,1.0);
  init();
  setShaders();
  glutMainLoop();
  return 0;
}

Attachments (24)