Visible surface determination is usually done with the Z-buffer technique (also known as depth buffering). In this case the drawing order of the objects is irrelevant for the render result. However, the Z-buffer technique only works with opaque faces but not with transparent faces. Transparent, overlapping faces have to be drawn in the correct order sorted from back to front. This is because the drawing order has a significant impact to the final compound color.(1)
Thus it is often wise to render the opaque geometries at first with Z-buffering enabled and the transparent geometries afterwards accessing the Z-buffer in read-only mode. Also for overlays, HUDs and various effects the render order often plays a vital role.
This tutorial describes the exact sequence in which the rendering occurs and shows ways to control the render order.
- Note
- (1) Also other techniques exist which allow to draw transparent faces order independent - e.g. Weighted Blended Order-Independent Transparency.
Render Hierarchy
The drawing order of the renderer can be controlled in several hierarchy levels:
- Framebuffer/Backbuffer
- View
- Camera
- Layer
- Pass
- SortOrder/Distance/DepthOrder
Framebuffer/Backbuffer
At first all Framebuffers
are rendered in the order in which they are defined in the scene graph. At last the back buffer is rendered.
View
For each frame buffer / back buffer one or more Graph::View
objects can exist.
A view specifies a display window or a region in the window (integer coordinates, pixels). The view has always the same size as the corresponding frame buffer / back buffer. A view mask can be used to restrict the drawing area to a smaller, rectangular region ("scissor test").
The render order can be defined with the attribute depthOrder
. If the depthOrder
value is the same for two views, the order in the scene graph defines the actual render order. A higher depthOrder
value results in the view being rendered later, i.e. on top of all other views in the same frame buffer with lower depthOrder
values.
Camera
For each view one or more Graph::Camera
objects can exist
A Graph::Camera
object specifies a visible area within the virtual world (floating point coordinates).
The render order can be defined with the attribute depthOrder
. If the depthOrder
value is the same for two cameras, the order in the scene graph defines the actual render order. A higher depthOrder
value results in the camera being rendered later, i.e. on top of all other cameras within the same view with lower depthOrder
values.
Layer
Each camera renders its objects (assigned by child nodes or with the Graph::CameraState
node).
The rendering can be split up into several layers. By default, all geometries are rendered to layer 0. A Graph::LayerState
node with the attribute index
can be used to switch to a different layer.
- Note
- Attention! In order to save resources, layers should always be used consecutively, starting with 0 (e.g. 0, 1, 2, 3 and not 0, 12, 20, 30).
The render order is defined by the layer index, higher values are rendered later.
Pass
The rendering of each layer is done in two passes, depending on the Graph::Material
and the objectSortMode
attribute.
In the first pass (pass 0) all objects are rendered, where the objectSortMode
of the Graph::Material
is equal to OBJECT_SORT_MODE_BY_MATERIAL
.
In the second pass (pass 1) all objects are rendered, where the objectSortMode
of the Graph::Material
is equal to OBJECT_SORT_MODE_BY_DEPTH
.
If the attribute objectSortMode
is not explicitly specified, the depthBufferMode
defines the mapping:
- Materials that write the depth buffer (
DEPTH_BUFFER_MODE_WRITE_ONLY
orDEPTH_BUFFER_MODE_READ_AND_WRITE
) useOBJECT_SORT_MODE_BY_MATERIAL
(Pass 0). - All other materials use
OBJECT_SORT_MODE_BY_DEPTH
(Pass 1).
SortOrder, Distance, DepthOrder
In pass 0 the attribute sortOrder
of the material
defines the render order.
In pass 1 the render order is defined by:
sorOrder
attribute of thematerial
.- Distance (if the
sortOrder
is equal, sort from back to front). depthOrder
attribute of thegeometry
(if thesortOrder
and distance is equal, sort by thedepthOrder
attribute).
The method to determine the distance can be specified with the depthSortMode
attribute of the Graph::Camera
(e.g. no depth sorting, z-value, distance – see IEnums::DepthSortMode
).
- Note
- The
depthOrder
attribute of the parent node is passed to the child node. The resultingdepthOrder
of the child node is the sum of thedepthOrder
of the parent node and the specifieddepthOrder
of the child node. If a child node should be rendered behind a parent node, a negativedepthOrder
value can be used for the child node.
Automatic Grouping
Objects, for which the render order is undefined within one pass, are grouped together according to the following criteria:
- Minimize shader program switches.
- Minimize texture switches.
- Group objects with same lighting.
The grouping is done automatically and is not deterministic.
Example
As a simple example we show how to use multiple views and cameras and draw several objects with different materials.
We use a background_camera
to clear the display and the depth buffer and a main_camera
to draw the background.
- Note
- The
background_camera
must be activated using aCameraState
node because it does not contain any child node. Otherwise the camera would be skipped by the renderer.
<View id="main_view" leftMaskCoord="0" topMaskCoord="0" rightMaskCoord="0" bottomMaskCoord="0" /> <OrthographicCamera id="background_camera" viewId="main_view" unitSizeX="1" unitSizeY="1" colorClearValue="000000aah" clearColorBuffer="true" clearDepthBuffer="true" depthOrder="0" /> <CameraState cameraId="background_camera" /> <OrthographicCamera id="main_camera" viewId="main_view" unitSizeX="1" unitSizeY="1" clearColorBuffer="no" clearDepthBuffer="no" depthOrder="10" /> <CameraTransform cameraId="main_camera" posX="0" posY="0" posZ="512" /> <CameraState cameraId="main_camera" />
The main_camera
is used to draw a texture.
<Instance graphResourceId="package_main:graph_camera"/> <PlaneGeometry materialSlot="4" textureSlot="1" scaleFactorX="10000" scaleFactorY="1080"/>
Additionally we define a view_left
and a perspective camera camera_left
. The Graph::View
is restricted to the left half of the screen with the attribute rightMaskCoord
. The center of the Graph::Camera
is also moved to the center of the left half.
<?xml version="1.0" ?> <Graph> <View id="view_left" leftMaskCoord="0" topMaskCoord="0" rightMaskCoord="-640" bottomMaskCoord="0" /> <Camera id="camera_left" centerX="-0.5" viewId="view_left" fieldOfViewX="2" clearColorBuffer="no" clearDepthBuffer="no" depthOrder="2" /> <CameraTransform cameraId="camera_left" posX="0" posZ="600" /> <CameraState cameraId="camera_left" /> </Graph>
For the right half of the screen we define a view_right
and an orthographic camera camera_right
. We again restrict the Graph::View
and move the center of the Graph::Camera
.
<?xml version="1.0" ?> <Graph> <View id="view_right" leftMaskCoord="640" topMaskCoord="0" rightMaskCoord="0" bottomMaskCoord="0" /> <OrthographicCamera id="camera_right" centerX="0.5" viewId="view_right" unitSizeX="1" unitSizeY="1" clearColorBuffer="no" clearDepthBuffer="no" depthOrder="2" /> <Transform angleX="-90d"> <CameraTransform cameraId="camera_right" posZ="500" /> </Transform> <CameraState cameraId="camera_right" /> </Graph>
The two cameras render the same scene in different views.
<Instance graphResourceId="package_main:graph_camera_left"/> <Reference targetId="myScene"/> <Instance graphResourceId="package_main:graph_camera_right"/> <Reference targetId="myScene"/>
We get an image that is rendered with four cameras:
background_camera
clears the window.main_camera
uses a blue image to draw the background.camera_left
renders the scene with a perspective camera.camera_right
renders the scene with an orthographic camera in a bird's eye view.
To get a correct render result for the opaque and transparent faces we use depthBufferMode="READ_AND_WRITE"
for the opaque material and depthBufferMode="READ_ONLY"
for the transparent material.