Home   Donators   Contact Us       

<< Previous Tutorial     Next Tutorial >>

Tutorial 19 - Sorted blending

Theory

When we render models to the screen, OpenGL uses a depth buffer to determine if pixels of a polygon is in-front or behind other polygons already rendered to the screen. Before a pixel of a polygon is drawn, OpenGL first checks the depth buffer to see if another pixel isn't already drawn at the same location that is in-front of the pixel to be drawn. If so, then the pixel will not be drawn. Consider the two polygons below.

At first glance there does not seem to be an issue. The problem is that the blue polygon is in fact a transparent polygon, yet part of the green polygon behind the blue polygon is not drawn. Why does this happen and how can we fix it?

The blue polygon is rendered before the green polygon. By the time the green polygon is drawn, the depth buffer indicates that part of the green polygon should not be rendered because that space is already occupied by the blue polygon in front of it.

The fix to this problem is very easy. All we need to do is to render polygons furthest from us first and thereafter the polygons closer to us. So before rendering, we simply sort our models from furthest to closest and then render them to the screen in that order.

The image above illustrates the outcome when the green polygon is rendered before the blue polygon.

Tutorial Steps
Tutorial created with Real Studio 2011 Release 4.3.
1. Download and extract the following project base to a new folder:
2. Open the project file with Real Studio.
3. Add the following code to the Open event of Window1:
Dim model As R3Model ' temporary model object
Dim light As R3LightSource  ' light source
Dim cam As R3Camera ' camera used in our scene

me.Maximize ' maximize the window
me.MouseCursor = REALbasic.System.Cursors.StandardPointer ' set mouse cursor

' instantiate the Scene object

Scene = new R3Scene
Scene.BackgroundColor.SetValue(0.3, 0.3, 0.3) ' set background color

' load textures used in scene

Scene.Texture.Append new R3Texture(imgMoonText, imgMoonBump, 1) 

' add sun

light = new R3LightSource
light.Position.SetValue(-10, 0, 3)
light.Ambient.SetValue(0, 0, 0, 1)
light.Diffuse.SetValue(1, 1, 1, 1)
light.Specular.SetValue(1, 1, 1, 1)
Scene.LightSource.Append light

' add camera

cam = new R3Camera
cam.DollyOut 6 ' move back so that we can get the model in our view
Scene.Camera.Append cam

Scene.ActiveCamera = 0 ' set the index of the active camera

' instantiate moon model

model = R3_Tut00019Moon
model.SurfaceColor(0).SetValue(1, 1, 1, 0.2)
Scene.AppendModel model

' instantiate red transparent sphere

model = R3_Tut00019Sphere(60, 40)
model.Scale.SetValue(0.25, 0.25, 0.25)
model.Position.SetValue(0, 0, 1.3)
model.SurfaceColor(0).SetValue(1, 0, 0, 0.8) ' transparent red
Scene.AppendModel model

' instantiate blue transparent sphere

model = R3_Tut00019Sphere(60, 40)
model.Scale.SetValue(0.25, 0.25, 0.25)
model.Position.SetValue(1.6, 0, 0)
model.SurfaceColor(0).SetValue(0, 0, 1, 0.8) ' transparent red
Scene.AppendModel model

' instantiate yellow transparent sphere

model = R3_Tut00019Sphere(60, 40)
model.Scale.SetValue(0.25, 0.25, 0.25)
model.Position.SetValue(0, 0, -1.9)
model.SurfaceColor(0).SetValue(1, 1, 0, 0.8) ' transparent red
Scene.AppendModel model

' instantiate green transparent sphere

model = R3_Tut00019Sphere(60, 40)
model.Scale.SetValue(0.25, 0.25, 0.25)
model.Position.SetValue(-2.3, 0, 0)
model.SurfaceColor(0).SetValue(0, 1, 0, 0.8) ' transparent red
Scene.AppendModel model

Timer1.Enabled = true
4. Add the following code to the Paint event of Window1:
OpenGLSurface1.Render ' refresh the OpenGL surface
5. Add the following code to the Close event of Window1:
Scene = nil ' remove the scene object from memory
6. Add the following code to the Open event of OpenGLSurface1:
R3_OGLInitialize ' initalize OpenGL environment
7. Add the following code to the Render event of OpenGLSurface1:
' is the scene object instantiated?
if Scene <> nil then

