CSE 5542 - Real Time Rendering
Week 3
The Anatomy of *GL*
Program
http://www.cs.unm.edu/~angel/BOOK/INTERACTIVE_COMPUTER_GRAPHICS/SIXTH_
The Sierpinski Gasket
The Sierpinski Gasket
Pseudo-code
Immediate Mode
Retained Mode
Sierpinski in GLSL thru GLUT
int
main( int argc, char **argv ) {
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA );
glutInitWindowSize( 512, 512 );
glutCreateWindow( "Sierpinski Gasket" );
init();
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutMainLoop();
return 0;
Callbacks – Event-based
..
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
…
void
keyboard( unsigned char key, int x, int y ) {
switch ( key ) { case 033:
exit( EXIT_SUCCESS );
break;
} } void
display( void ) {
glClear( GL_COLOR_BUFFER_BIT ); //
clear the window
glDrawArrays( GL_POINTS, 0, NumPoints ); // draw the points
glFlush();
}
8
E. Angel and D. Shreiner: Interactive Computer Graphics 6E ©
*GL*
void
init( void ) {
vec2 points[NumPoints];
// Specifiy the vertices for a triangle vec2 vertices[3] = {
vec2( -1.0, -1.0 ), vec2( 0.0, 1.0 ), vec2( 1.0, -1.0 )
};
// Select an arbitrary initial point inside of the triangle
points[0] = vec2( 0.25, 0.50 );
// compute and store N-1 new points for ( int i = 1; i < NumPoints; ++i ) { int j = rand() % 3; // pick a vertex at random
// Compute the point halfway between the selected vertex
// and the previous point points[i] = ( points[i - 1] + vertices[j] ) / 2.0;
}
// Create a vertex array object GLuint vao[1];
glGenVertexArrays( 1, vao );
glBindVertexArray( vao[0] );
// Create and initialize a buffer object GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER,
sizeof(points), points, GL_STATIC_DRAW );
Sierpinski in GLSL
// Load shaders and use the resulting shader program GLuint program = InitShader( "vshader21.glsl",
"fshader21.glsl" );
glUseProgram( program );
// Initialize the vertex position attribute from the vertex shader
GLuint loc = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( loc );
glVertexAttribPointer( loc, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
glClearColor( 1.0, 1.0, 1.0, 1.0 ); // white background
Sierpinski in GLSL
Sierpinski Vertex Shader
attribute vec4 vPosition;
void main() {
gl_Position = vPosition;
}
…
// Load shaders and use the resulting shader program GLuint program = InitShader( "vshader21.glsl",
"fshader21.glsl" );
glUseProgram( program );
..
Sierpinski Fragment Shader
void main() {
gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
…
// Load shaders and use the resulting shader program GLuint program = InitShader( "vshader21.glsl",
"fshader21.glsl" );
glUseProgram( program );
..
Compiling Code
MacOs
http://www.cs.unm.edu/~angel/BOOK/INTERACTIVE_COMPUTER_GRAPHICS/SIXTH_EDIT ION/apple
Windows/VC++
http://www.cs.unm.edu/~angel/BOOK/INTERACTIVE_COMPUTER_GRAPHICS/SIXTH_EDITI ON/vc
Linux
http://www.cs.unm.edu/~angel/BOOK/INTERACTIVE_COMPUTER_GRAPHICS/SIXTH_EDITI ON/linux
Another Example
Triangles.cpp
#include <iostream>
using namespace std;
#include "vgl.h”
#include "LoadShader.h”
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
const GLuint 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),
ShaderInfo
ShaderInfo shaders[] = { { GL_VERTEX_SHADER,
"triangles.vert" },
{ GL_FRAGMENT_SHADER,
"triangles.frag" },
{ GL_NONE, NULL } };
GLuint program = LoadShaders(*shaders);
glUseProgram(program);
glVertexAttribPointer(vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(vPosition);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAOs[Triangles]);
glDrawArrays(GL_TRIANGLES, 0, NumVertices);
glFlush();
}
Main()
Int
main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(512, 512);
glutInitContextVersion(4, 3);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutCreateWindow(argv[0]);
glewExperimental = GL_TRUE;
if (glewInit()) {
cerr << "Unable to initialize GLEW ... exiting" << endl;
exit(EXIT_FAILURE);
} init();
glutDisplayFunc(display);
glutMainLoop();
// Create a vertex array object GLuint vao[1];
glGenVertexArrays( 1, vao );
glBindVertexArray( vao[0] );
Vertex Arrays
• Vertices can have many attributes
– Position – Color
– Texture Coordinates – Application data
• A vertex array holds these data
• Using types in vec.h
23
point2 vertices[3] = {point2(0.0, 0.0), point2( 0.0, 1.0), point2(1.0, 1.0)};
Vertex Array Object
• Bundles all vertex data (positions, colors, ..,)
• Get name for buffer then bind
• At this point we have a current vertex array but no contents
• Use of glBindVertexArray lets us switch between VBOs
Glunit abuffer;
glGenVertexArrays(1, &abuffer);
glBindVertexArray(abuffer);
// Create and initialize a buffer object GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER,
sizeof(points), points, GL_STATIC_DRAW );
Buffer Object
• Buffers objects allow us to transfer large amounts of data to the GPU
• Need to create, bind and identify data
• Data in current vertex array is sent to GPU
Gluint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points);
http://www.khronos.org/files/opengl-quick- reference-card.pdf
OpenGL Recipes
Sierpinski Again
void 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("Sierpinski Gasket"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
}
Sierpinski World
/* Two-Dimensional Sierpinski Gasket */
/* Generated Using Randomly Selected Vertices */
/* And Bisection */
void myinit() {
/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0);
/* white background */
glColor3f(1.0, 0.0, 0.0); /* draw in red
*/
/* set up viewing */
/* 500 x 500 window with origin lower left
*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 50.0, 0.0, 50.0);
glMatrixMode(GL_MODELVIEW);
No Shaders Here
void display( void )
{ GLfloat vertices[3][2]={{0.0,0.0},{25.0,50.0},{50.0,0.0}};
/* A triangle */
int j, k;
int rand(); /* standard random number generator */
GLfloat p[2] ={7.5,5.0};
/* An arbitrary initial point inside traingle */
glClear(GL_COLOR_BUFFER_BIT); /*clear the window */
/* compute and plots 5000 new points */
glBegin(GL_POINTS);
for( k=0; k<5000; k++){
j=rand()%3; /* pick a vertex at random */
/* Compute point halfway between selected vertex and old point */
p[0] = (p[0]+vertices[j][0])/2.0;
p[1] = (p[1]+vertices[j][1])/2.0; /* plot new point */
glVertex2fv(p); } glEnd();
glFlush(); /* clear buffers */
}
A Recursive OpenGL
Example
The Basic Shape
* initial triangle */
GLfloat v[3][2]={{-1.0, -0.58}, {1.0, -0.58}, {0.0, 1.15}};
int n;
void triangle( GLfloat *a, GLfloat *b, GLfloat *c) /* specify one triangle */
{
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
}
The Inductive step
void divide_triangle(GLfloat *a, GLfloat *b, GLfloat *c, int m)
{
/* triangle subdivision using vertex numbers */
GLfloat v0[2], v1[2], v2[2];
int j;
if(m>0) {
for(j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for(j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for(j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else triangle(a,b,c); /* draw triangle at end of recursion */
Callbacks – same as before
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
divide_triangle(v[0], v[1], v[2], n);
glEnd();
glFlush();
}
void myinit() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glClearColor (1.0, 1.0, 1.0, 1.0);
glColor3f(0.0,0.0,0.0);
}
The main() – same as before
int main(int argc, char **argv) {
n=atoi(argv[1]); /* or set number of subdivision steps here */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("Sierpinski Gasket");
glutDisplayFunc(display);
myinit();
glutMainLoop();
Now As Shaders
Shading & Subdivision
#include "Angel.h”
using namespace std;
const int NumTimesToSubdivide = 5;
const int NumTriangles = 243; // 3^5 triangles generated const int NumVertices = 3 * NumTriangles;
vec2 points[NumVertices];
int Index = 0;
void triangle( const vec2& a, const vec2& b, const vec2& c ) {
points[Index++] = a;
points[Index++] = b;
points[Index++] = c;
Induction
void divide_triangle( const vec2& a, const vec2& b, const vec2& c, int count )
{
if ( count > 0 ) {
vec2 v0 = ( a + b ) / 2.0;
vec2 v1 = ( a + c ) / 2.0;
vec2 v2 = ( b + c ) / 2.0;
divide_triangle( a, v0, v1, count - 1 );
divide_triangle( c, v1, v2, count - 1 );
divide_triangle( b, v2, v0, count - 1 );
}
else {
triangle( a, b, c ); // draw triangle at end of recursion
} }
Shader Mechanics
void init( void )
{ vec2 vertices[3] =
{vec2( -1.0, -1.0 ), vec2( 0.0, 1.0 ), vec2( 1.0, -1.0 )};
// Subdivide the original triangle
divide_triangle( vertices[0], vertices[1], vertices[2],
NumTimesToSubdivide );
// Create a vertex array object GLuint vao;
glGenVertexArraysAPPLE( 1, &vao );
glBindVertexArrayAPPLE( vao );
// Create and initialize a buffer object GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER,
sizeof(points), points, GL_STATIC_DRAW );
// Load shaders and use the resulting shader program
GLuint program =
InitShader( "vshader22.glsl",
"fshader22.glsl" );
glUseProgram( program );
// Initialize vertex position attribute from vertex shader
GLuint loc = glGetAttribLocation(program,
"vPosition" );
glEnableVertexAttribArray( loc );
glVertexAttribPointer( loc, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
/* white background */
}
Same Callbacks
void display( void ) {
glClear( GL_COLOR_BUFFER_BIT );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
glFlush();
}
void keyboard( unsigned char key, int x, int y ) {
switch ( key ) { case 033:
exit( EXIT_SUCCESS );
break;
} }
And the same main()
int main( int argc, char **argv ) {
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA );
glutInitWindowSize( 512, 512 );
glutCreateWindow( "Simple GLSL example" );
init();
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutMainLoop();
return 0;
One Last Example
OpenGL 1.x Code Example
void Display() {
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(1,1,0,1);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
glFlush();
}
45
OpenGL Functions
• Primitives
– Points
– Line Segments – Triangles
• Attributes
• Transformations
– Viewing – Modeling
• Control (GLUT)
• Input (GLUT)
• Query
OpenGL and GLSL
OpenGL and GLSL
• Shader based OpenGL is based less on a
state machine model than a data flow model
• Most state variables, attributes and related pre 3.1 OpenGL functions have been
deprecated
• Action happens in shaders
• Job is application is to get data to GPU
47
OpenGL State
• OpenGL is a state machine
• OpenGL functions are of two types – Primitive generating
• Can cause output if primitive is visible
• How vertices are processed and appearance of primitive are controlled by the state
– State changing
• Transformation functions
• Attribute functions
• Under 3.1 most state variables are defined by the application and sent to the shaders
GLSL
• OpenGL Shading Language
• C-like with
– Matrix and vector types (2, 3, 4 dimensional) – Overloaded operators
– C++ like constructors
• Similar to Nvidia’ s Cg and Microsoft HLSL
• Code sent to shaders as source code
• New OpenGL functions to compile, link and get information to shaders
49
Still Maximal Portability
• Display device independent
• Window system independent
• Operating system independent