SourceForge.net Logo
Home
Documentation
Tutorials
    Beginning
    Gears
    Noise
    Bumpmapping
    Point sprites
    Hello World
    Armature
    Geometryshader
    Toolscripting
    Keyframe animation
    Instancing
    Bezier Surface
    Deferred shading
    Depth peeling
    Particle System
Links
Support This Project
OpenGL
Welcome to the second Lumina tutorial

This tutorial will demonstrate to use the Luminas scripting for animating some gears
like the glxgears example. The script and shaders are also usefull for own projects.

1. Create objects
For this tutorial we will need a node with some items:

1. Vertexshader
2. Fragmentshader
3. Script
4. Some gear meshes

The gear creator script, will open a dialog to get the number of teeth create gears
with 8, 12 and 16 teeth.

2. Vertexshader
Add this code to the Vertexshaders editor:
attribute vec3 Tangent;

varying vec3 T,N;

void main(void){
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
N = normalize(gl_NormalMatrix * gl_Normal);
T = normalize(gl_NormalMatrix * Tangent);
}

The "Tangent" attribute is a vector that is perpendicular to the normal vector. In the
gears case the tangent vector is radial aligned. We will use that vector for anisotropic
shading which simulates a metallic surface.
The varying T and N are the in worldspace projected normal and tangent vectors that will
be passed to the fragmentshader.

3. Fragmentshader
Add this code to the Fragmentshaders editor:
varying vec3 T,N;

uniform vec4 col;
void main(void){
vec3 lv = vec3 (0.0 ,0.707,0.707);
vec3 t = normalize (T);
vec3 n = normalize(lv - t * dot(lv,t));
float r = pow(max(dot(reflect (lv,n),vec3(0.0,0,-1)), 0),8);
gl_FragColor = (col * dot(n,lv) + r ) * dot(normalize(N),lv) + col * 0.2 ;
}

The code is not hard to understand:
The varyings T and N are inputs from from the vertexshader. "lv" is a faked parallel
light. The next line normalize the tangent that is needed for calculating the
anisotropic normalvector "n". "r" is the reflected lightpart.
The last line composite the lightning. "col" is the gears color "dot(n,lv)" the
anisotropic term. Together with the reflected part, it will be weighted by a
multiplication with the direction depend luminance. The last term adds a little emissive
light.
This is not a physical correct model, but it looks like machined metal.


3. Script
Add this code to the Scripts editor:
shader = gl.Shader(Vertexshader,Fragmentshader);

tan = shader.Loc("Tangent");

function render(){
shader.Bind();

gl.Rotate(60 * World.getTime(), 0,1,0);
gl.PushMatrix();
gl.Translate(-10,0,0);
gl.Rotate(20 * World.getTime(), 0,0,1);

shader.Uniform("col",1.0,0.9,0.4,0);

Gear12.Tangent.Bind(tan);
Gear12.Vertex.Bind();
Gear12.Normal.Bind();
Gear12.Index.Draw();

gl.PopMatrix()
gl.Translate(10,0,0);

gl.Rotate(-30 * World.getTime(), 0,0,1);

shader.Uniform("col",0.8,0.8,1.0,0);

Gear8.Tangent.Bind(tan);
Gear8.Vertex.Bind();
Gear8.Normal.Bind();
Gear8.Index.Draw();

shader.Uniform("col",0.0,0.4,0.0,0);
gl.Translate(0,0,-2);

Gear16.Tangent.Bind(tan);
Gear16.Vertex.Bind();
Gear16.Normal.Bind();
Gear16.Index.Draw();
}

This code should be self-explanatory. The correct distance between two gears is the sum
of both number of teeth. The generated gear meshes are so rotated that even gears are
in mesh.

4. Running the Script
After running the script it should look like:



5. Lets play with gears
Here is a script that draws a more complex example:
shader = gl.Shader(Vertexshader,Fragmentshader);

tan = shader.Loc("Tangent");

function render(){
gl.Rotate(60 * World.getTime(), 0,1,0);
gl.Translate(0,0,1);
shader.Uniform("col",0.0,0.4,0.0,0);

Gear16.Tangent.Bind(tan);
Gear16.Vertex.Bind();
Gear16.Normal.Bind();

Gear16.Index.Draw();

gl.Rotate(30 * World.getTime(), 0,0,1);

shader.Uniform("col",0.8,0.8,1.0,0);
Gear8.Tangent.Bind(tan);
Gear8.Vertex.Bind();
Gear8.Normal.Bind();

for (i = 0 ; i < 360; i += 90){
gl.PushMatrix();
gl.Rotate(i,0,0,1);
gl.Translate(24,0,0);
gl.Rotate(60 * World.getTime(), 0,0,1);
Gear8.Index.Draw();

gl.PopMatrix();
}

shader.Uniform("col",1.0,0.9,0.4,0);
gl.Translate(0,0,-2);

Gear12.Tangent.Bind(tan);
Gear12.Vertex.Bind();
Gear12.Normal.Bind();

for (i = 0 ; i < 360; i += 90){
gl.PushMatrix();
gl.Rotate(i,0,0,1);
gl.Translate(24,0,0);
gl.Rotate(60 * World.getTime(), 0,0,1);
Gear12.Index.Draw();

gl.PopMatrix();
}


gl.Rotate(-60 * World.getTime(), 0,0,1);

shader.Uniform("col",0.5,0.2,0.8,0);
Gear12.Index.Draw();
}



6. A differential gear
shader = gl.Shader(Vertexshader,Fragmentshader); 

tan = shader.Loc("Tangent");

function Draw(Gear){
Gear.Tangent.Bind(tan);
Gear.Vertex.Bind();
Gear.Normal.Bind();

Gear.Index.Draw();
}

function render(){
alpha = World.getTime();
beta = 60 * Math.sin(World.getTime()/3*3.141)

gl.Rotate(60 * World.getTime(), 0,1,0.5);
gl.Scale(-1,-1,-1);
gl.Rotate(-10, 1,0,0);

shader.Uniform("col",1.0,0.9,0.4,0);

gl.PushMatrix();
gl.Translate(16,0,0);
gl.Rotate(90,0,1,0);
gl.Rotate(80 * alpha,0,0,1);
Draw(Gear12);
gl.PopMatrix();

gl.Rotate(-60 * alpha,0,0,1);

shader.Uniform("col",0.0,0.4,0.0,0);

gl.PushMatrix();
gl.Translate(0,0,12);
Draw(Gear16);
gl.PopMatrix();

shader.Uniform("col",0.8,0.8,1.0,0);

gl.PushMatrix();
gl.Translate(0,0,8);
gl.Rotate(beta,0,0,1);
Draw(Gear8);
gl.PopMatrix();

gl.PushMatrix();
gl.Rotate(90,0,1,0);
gl.Translate(0,0,8);
gl.Rotate(-beta,0,0,1);
Draw(Gear8);
gl.PopMatrix();

gl.PushMatrix();
gl.Rotate(180,0,1,0);
gl.Translate(0,0,8);
gl.Rotate(beta,0,0,1);
Draw(Gear8);
gl.PopMatrix();

shader.Unbind();
}



EDIT