' render the modal normally
R3_OGLRenderScene Scene

end if
8. Add the following code to the Resized event of OpenGLSurface1:
' set the viewport rectangle

OpenGL.glViewport 0, 0, OpenGLSurface1.Width, OpenGLSurface1.Height

' set up the perspective projection settings

OpenGL.glMatrixMode OpenGL.GL_PROJECTION
OpenGL.glLoadIdentity
OpenGL.gluPerspective 60.0, OpenGLSurface1.Width / OpenGLSurface1.Height, 1, 100.0

' select and reset the modelview matrix

OpenGL.glMatrixMode OpenGL.GL_MODELVIEW
OpenGL.glLoadIdentity
9. Add the following code to the Action event of Timer1:
Dim cam As R3Camera
Dim light As R3LightSource
Dim model As R3Model

cam = Scene.Camera(Scene.ActiveCamera) ' get current active camera in scene

cam.DollyPosition.RotateAroundPoint(Scene.Model(0).Position, 0, 1, 0) ' rotate camera dolly around the position of the moon
cam.CameraRotation.Rotate(0, 1, 0) ' rotate camera to keep it pointing to the moon

light = Scene.LightSource(0) ' get the sun light source
light.Position.RotateAroundPoint(Scene.Model(0).Position, 0, 1, 0) ' rotate light source around position of the moon

model = Scene.Model(1) ' red sphere
model.Position.RotateAroundAxis(new R3Vector(1, 0, 0), 2) ' rotate sphere around moon

model = Scene.Model(2) ' blue sphere
model.Position.RotateAroundAxis(new R3Vector(0, 0, 1), 3) ' rotate sphere around moon

model = Scene.Model(3) ' yellow sphere
model.Position.RotateAroundAxis(new R3Vector(1, 0, 0), -4) ' rotate sphere around moon

model = Scene.Model(4) ' green sphere
model.Position.RotateAroundAxis(new R3Vector(0, 0, 1), -5) ' rotate sphere around moon

OpenGLSurface1.Render ' refresh the OpenGL surface
10. Save and run the project. Notice how we used a transparent texture map image to make the moon transparent, as well as transparent colors for the spheres rotating about the moon.
Code Analysis

In the previous tutorials our R3_OpenGL.R3_OGLRenderScene function made use of a for loop to sequentially render the models in our scene, irrespective of their distance from the camera.

If you inspect the R3_OpenGL.R3_OGLRenderScene function used in this tutorial, you will notice that we now first build a binary sorted tree that arranges the models from furthest to closest, with respect to the camera's position. We then call the R3_OpenGL.R3_OGLRenderModelTree function with the root node, to render our models in this order. The image below illustrates what a binary sorted tree might look like for 3 different models, each having a different distance from our camera.

The yellow node represents the root node of our sorted model tree. So how does the R3_OpenGL.R3_OGLRenderModelTree function traverse this tree?

The R3_OpenGL.R3_OGLRenderModelTree function is a recursive function (a function that calls itself) using the following logic:

  • Render the left child of the current node with R3_OGLRenderModelTree.
  • Render the current node.
  • Render the right child of the current node R3_OGLRenderModelTree.

If you apply the logic above to the root node of the tree, you will notice that the models are rendered in the following order:

  • Scene.Model(2): Distance = 4
  • Scene.Model(0): Distance = 2
  • Scene.Model(1): Distance = 1

A binary sorted tree provides a quick way to sort and render the models in your scene according to their distance from the camera.

Project Downloads

<< Previous Tutorial     Next Tutorial >>


 
All the content on Real 3D Tutorials, with the exception of the SyntaxHighlighter which is licensed under the MIT License, is provided to the public domain and everyone is free to use, modify, republish, sell or give away this work without prior consent from anybody. Content is provided without warranty of any kind. Under no circumstances shall the author(s) or contributor(s) be liable for damages resulting directly or indirectly from the use or non-use of the content.
Should you find the content useful and would like to make a contribution, you can show your support by making a donation.