Version 13 (modified by 11 years ago) (diff) | ,
---|
OpenGL hands-on tutorial
Running this tutorial on Linux desktop one requires at least the OpenGL 2.0 graphics with the OpenGL Shading Language (GLSL) 1.1 and supporting libraries GL, GLU, GLUT, GLEW. This can be verified with the following 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 favorite 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.
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:
- Add RGB color to vertices with
glColor3f(0.0, 0.4, 1.0);
. - Replace single line drawing in
display()
with the following snippetand try to draw two wireframe triangles in a loop. Change primitive toGLfloat 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 } };
GL_LINE_LOOP
. - Draw two primitives with
GL_TRIANGLES
. - 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}};
- Replace loop with the following
How can we add color to vertices? See glColorPointer and glEnableClientState.
glVertexPointer(2, GL_FLOAT, 0, &vertices[0][0]); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableClientState(GL_VERTEX_ARRAY);
- Change background to
glClearColor(0.9,1,1,1.0);
Modern OpenGL
We extend previous exercise with example that introduces OpenGL 3.x techniques:
- OpenGL Shading Language where simple vertex and fragment shader are required.
- Vertex Buffer Objects stored in GPU
Create triangle.c
and update Makefile
with new target
#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; }
Exercises #2
- To be able to continue and not get lost introduce shader compiler logs in case of compilation errors by adding the following code into {{{setShaders()}} right at after vertex shader compilation:
Do not forget to repeat the same thing for fragment shader.
GLint compiled; glGetShaderiv(v, GL_COMPILE_STATUS, &compiled ); if ( !compiled ) { GLsizei len; glGetShaderiv( v, GL_INFO_LOG_LENGTH, &len ); GLchar* log = malloc(sizeof(GLchar)*(len+1)); printf("Shader compilation failed: %s\n", log); free(log); }
- Add linker debugging
Create some error to verify if it works.
GLint linked; glGetProgramiv(p, GL_LINK_STATUS, &linked ); if ( !linked ) { GLsizei len; glGetProgramiv( p, GL_INFO_LOG_LENGTH, &len ); GLchar* log = malloc(sizeof(GLchar)*(len+1)); glGetProgramInfoLog( p, len, &len, log ); printf("Shader linking failed: %s\n", log); free(log); }
- For general (core) OpenGL errors we can use the following utility at suspicious places.
GLenum errCode; if ((errCode = glGetError()) != GL_NO_ERROR) { const GLubyte *errString = gluErrorString(errCode); fprintf (stderr, "OpenGL Error: %s\n", errString); }
Attachments (24)
-
ex1-5.png (6.0 KB) - added by 11 years ago.
Exercise #1.5
-
first.png (3.9 KB) - added by 11 years ago.
Legacy sample
-
triangle.png (2.9 KB) - added by 11 years ago.
First GLSL example
-
OpenGL-pipeline.svg (19.7 KB) - added by 11 years ago.
OpenL pipeline
-
temperature.png (5.8 KB) - added by 11 years ago.
Temperature varying field
-
teapot.png (6.2 KB) - added by 11 years ago.
Famous Utah teapot from GLUT
-
trackball.h (3.2 KB) - added by 11 years ago.
Header for trackball
-
trackball.c (8.9 KB) - added by 11 years ago.
Virtual trackball source for interactivity
-
motorBike.obj.gz (3.6 MB) - added by 11 years ago.
Example mesh from OpenFOAM tutorials/incompressible/simpleFoam/motorBike/constant/triSurface
-
motorBike-subset.png (66.4 KB) - added by 11 years ago.
Complete motorBike mesh in VisIt
-
motorBike.obj (10.2 MB) - added by 11 years ago.
Example mesh from OpenFOAM tutorials/incompressible/simpleFoam/motorBike/constant/triSurface
-
motorBike.stl.bz2 (9.4 MB) - added by 11 years ago.
STL example from 1.7.1/run/tutorials/incompressible/simpleFoam/motorBike/constant/triSurface
-
copper-mix.png (30.7 KB) - added by 11 years ago.
Copper mix Gouraud shading of the Teapot
-
point-cloud.png (26.7 KB) - added by 11 years ago.
Point cloud from single vertex array
-
helmet.obj (303.4 KB) - added by 11 years ago.
Rider's helmet with center at (0.5, 0, 1.2)
-
temperature.c (5.2 KB) - added by 11 years ago.
Exercise 2.2
-
teapot.c (4.7 KB) - added by 11 years ago.
Extended teapot example
-
wavefront.c (1.9 KB) - added by 11 years ago.
Wavefront converter
-
motorbike-shadow.png (28.2 KB) - added by 11 years ago.
Garbled normals on some parts of motorbike
-
motorbike-final.png (13.1 KB) - added by 11 years ago.
Tooned motorbike example
-
motorbike.c (8.0 KB) - added by 11 years ago.
Final motorbike source
-
p_yNormal.vtk (1.7 MB) - added by 11 years ago.
motorBike VTK data for pressure at cutting plane at time 500
-
pressure.png (22.3 KB) - added by 11 years ago.
Pressure from p_yNormal.vtk
-
pressure.c (6.7 KB) - added by 11 years ago.
Pressure example