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
Version 0.3.1 is required


Depth peeling is a technique that can be used for order independent transparency, and
other algorithms that requires more than one layer in Z direction. This tutorial
implements order independent transparency with four color layers.


Depth peeling setup
The first step is to build the environment for depth peeling. Enter that following lines
into the Console:

Global = World.addNode("Global");
Global.addScript("Globalscript");
for(i=1;i<=2;i++)Global.addTexture("Depth_"+i);
for(i=1;i<=4;i++)Global.addTexture("Color_"+i);
Global.addVertexShader("CopyVertex");
Global.addFragmentShader("CopyFragment");

A node, a script, 6 textures, and shader for composing shall appear. Paste that code
into the script:


copyshader = gl.Shader(CopyVertex,CopyFragment);
for (i = 0; i < 4; i++)copyshader.Uniformi("Color" + i,i);

Color = Array(Color_1,Color_2,Color_3,Color_4);
Depth = Array(Depth_1, Depth_2, Depth_1, Depth_2, Depth_1);

rt = Array(4);
for (i = 0; i < 4; i++)rt[i] = gl.Framebuffer();

resizeEvent(World.getCamWidth(),World.getCamHeight());
function resizeEvent(W,H){
for (i = 0; i < 2; i++){
Depth[i].ImageRect(W,H,gl.DEPTH_COMPONENT24);
Depth[i].MinFilter=gl.NEAREST;
Depth[i].MagFilter=gl.NEAREST;
Depth[i].CompareMode = true;
}
for (i = 0; i < 4; i++){
Color[i].ImageRect(W,H,gl.RGBA8);
Color[i].MinFilter=gl.NEAREST;
Color[i].MagFilter=gl.NEAREST;
rt[i].Append(Color[i],0);
rt[i].Append(Depth[i%2]);
}
}

This is the init part of the code. It create four Framebuffer Object, and inits the
textures, with the same size as the camera window. The Arrays and for loops allow a more
compact code.
Now the rendering function:

function render(){
// first pass
rt[0].Bind();
gl.Clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
World.Call("pass1");

This first pass will be rendered like every in other render.

//depth peeling passes
gl.Enable(gl.POLYGON_OFFSET_FILL);
for(i = 1; i < 4; i++){
gl.PolygonOffset(-i,0);
Depth[i%2+1].Bind(14); //bind the previous Depthbuffer to TMU14
rt[i].Bind();
gl.Clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
World.Call("passn")
}
rt[3].Unbind();
gl.Disable(gl.POLYGON_OFFSET_FILL);

This thers the depth peeling passes. The Depthbuffer from the previous pass is used to
skip already stored fragments. The polygonoffset is required to avoid artifacts. The
depth texture is bound to Texture Unit14 (15 may be used by lumina internally, for
editing) All others can be used during the rendering pass.

for (i = 0; i < 4; i++)Color[i].Bind(i);
Color[0].Bind(0);
copyshader.Bind();
gl.Begin(gl.QUADS);
gl.Vertex(1,1);
gl.Vertex(1,0);
gl.Vertex(0,0);
gl.Vertex(0,1);
gl.End();
}

This code part combines the four color buffers, into the backbuffer. This fragment
shader will mix the colors with help of the alpha values (Paste code to CopyFragment):

#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect Color0;
uniform sampler2DRect Color1;
uniform sampler2DRect Color2;
uniform sampler2DRect Color3;

void main(void){
vec4 c[4];
c[0] = texture2DRect(Color0,gl_FragCoord.xy);
c[1] = texture2DRect(Color1,gl_FragCoord.xy);
c[2] = texture2DRect(Color2,gl_FragCoord.xy);
c[3] = texture2DRect(Color3,gl_FragCoord.xy);
gl_FragColor = c[0] * c[0].a
+(1.0 - c[0].a)*(c[1]*c[1].a
+(1.0 - c[1].a)*(c[2]*c[2].a
+(1.0 - c[2].a)*(c[3]*c[3].a)));
}

The required vertex shader is dummy (CopyVertex):

void main (void){
gl_Position = gl_Vertex * 2.0 - 1.0;
}


A transparent Teapot
Now it's possible to reuse some code from the "Bezier Surface" tutorial. The script
have to be modified a little bit, to support the passes:

shader = gl.Shader(Vertexshader,Fragmentshader);
shader.Bind()
Teapot.Uniform(shader,"Bezier");

shaderN = gl.Shader(Vertexshader,Fragmentshader_1);
shaderN.Bind()
Teapot.Uniform(shaderN,"Bezier");
shaderN.Uniformi("peel",14);

function pass1(){
gl.Rotate(60 * World.getTime(),1,1,1);
shader.Bind()
Quadric.Vertex.Bind();
Quadric.Index.DrawInstanced(32);
}

function passn(){
gl.Rotate(60 * World.getTime(),1,1,1);
shaderN.Bind()
Quadric.Vertex.Bind();
Quadric.Index.DrawInstanced(32);
}

The available Fragmentshader should write a valid alpha value:

varying vec3 T,B,N;
void main (void){
gl_FragColor.rgb = normalize(N) * sign(N.z) * 0.5 + 0.5;
gl_FragColor.a = 1.2 - abs(normalize(N).z);
}

A modified copy for the depth peeling passed is required (Fragmentshader_1):

#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRectShadow peel;
varying vec3 T,B,N;

void main (void){
if(shadow2DRect(peel, gl_FragCoord.xyz).r > 0.5) discard;
gl_FragColor.rgb = normalize(N)* sign(N.z) * 0.5 + 0.5;
gl_FragColor.a = 1.2 - abs(normalize(N).z);
}

The vertex shader didn't change. The result should look like this:


References:
http://developer.nvidia.com/object/order_independent_transparency.html
EDIT