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
Geometry Shader

I've got my GF8800GTS and it's time for a new tutorial. Geomtry shaders are supported
since Lumina-0.2.5 (but never tested)

First edit the rendering script. Replace:
shader = gl.Shader(Vertexshader,Fragmentshader);
by
shader =
gl.Shader(Vertexshader,Geometryshader,Fragmentshadr,gl.TRIANGLES,gl.TRIANGLES,3);

The first 3 arguments are the shader source objects, the 4th the input primitive, th 5th
the outputprimitive and the last the maximum number of emited vertices.

For starting it's recomment to use a dummy geometry shader:
      

#version 120
#extension GL_EXT_geometry_shader4 : enable
void main(){
for (int i = 0 ; i < 2 ; i ++){
gl_Position = gl_PositionIn[i];
gl_TexCoord[0] =gl_TexCoordIn[i][0];
EmitVertex();
}
gl_Position = (gl_PositionIn[2]+gl_PositionIn[1]) * 0.5;
gl_TexCoord[0] =gl_TexCoordIn[2][0];
EmitVertex();

}

This shader does nothing except passing all 3 vertices of triangle to the new triangle.
This example isn't very usefull jet. So start with a more advanced:


Tesselation
Geometry shader usefull for tesselating triangles into smaller triangles:

      

#version 120
#extension GL_EXT_geometry_shader4 : enable

void calcVertex(float a, float b, float c){
gl_Position = gl_PositionIn[0] * a + gl_PositionIn[1] * b + gl_PositionIn[2] *
c;
gl_TexCoord[0] = gl_TexCoordIn[0][0]*a + gl_TexCoordIn[1][0]*b +
gl_TexCoordIn[2][0]*c;
EmitVertex();
}

void main(void){
calcVertex(0.5,0.0,0.5);
calcVertex(1.0,0.0,0.0);
calcVertex(0.5,0.5,0.0);

EmitVertex();
calcVertex(0.0,1.0,0.0);
calcVertex(0.0,0.5,0.5);

EmitVertex();
calcVertex(0.0,0.0,1.0);
calcVertex(0.5,0.0,0.5);

EmitVertex();
calcVertex(0.5,0.5,0.0);
calcVertex(0.0,0.5,0.5);
}


This code creates 4 smaller triangles that fit into the input triangle. Remember to set
the maximum output vertices to 12. The code doesn't look optimised, but the compiler
should remove all multiplications with 0.0 or 1.0. It's more important to use the last
vertex of a output primitive as first vertex for the next primitive if it's possible.
This code isn't usfully too, but can help to write a npatch or displacement shader. a
tessellation like this can be extended by the stream out feature.

Tesselation with Tringle Stripes and displacement mapping
The last example needs 9 calculation. With triangle stripes 8 calculation woud be
enough.
Mor important are stripes for higher tesselations. An example that tesselates a triangle
into 16 subtriangles. With stripes a vertex can be reused up to 3 times.

For the displacement mapping it's recommend for the input vertices to read the heightmap
in the vertex shader or encode the value into the attributes. That sample can be shared
for up to 6 different input primitives.

The Vertexshader should do so many steps as possible. This vertex shader is designed for
spheres only, for more complex objects use the normal vector as offset:
   

uniform sampler2D Depthmap;

varying vec4 Pos1;
varying vec4 Pos2;

void main(void){
gl_TexCoord[0] = gl_MultiTexCoord0;
Pos1 = gl_ModelViewProjectionMatrix * gl_Vertex;
Pos2 = gl_ModelViewProjectionMatrix * (gl_Vertex *vec4(1.1,1.1,1.1,1.0));
float mix = texture2D(Depthmap,gl_TexCoord[0].st).r;
gl_Position = (1.0-mix) * Pos1 + mix * Pos2;
gl_FrontColor = vec4(1.0,1.0,1.0,1.0);
}



The geometry use the vertexshaders output. The shader is optional and tessellates each
triangle into 16 new triangles. The number of output primitives is 24 and the output
type is gl.TRIANGLE_STRIPE. For debugging the color will be set to white for new and
black for the 3 inputs vertices:
 

#version 120
#extension GL_EXT_geometry_shader4 : enable

uniform sampler2D Depthmap;
varying in vec4 Pos1[];
varying in vec4 Pos2[];

void passVertex(int v){
gl_TexCoord[0] = gl_TexCoordIn[v][0];
gl_Position = gl_PositionIn[v];
gl_FrontColor = vec4(0.0,0.0,0.0,0.0);
EmitVertex();
}

void calcVertex(float a, float b, float c){
gl_TexCoord[0] = gl_TexCoordIn[0][0]*a
gl_TexCoord[0] += gl_TexCoordIn[1][0]*b;
gl_TexCoord[0] += gl_TexCoordIn[2][0]*c;
float mix = texture2D(Depthmap,gl_TexCoord[0].st).r;
gl_Position = (1.0-mix) * (Pos1[0] * a + Pos1[1] * b + Pos1[2] * c);
gl_Position += mix *(Pos2[0] * a + Pos2[1] * b + Pos2[2] * c);
gl_FrontColor = vec4(1.0,1.0,1.0,1.0);
EmitVertex();
}



void main(void){

calcVertex(0.75, 0.25, 0.00);
passVertex(0);
calcVertex(0.75, 0.00, 0.25);
EndPrimitive();

calcVertex(0.50, 0.50, 0.00);
calcVertex(0.75, 0.25, 0.00);
calcVertex(0.50, 0.25, 0.25);
calcVertex(0.75, 0.00, 0.25);
calcVertex(0.50, 0.00, 0.50);
EndPrimitive();

calcVertex(0.25, 0.75, 0.00);
calcVertex(0.50, 0.50, 0.00);
calcVertex(0.25, 0.50, 0.25);
calcVertex(0.50, 0.25, 0.25);
calcVertex(0.25, 0.25, 0.50);
calcVertex(0.50, 0.00, 0.50);
calcVertex(0.25, 0.00, 0.75);
EndPrimitive();

passVertex(1);
calcVertex(0.25, 0.75, 0.00);
calcVertex(0.00, 0.75, 0.25);
calcVertex(0.25, 0.50, 0.25);
calcVertex(0.00, 0.50, 0.50);
calcVertex(0.25, 0.25, 0.50);
calcVertex(0.00, 0.25, 0.75);
calcVertex(0.25, 0.00, 0.75);
passVertex(2);
EndPrimitive();
}


Sphere with 2048 Quads, tessellated into 65536 Triangles
EDIT