2. openGL
OF uses openGL to draw things to your screen.
openGL is a standard which is implemented by
most big operating systems and video cards. It’s
heavily in use by game developers.
Besided openGL there exist another big player
called DirectX. This is not (yet) used by OF.
These slides give you a model of how openGL
roughly works. For in depth information you can
visit www.opengl.org
4. Overview GL
ofTexture
An ofTexture is an object which holds pixels and is
used to draw images to your screen. When you
want to draw an image onto a lets say a 3D cube,
you tell openGL what texture you want to use, the
size, how the pixels are stored in memory etc..
etc.. Nice thing: you don’t need to know the
details, ofTexture does it all for you.
5. Overview GL
ofLight
ofLight is used to tell openGL how to simulate
lights in your 3D scene. In 3D graphics there are a
couple of standard light models. As in the real
world not every light has the same effect on an
object; the same count for openGL. There are i.e.
directional and spot lights.
6. Overview GL
ofMaterial
Each object in the real world has a specific kind of
surface. Some are rough some are smooth. Using
ofMaterial you can define the what kind of material
your 3D object has. openGL uses the material
properties together with the light properties to
calculate the colors of your 3D object.
7. Overview GL
ofVbo
openGL has the concept of “buffers”. In relation
with VBOs you can think of these as arrays with
lots of data describing a 3D scene. For example
where the 3D vertices of a cube are located in your
world. You can send these arrays with information
to your graphic card. VBO is short for Vertex Buffer
Object. ofVbo helps you managing the data you
can store in these buffers.
8. Overview GL
ofFbo
Frame Buffer Objects (FBO) are used to render
things, which you normally render to your screen
to something else, often to another texture. FBOs
are mostly used to apply special effects to your
scenes. ofFbo helps you to setup and manage
FBOs.
9. Overview GL
In short...
Frame Buffer Object used to render
FBO ofFbo offscreen.
Vertex Buffer Object: used to store
VBO ofVbo data about your 3D scene.
OpenGL uses light settings to calculate
Light ofLight the colors of your 3D objects.
Light color values are affected by the
Material ofMaterial material properties.
10. important
Deprecated
The current version of openFrameworks uses
deprecated openGL functions to simulate light and
materials. So if you’re interested in how it’s done,
make sure to look at the current state of openGL.
Though you’re probably safe to use ofLight and
ofMaterial
A very good, the best I’ve found, online and free
tutorial can be found here:
http://www.arcsynthesis.org/gltut/
12. ofLight
Draw something with light
void testApp::draw(){
// use an easy cam!
cam.begin();
// rotate around origin of view space
float xx = 0;
float yy = sin(ofGetElapsedTimef()*0.4)*150;
float zz = cos(ofGetElapsedTimef()*0.4)*150;
light.enable();
light.setPosition(xx,yy,zz);
light.draw();
// draw a box
ofPushStyle();
ofRotateY(45);
ofSetColor(255,255,255);
ofBox(0,0,10,220);
ofPopStyle();
}
13. ofVbo
A VBO is an openGL concept used to reduce the
number of openGL function calls. With one call you
can draw millions of vertices at once.
ofVbo sets up all things related to VBOs. You need
to provide the vertex data yourself.
ofMesh (see the 3D keynote), is an
openFrameworks container for 3D related data.
ofMesh and ofVbo are therefore very related and
used together.
14. ofVbo
So how does this work?
Simple, first create an ofMesh and fill it with some
vertices, then pass it to an ofVbo and you’re ready
to go!
// our vbo/mesh
ofVbo my_vbo;
ofMesh my_mesh;
// store position data
my_mesh.addVertex(ofVec3f(-1,0,1));
my_mesh.addVertex(ofVec3f(1,0,1));
my_mesh.addVertex(ofVec3f(1,0,-1));
my_mesh.addVertex(ofVec3f(-1,0,-1));
// pass the mesh to the vbo
my_vbo.setMesh(my_mesh, GL_STATIC_DRAW);
15. ofVbo
GL_STATIC_DRAW (?)
Here we use raw openGL. The VBO and related
vertex data is stored in high performance memory.
When you supply data to a VBO (remember, which
is just an array), you give openGL a hint on how
often this data is changed. openGL can apply
different performance tricks based on this hint.
16. ofVbo
Hints about VBO data
When vertices data are never or almost never
GL_STATIC_DRAW updated
GL_DYNAMIC_DRA When vertices data could be updated between
each frames.
W
When vertices data could be updated between
GL_STREAM_DRAW each rendering.
17. ofVbo
class My3DObject : public ofNode {
public:
My3DObject() {
// store position data
my_mesh.addVertex(ofVec3f(-1,0,1));
my_mesh.addVertex(ofVec3f(1,0,1));
my_mesh.addVertex(ofVec3f(1,0,-1));
my_mesh.addVertex(ofVec3f(-1,0,-1));
// pass the mesh to the vbo
my_vbo.setMesh(my_mesh, GL_STATIC_DRAW);
}
void customDraw() {
setScale(100);
glDisable(GL_CULL_FACE); We inherit from
rotate(0.05, getXAxis());
my_vbo.draw(GL_QUADS, 0, 4);
ofNode so we got all
ofScale(1.1,1.1,1.1);
the functions like
}
my_vbo.draw(GL_LINE_LOOP, 0, 4);
scaling, positioning,
ofVbo my_vbo;
rotating etc..
ofMesh my_mesh;
};
18. ofVbo
Note that when adding more information then
just the positions, like color, normals, texcoords,
you need to provide the same number of
elements. So 4 vertices mean 4 colors.
// store position data
my_mesh.addVertex(ofVec3f(-1,0,1));
my_mesh.addVertex(ofVec3f(1,0,1));
my_mesh.addVertex(ofVec3f(1,0,-1));
my_mesh.addVertex(ofVec3f(-1,0,-1));
// store colors
my_mesh.addColor(ofFloatColor(1.0, 0.0, 0.0, 1.0));
my_mesh.addColor(ofFloatColor(0.0, 1.0, 0.0, 1.0));
my_mesh.addColor(ofFloatColor(0.0, 0.0, 1.0, 1.0));
my_mesh.addColor(ofFloatColor(0.0, 1.0, 1.0, 1.0));
19. ofVbo
Mesh
void setMesh(const ofMesh& mesh, int usage)
void updateMesh(const ofMesh& mesh)
Vertex Data
void setVertexData(const ofVec3f* verts, int total, int usage)
void setVertexData(const ofVec2f* verts, int total, int usage)
void updateVertexData(const ofVec3f* verts, int total)
void updateVertexData(const ofVe2f* verts, int total)
GLuint getVertId()
20. ofVbo
TexCoord data
void setTexCoordData(const ofVec2f* texcoords, int total, int usage)
void updateTexCoordData(const ofFloatColor* colors, int total)
GLuint getTexCoordId()
Normal data
void updateNormalData(const ofFloatColor* colors, int total)
void setNormalData(const ofVec3f* normals, int total, int usage)
GLuint getNormalId()
21. ofVbo
Color data
void setColorData(const ofFloatColor* colors, int total, int usage)
void updateColorData(const ofFloatColor* colors, int total)
GLuint getColorId()
Index data
void setIndexData(const ofIndexType* indices, int total, int usage)
void updateIndexData(const oofIndexType* indices, int total)
GLuint getIndexId()
22. ofFbo
A FBO, frame buffer object, is mainly used to
render something to a offscreen “thing”. This thing
can be a texture which you then can apply on
something else.
Note: although a FBO has the word buffer in it, it
does not allocate any memory itself. You hookup
other objects that have memory storage such as
render buffers or textures.
23. ofFbo
How to use an ofFbo
Create a member for the ofFbo
•Allocate the size of the FBO
•Call begin()
•[DRAW]
•call end()
•Use the fbo texture to draw the capture [DRAW].
Pseude code (!)
my_fbo.allocate(320,240);
...
my_fbo.begin();
my_cam.begin();
my_3d_object.draw();
my_cam.end();
my_fbo.end();
my_fbo.draw(0,0);
24. ofFbo example
Custom 3D object using ofVbo and ofMesh testApp.h (standard functions hidden)
class My3DObject : public ofNode {
public: class testApp : public ofBaseApp{
My3DObject() {
// store position data
public:
my_mesh.addVertex(ofVec3f(-1,0,1));
ofEasyCam cam;
my_mesh.addVertex(ofVec3f(1,0,1));
My3DObject my_3d_object;
my_mesh.addVertex(ofVec3f(1,0,-1));
ofFbo my_fbo;
my_mesh.addVertex(ofVec3f(-1,0,-1)); };
my_mesh.addColor(ofFloatColor(1.0, 1.0, 0.0, 1.0));
my_mesh.addColor(ofFloatColor(1.0, 1.0, 1.0, 1.0));
my_mesh.addColor(ofFloatColor(1.0, 0.0, 1.0, 1.0));
my_mesh.addColor(ofFloatColor(0.0, 1.0, 1.0, 1.0));
// pass the mesh to the vbo
my_vbo.setMesh(my_mesh, GL_STATIC_DRAW);
}
void customDraw() {
setScale(100);
glDisable(GL_CULL_FACE); // we want to see both sides.
rotate(0.05, getXAxis());
my_vbo.draw(GL_QUADS, 0, 4);
ofScale(1.1,1.1,1.1);
my_vbo.draw(GL_LINE_LOOP, 0, 4);
}
ofVbo my_vbo;
ofMesh my_mesh;
};
25. ofFbo example
Drawing the VBO (not into the FBO...yet)
void testApp::setup(){
ofBackground(33,33,33);
my_fbo.allocate(ofGetWidth(),ofGetHeight());
}
void testApp::draw(){
cam.begin();
my_3d_object.draw();
}
26. ofFbo example
Drawing into the FBO
void testApp::setup(){
ofBackground(33,33,33);
my_fbo.allocate(ofGetWidth(),ofGetHeight());
}
void testApp::draw(){
my_fbo.begin();
cam.begin();
my_3d_object.draw();
cam.end();
my_fbo.end();
my_fbo.draw(0,0,320,240);
}
27. ofFbo example
Drawing the FBO texture more then once
void testApp::draw(){
cam.begin();
my_fbo.begin();
cam.begin();
my_3d_object.draw();
cam.end();
my_fbo.end();
for(int i = 0; i < 2; ++i) {
for(int j = 0; j < 2; ++j) {
my_fbo.draw(i*320,j*240,320,240);
}
}
}
28. ofFbo
void allocate(int width, int height, int internalformat = GL_RGBA, int numSamples = 0)
void allocateForShadow(int width, int height)
void draw(float x, float y)
void draw(float x, float y, float width, float height)
float getWidth()
float getHeight()
void begin()
void end()
ofTexture& getTexture(int attachmnetPoint = 0)
For more information see ofFbo.h
29. ofShader
Shaders let you create amazing effects. A shader is
a small program which runs on your graphics card.
There are several kinds of programs you can create
and the programs run in parallel on your graphics
card.
You can create a shader for vertices and i.e.
change the position of these. Such a shader is
called a vertex shader. Another type of shader is
called a fragment shader which operates on one
pixel.
30. ofShader
Vertex and fragment shaders
So each shader has a specific purpose. Vertex and
fragment shaders form a “group”. Often with a
“shader” we mean both a vertex and fragment
shader.
There are more kinds of shaders like geometry
shaders which let you generate vertices on the
graphics card. Mac OSX 10.6.x does not support
these. 10.7 will!
31. ofShader
For a shader you need to write the code for the
shader-program. The language is called openGL
Shader Language (GLSL) and looks a lot like C.
Just like any other programming language you
need to compile it. This is done by the openGL
driver. openGL provides functions to compile the
shaders.
ofShader sets up all necessary things like loading
the shader, compiling, linking, etc..
32. ofShader
Geometry Shader Shaders are executed in
different, successive
stages.
Vertex Shader
Fragment Shader
33. ofShader
Commonly used file extensions
.vert For vertex shaders
.frag For fragment shaders
.geom For geometry shaders
34. Vertex Shader
Basic vertex shader example
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
This example shows a very basic shader. It uses
(by openGL) globally defined variables.
gl_Position The final position of the 3D point
gl_ModelViewProjectionMatrix Converts a point from object space to screen space
The 3D position we’re working with. When you created
gl_Vertex an ofMesh and added vertices to it, this variable will
hold the value of the set vertices.
35. Fragment Shader
Basic fragment shader example
void main() {
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
A fragment shader is executed for each fragment
and is the final shader stage. It is executed after
the vertex shader.
gl_FragColor The final color of a fragment
36. Recap shaders
So what you need to remember is that a shader is a
program which runs on GPU. The vertex shader is
used to set a position of a 3D point; the fragment
shader is used to set the color of a fragment.
There are several globally defined variables, i.e.
gl_Position, gl_ModelViewProjectionMatrix,
gl_Vertex, gl_FragData.
Note: some of these are deprecated
37. Shader programming
GLSL looks like C. There are several data types and
functions. Just like any other language the
variables have scope.
Some common data types are int, vec2, vec3, vec4,
mat3 and mat4. For boolean values you can use an
int. GLSL has some special variable identifiers
called varying and uniform.
varying variables will be interpolated between the
vertex and fragment shader. uniform variable will
stay... uniform (immutable)
38. Shader programming
Lets say you have two vertices and a varying
variable. When the value is 0.0 for the first vertex
and 1.0 for the second vertex it will be
interpolated between 0.0 and 1.0 between the
vertices.
v0 0.1
0.5
0.95
v1
39. Shader programming
Uniform variables are used to “communicate”
between a shader and the host application (the OF
application in this case).
To change a value of an uniform variable your
application needs to know where in (GPU) memory
the location of the variable is stored. openGL uses
glGetUniformLocation(program, name) for this.
You don’t have to worry about this because
ofShader handles this for you.
40. Attributes
There is another type of variables I didn’t mention
yet. Attributes are a special kind of variables which
are the way to go when you want to start
programming shaders. They allow you to use
custom data for gl_Vertex, gl_FrontColor,
gl_TexCoord etc... For now we will focus on the
globally defined variables as this makes it a lot
easier to start creating shaders.
41. Using ofShader
To create a shader, follow these steps:
1. Lets assume we call the shader “my_shader”.
Then create two files my_shader.vert and
my_shader.frag in your data directory.
2. Create a member ofShader my_shader in your
testApp.
3. Load the shaders
4. Create a simple ofVBO/ofMesh and draw while
the shader is enabled.
48. ofShader
Using uniforms
Uniforms allow you to change values of variables in a
shader. You can do this by defining a uniform
variable and using one of the setUniform**()
functions. The next example uses an uniform to
change the value of gl_FragData
50. ofShader
Using uniforms
When you want to set an uniform value make sure
that you enable the shader first! You can do this by
calling the
begin() function.
void testApp::draw(){
cam.begin();
my_shader.begin();
my_shader.setUniform1i("u_color", use_color);
my_vbo.draw(GL_QUADS,0,4);
my_shader.end();
cam.end();
}
52. ofShader
Simple light
Here follows an example of a simple light shader. For more
information on shaders you can visit this page which has lots of
interesting information:
http://www.arcsynthesis.org/gltut/
of.vert of.frag
varying vec3 v_light_dir;
varying vec3 v_normal; varying vec3 v_light_dir;
uniform float time; varying vec3 v_normal;
uniform float time;
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
void main() {
// get view space position.
vec4 diffuse_color = vec4(1.0, 0.0, 0.0, 1.0);
vec4 position = gl_ModelViewMatrix * gl_Vertex;
// IMPORTANT: you need to normalize the normal and light dir!
// we create our light position in "view space".
float ndotl = max(dot(normalize(v_normal), normalize(v_light_dir)),0.0);
vec3 light_position = vec3(1.0, sin(time)*130.0,1.0);
vec4 result_color = diffuse_color * ndotl;
v_light_dir = (position.xyz - light_position);
gl_FragColor = result_color;
}
// get normal in eye coordinates.
v_normal = (gl_NormalMatrix * gl_Normal);
}
53. ofShader
General
void load(string shaderName)
void load(string vertName, string fragName, string geomName = “”)
void begin()
void end()
Uniforms: integers
void setUniformTexture(const char* name, ofBaseHasTexture& img, int textureLocation)
void setUniformTexture(const char* name, ofTexture& img, int textureLocation)
void setUniform1i(const char* name, int v1)
void setUniform2i(const char* name, int v1, int v2)
void setUniform3i(const char* name, int v1, int v2, int v3)
void setUniform4i(const char* name, int v1, int v2, int v3, int v4)