<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.flightgear.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mcginnly</id>
	<title>FlightGear wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.flightgear.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mcginnly"/>
	<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/Special:Contributions/Mcginnly"/>
	<updated>2026-05-09T10:32:17Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.6</generator>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Project_Rembrandt&amp;diff=50057</id>
		<title>Project Rembrandt</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Project_Rembrandt&amp;diff=50057"/>
		<updated>2012-05-17T19:04:53Z</updated>

		<summary type="html">&lt;p&gt;Mcginnly: /* Caveats */ grmr&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
== Why this name ? ==&lt;br /&gt;
[http://en.wikipedia.org/wiki/Rembrandt Rembrandt] was a dutch painter living in the 17th century, famous as one of the master of [http://en.wikipedia.org/wiki/Chiaroscuro chiaroscuro].&lt;br /&gt;
&lt;br /&gt;
This project is about changing the way [[FlightGear]] renders lights, [[shadows]] and shades, and aims at making Rembrandt painting style possible in FG.&lt;br /&gt;
&lt;br /&gt;
== What is it ? ==&lt;br /&gt;
The idea driving the project is to implement [http://en.wikipedia.org/wiki/Deferred_shading deferred rendering] inside FlightGear.&lt;br /&gt;
From the beginning FlightGear had a forward renderer that tries to render all properties of an object in one pass (shading, lighting, fog, ...), making it difficult to render more sophisticated shading &lt;br /&gt;
(see the [[FlightGear Newsletter December 2011#Shaders|'Uber-shader']]) because one has to take into account all aspects of the [http://www.wired.com/magazine/2010/07/st_equation_3danimation/ rendering equation].&lt;br /&gt;
&lt;br /&gt;
[[Image:project_rembrandt_1.png|thumb|300px|Main view with the content of buffers displayed at corners]]&lt;br /&gt;
On the contrary, deferred rendering is about separating operations in simplified stages and collecting the intermediary results in hidden buffers that can be used by the next stage.&lt;br /&gt;
&lt;br /&gt;
;First stage is the Geometry Stage :&lt;br /&gt;
: we render all the scene into 4 textures, using multi render targets, to do it in one pass: one for the depth buffer, one for the normals (lower left of the image), one for the diffuse colors (lower right) and one for the specular colors (upper right).&lt;br /&gt;
&lt;br /&gt;
;Next stage is the Shadow Stage :&lt;br /&gt;
: we render the scene again into a depth texture from the point of view of the lights. There will be one texture for every light casting shadows.&lt;br /&gt;
&lt;br /&gt;
;Then comes the Lighting Stage, with several substages :&lt;br /&gt;
:*&amp;lt;u&amp;gt;Sky pass&amp;lt;/u&amp;gt;: the sky is first drawn using classical method.&lt;br /&gt;
:*&amp;lt;u&amp;gt;Ambient pass&amp;lt;/u&amp;gt;: the diffuse buffer is modulated with the ambient color of the scene and is drawn as a screen-aligned textured quad&lt;br /&gt;
:*&amp;lt;u&amp;gt;Sunlight pass&amp;lt;/u&amp;gt;: a second screen aligned quad is drawn and a shader computes the view position of every pixel to compute its diffuse and specular color, using the normal stored in the first stage. The resulting color is blended with the previous pass. Shadows are computed here by comparing the position of the pixel with the position of the light occluder stored in the shadow map.&lt;br /&gt;
:*&amp;lt;u&amp;gt;Additional light pass&amp;lt;/u&amp;gt;: the scene graph will be traversed another time to display light volumes (cone or frusta for spot lights, sphere for omni-directional lights) and their shader will add the light contributed by the source only on pixels receiving light.&lt;br /&gt;
:*&amp;lt;u&amp;gt;Fog pass&amp;lt;/u&amp;gt;: a new screen aligned quad is draw and the position of the pixel is computed to evaluate the amount of fog the pixel has. The fog color is blended with the result of the previous stage.&lt;br /&gt;
:*&amp;lt;u&amp;gt;Transparent objects pass&amp;lt;/u&amp;gt;: transparent objects (and clouds) are finally rendered using classical method.&lt;br /&gt;
&lt;br /&gt;
:All lighting computations are accumulated in a single buffer that will be used for the last stage, in addition of the one computed by the Geometry stage.&lt;br /&gt;
&lt;br /&gt;
;In the end, the Display Stage, with optional Post-Processing effect :&lt;br /&gt;
:The results of the previous buffers are pushed to the main framebuffer to be displayed, optionally modified to show Glow, Motion blur, HDR, redout or blackout, screen-space ambient occlusion, anti-aliasing, etc...&lt;br /&gt;
&lt;br /&gt;
In FG, we end the rendering pipeline by displaying the [[Menubar|GUI]] and the [[HUD]].&lt;br /&gt;
&lt;br /&gt;
All these stages are more precisely described if this [http://bat710.univ-lyon1.fr/~jciehl/Public/educ/GAMA/2007/Deferred_Shading_Tutorial_SBGAMES2005.pdf tutorial] that is the basis of the current code, with some addition and modifications.&lt;br /&gt;
&lt;br /&gt;
== Caveats ==&lt;br /&gt;
Deferred rendering is not able to display transparency. For the moment, clouds are renderer separately and should be lit and shaded by their own. Transparent surfaces are alpha-tested and not blended. They would have to be drawn in their own bin over the composited image.&lt;br /&gt;
&lt;br /&gt;
It also don't fit with depth partitioning because the depth buffer should be kept to retain the view space position, so for the moment, z-fighting is quite visible. Depth partitioning with non overlapping depth range might be the solution and should be experimented at one point.&lt;br /&gt;
&lt;br /&gt;
The glow pass can make certain MFD (that use emissive color) unreadable because blurred. Should be treated as transparent.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Repositories ===&lt;br /&gt;
The code is in the main branch of the [[FlightGear and Git|official repository]]. Any other location is not maintained anymore.&lt;br /&gt;
&lt;br /&gt;
=== Rendering of transparent surfaces ===&lt;br /&gt;
[[Image:project_rembrandt_5.png|thumb|300px|Transparent surfaces drawn after opaque objects]]&lt;br /&gt;
Transparent surfaces are detected by OSG loader plugins and their state set receive the TRANSPARENT_BIN rendering hint. In the culling pass, the cull visitor orders transparent surfaces in transparent bin. In a cull callback attached to the Geometry camera, after the scenegraph traversal, the transparent bins are removed from the render stage and saved in a temporary collection. In a cull callback attached to the Lighting camera, after the scenegraph traversal, the transparent bins saved at the previous stage, are added to the render stage of the Lighting camera with a high order num. That way, the transparent surface are drawn on top of the scene lighted from the Gbuffer.&lt;br /&gt;
&lt;br /&gt;
=== Memory consumption ===&lt;br /&gt;
For each camera defined in the camera group, there is a separate shadow map, so the video memory usage is :&lt;br /&gt;
* G-buffer and Lighting buffer: 20 bytes per pixel. For an HD screen (1920x1080) memory requirement is 40 Mb&lt;br /&gt;
* Shadow map: 3 x shadow_map_size x shadow_map_size bytes (if size is 8192, whole map size is 192 Mb&lt;br /&gt;
Not counting textures, display list or vertex buffers for models and terrain&lt;br /&gt;
&lt;br /&gt;
3 HD screens require 120 Mb of memory for the buffers (shadow excluded), you're asking 3x8192x8192x3 = 576 Mb (megabytes) of memory for the shadows alone.&lt;br /&gt;
&lt;br /&gt;
If you are seeing error messages during startup or FlightGear doesn't start up properly, it's probably because you don't have enough free video memory. Reduce the size of the shadow map in preferences.xml by locating &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;map-size type=&amp;quot;int&amp;quot;&amp;gt;8192&amp;lt;/map-size&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And put 4096 or 2048 instead.&lt;br /&gt;
You can also use a startup parameter: --prop:/sim/rendering/shadows/map-size=2048&lt;br /&gt;
&lt;br /&gt;
=== Configurable pipeline ===&lt;br /&gt;
&lt;br /&gt;
The Rembrandt renderer uses an XML file to setup its pipeline for each viewport described in the camera group. This file describes the way the intermediary buffers are setup and how the different rendering stages are sequenced. The general outline of a pipeline file is as follow :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
	&amp;lt;!-- BUFFERS --&amp;gt;&lt;br /&gt;
	&amp;lt;buffer&amp;gt;&lt;br /&gt;
		&amp;lt;!-- First buffer definition --&amp;gt;&lt;br /&gt;
	&amp;lt;/buffer&amp;gt;&lt;br /&gt;
	&amp;lt;buffer&amp;gt;&lt;br /&gt;
		&amp;lt;!-- nth buffer definition --&amp;gt;&lt;br /&gt;
	&amp;lt;/buffer&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;!-- STAGES --&amp;gt;&lt;br /&gt;
	&amp;lt;stage&amp;gt;&lt;br /&gt;
		&amp;lt;!-- First stage definition --&amp;gt;&lt;br /&gt;
	&amp;lt;/stage&amp;gt;&lt;br /&gt;
	&amp;lt;stage&amp;gt;&lt;br /&gt;
		&amp;lt;!-- nth stage definition --&amp;gt;&lt;br /&gt;
	&amp;lt;/stage&amp;gt;&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Buffers ====&lt;br /&gt;
A buffer is a texture used as a storage area in the GPU. It's size is usually a multiple of the screen size, but fixed size is supported (typical for shadow map). The description of a buffer is described below :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;buffer&amp;gt;&lt;br /&gt;
		&amp;lt;name&amp;gt;buffer-name&amp;lt;/name&amp;gt;&lt;br /&gt;
		&amp;lt;internal-format&amp;gt;rgba8&amp;lt;/internal-format&amp;gt; &amp;lt;!-- rgb8, rgba8, rgb16, rgba16, rg16, depth-component24, depth-component32 or OpenGL hex value --&amp;gt;&lt;br /&gt;
		&amp;lt;source-format&amp;gt;rgba&amp;lt;/source-format&amp;gt; &amp;lt;!-- rg, rgb, rgba, depth-component or OpenGL hex value --&amp;gt;&lt;br /&gt;
		&amp;lt;source-type&amp;gt;unsigned-byte&amp;lt;/source-type&amp;gt; &amp;lt;!-- unsigned-byte, unsigned-short, unsigned-int, float or OpenGL hex value --&amp;gt;&lt;br /&gt;
		&amp;lt;width&amp;gt;screen&amp;lt;/width&amp;gt; &amp;lt;!-- screen, value or &amp;lt;property&amp;gt;/a/width/property&amp;lt;/property&amp;gt; --&amp;gt;&lt;br /&gt;
		&amp;lt;height&amp;gt;screen&amp;lt;/height&amp;gt; &amp;lt;!-- screen, value or &amp;lt;property&amp;gt;/a/height/property&amp;lt;/property&amp;gt; --&amp;gt;&lt;br /&gt;
		&amp;lt;scale-factor&amp;gt;1.0&amp;lt;/scale-factor&amp;gt;&lt;br /&gt;
		&amp;lt;wrap-mode&amp;gt;clamp-to-border&amp;lt;/wrap-mode&amp;gt; &amp;lt;!-- clamp, clamp-to-border, clamp-to-edge, mirror, repeat or OpenGL hex value --&amp;gt;&lt;br /&gt;
		&amp;lt;!-- optional, for shadow map --&amp;gt;&lt;br /&gt;
		&amp;lt;shadow-comparison&amp;gt;true&amp;lt;/shadow-comparison&amp;gt;&lt;br /&gt;
		&amp;lt;!-- optional condition --&amp;gt;&lt;br /&gt;
		&amp;lt;condition&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Valid boolean expression --&amp;gt;&lt;br /&gt;
		&amp;lt;/condition&amp;gt;&lt;br /&gt;
	&amp;lt;/buffer&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Stages ====&lt;br /&gt;
A stage is an unit of rendering to a group of buffer. Most stages are predefined and their type is not free. When a type is not specified, the name is used. Stage types are :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!align=&amp;quot;left&amp;quot;| Stage type&lt;br /&gt;
!align=&amp;quot;left&amp;quot;| Purpose&lt;br /&gt;
|-&lt;br /&gt;
|geometry&lt;br /&gt;
|The geometry stage initialize most of the buffers and works on the real objects and geometry. Transparent objects are set aside and will be used untouched in the lighting stage. Other opaque geometry is rendered with the standard effects that do the hard work to put sensible data in the buffers.&lt;br /&gt;
|-&lt;br /&gt;
|shadow&lt;br /&gt;
|In this stage, the geometry is rendered in the normal map from the perspective of the sun.&lt;br /&gt;
|-&lt;br /&gt;
|lighting&lt;br /&gt;
|This stage uses the buffers filled by the previous stages to light every pixel of the scene. The result is rendered in another buffer to allow post effects.&lt;br /&gt;
|-&lt;br /&gt;
|fullscreen&lt;br /&gt;
|Stages of this type are used to alter the whole scene or transform data from a particular buffer.&lt;br /&gt;
|-&lt;br /&gt;
|display&lt;br /&gt;
|Final rendering of the scene to the screen or the texture defined in the camera group.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A stage description is outlined below :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;stage&amp;gt;&lt;br /&gt;
		&amp;lt;name&amp;gt;stage-name&amp;lt;/name&amp;gt;&lt;br /&gt;
		&amp;lt;type&amp;gt;stage-type&amp;lt;/type&amp;gt; &amp;lt;!-- optional if name is one of the predefined type except fullscreen --&amp;gt;&lt;br /&gt;
		&amp;lt;order-num&amp;gt;-1&amp;lt;/order-num&amp;gt;&lt;br /&gt;
		&amp;lt;effect&amp;gt;Effects/fullscreen-effect&amp;lt;/effect&amp;gt; &amp;lt;!-- only if type == fullscreen --&amp;gt;&lt;br /&gt;
		&amp;lt;needs-du-dv&amp;gt;true&amp;lt;/needs-du-dv&amp;gt; &amp;lt;!-- only if type == fullscreen --&amp;gt;&lt;br /&gt;
		&amp;lt;scale-factor&amp;gt;0.25&amp;lt;/scale-factor&amp;gt; &amp;lt;!-- only if type == fullscreen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
		&amp;lt;!-- optional condition --&amp;gt;&lt;br /&gt;
		&amp;lt;condition&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Valid boolean expression --&amp;gt;&lt;br /&gt;
		&amp;lt;/condition&amp;gt;&lt;br /&gt;
&lt;br /&gt;
		&amp;lt;attachment&amp;gt;&lt;br /&gt;
			&amp;lt;!-- First attachment definition --&amp;gt;&lt;br /&gt;
		&amp;lt;/attachment&amp;gt;&lt;br /&gt;
		&amp;lt;attachment&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Nth attachment definition --&amp;gt;&lt;br /&gt;
		&amp;lt;/attachment&amp;gt;&lt;br /&gt;
&lt;br /&gt;
		&amp;lt;!-- Passes only for the lighting stage --&amp;gt;&lt;br /&gt;
		&amp;lt;pass&amp;gt;&lt;br /&gt;
			&amp;lt;!-- First pass definition --&amp;gt;&lt;br /&gt;
		&amp;lt;/pass&amp;gt;&lt;br /&gt;
		&amp;lt;pass&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Nth pass definition --&amp;gt;&lt;br /&gt;
		&amp;lt;/pass&amp;gt;&lt;br /&gt;
	&amp;lt;/stage&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Stages render in buffers (except for the display stage). Attachments describe which buffers are affected by each stage.&lt;br /&gt;
&lt;br /&gt;
===== Attachments =====&lt;br /&gt;
Attachment describe bindings between buffer and attachment point :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;attachment&amp;gt;&lt;br /&gt;
		&amp;lt;component&amp;gt;color0&amp;lt;/component&amp;gt; &amp;lt;!-- depth, stencil, packed-depth-stencil, color0, color1, color2 or color3 --&amp;gt;&lt;br /&gt;
		&amp;lt;buffer&amp;gt;buffer-name&amp;lt;/buffer&amp;gt;&lt;br /&gt;
		&amp;lt;!-- optional condition --&amp;gt;&lt;br /&gt;
		&amp;lt;condition&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Valid boolean expression --&amp;gt;&lt;br /&gt;
		&amp;lt;/condition&amp;gt;&lt;br /&gt;
	&amp;lt;/attachment&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Passes =====&lt;br /&gt;
Passes are only available in the &amp;lt;tt&amp;gt;lighting&amp;lt;/tt&amp;gt; stage. Three kind of stage are allowed :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!align=&amp;quot;left&amp;quot;| Pass type&lt;br /&gt;
!align=&amp;quot;left&amp;quot;| Purpose&lt;br /&gt;
|-&lt;br /&gt;
|sky-clouds&lt;br /&gt;
|Renders the skydome, sun, moon, planet, stars and clouds&lt;br /&gt;
|-&lt;br /&gt;
|lights&lt;br /&gt;
|Renders additional spot and point lights&lt;br /&gt;
|-&lt;br /&gt;
|fullscreen&lt;br /&gt;
|Fullscreen pass analog to a fullscreen stage except that it renders in the buffers attached to the lighting stage&lt;br /&gt;
|}&lt;br /&gt;
A pass is defined like below :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;pass&amp;gt;&lt;br /&gt;
		&amp;lt;name&amp;gt;pass-name&amp;lt;/name&amp;gt;&lt;br /&gt;
		&amp;lt;type&amp;gt;pass-type&amp;lt;/type&amp;gt; &amp;lt;!-- optional if name is one of the predefined type except fullscreen --&amp;gt;&lt;br /&gt;
		&amp;lt;order-num&amp;gt;-1&amp;lt;/order-num&amp;gt;&lt;br /&gt;
		&amp;lt;effect&amp;gt;Effects/fullscreen-effect&amp;lt;/effect&amp;gt; &amp;lt;!-- only if type == fullscreen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
		&amp;lt;!-- optional condition --&amp;gt;&lt;br /&gt;
		&amp;lt;condition&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Valid boolean expression --&amp;gt;&lt;br /&gt;
		&amp;lt;/condition&amp;gt;&lt;br /&gt;
	&amp;lt;/pass&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A typical lighting stage is a succession of 5 passes :&lt;br /&gt;
# &amp;lt;tt&amp;gt;sky-clouds&amp;lt;/tt&amp;gt; pass&lt;br /&gt;
# &amp;lt;tt&amp;gt;fullscreen&amp;lt;/tt&amp;gt; pass for ambient light&lt;br /&gt;
# &amp;lt;tt&amp;gt;fullscreen&amp;lt;/tt&amp;gt; pass for sun light (and shadows)&lt;br /&gt;
# &amp;lt;tt&amp;gt;lights&amp;lt;/tt&amp;gt; pass&lt;br /&gt;
# &amp;lt;tt&amp;gt;fullscreen&amp;lt;/tt&amp;gt; pass for fog&lt;br /&gt;
&lt;br /&gt;
Each effect attached to the fullscreen passes define the way blending is done between the pass and the previous accumulation of render.&lt;br /&gt;
&lt;br /&gt;
== Running Flightgear with Rembrandt ==&lt;br /&gt;
&lt;br /&gt;
The Rembrandt renderer is now integrated in the main repository but needs to be enabled to run. Use the &amp;lt;tt&amp;gt;--enable-rembrandt&amp;lt;/tt&amp;gt; option to start Flightgear with this new renderer.&lt;br /&gt;
&lt;br /&gt;
Rembrandt is quite demanding in GPU resources and may fail to run with the default options. The more frequent symptom is an OSG message in the console :&lt;br /&gt;
&lt;br /&gt;
 RenderStage::runCameraSetUp(), FBO setup failed, FBO status= 0x8cd6&lt;br /&gt;
 Warning: RenderStage::runCameraSetUp(State&amp;amp;) Pbuffer does not support multiple color outputs.&lt;br /&gt;
&lt;br /&gt;
Some card also exhibit messages like this :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgram &amp;quot;&amp;quot; FAILED&lt;br /&gt;
 Program &amp;quot;&amp;quot; infolog:&lt;br /&gt;
 Fragment info&lt;br /&gt;
 -------------&lt;br /&gt;
 0(37) : error C6013: Only arrays of texcoords may be indexed in this profile, and only with a loop index variable&lt;br /&gt;
 0(36) : error C6013: Only arrays of texcoords may be indexed in this profile, and only with a loop index variable&lt;br /&gt;
 0(35) : error C6013: Only arrays of texcoords may be indexed in this profile, and only with a loop index variable&lt;br /&gt;
 0(34) : error C6013: Only arrays of texcoords may be indexed in this profile, and only with a loop index variable&lt;br /&gt;
&lt;br /&gt;
There is a number of additional options that can help to avoid these problems :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/rembrandt/use-color-for-depth=true&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Some old NVidia cards, such as 7600GT, don't give enough resolution for depth and that result in &amp;quot;fog curtains&amp;quot; at few meters from the viewer. One trick is to encode depth in another texture and get the proper value afterward. This option enables that.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/enabled=false&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Disable shadows altogether. This setting is changeable at runtime in the rendering option dialog.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/num-cascades=1&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Avoid the &amp;quot;error C6013&amp;quot; message on old cards at the cost of resolution in the cockpit. Set &amp;lt;tt&amp;gt;/sim/rendering/shadows/cascade-far-m[0]&amp;lt;/tt&amp;gt; to change the shadow map range. The more the range, the less the resolution (default value is 5 meters)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/map-size=&amp;lt;power-of-two&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Set the shadow map size. Useful values are 1024, 2048, 4096 or 8192. Few cards have the resources to support 16384.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/num-cascades&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Set the shadow map cascade number. Less cascades means less time spent in shadow map generation, but also means lower shadow quality. Integer between 1 and 4.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/cascade-far-m[i]&amp;lt;/tt&amp;gt;&lt;br /&gt;
(1 &amp;lt;= i &amp;lt;= &amp;lt;tt&amp;gt;/sim/rendering/shadows/num-cascades&amp;lt;/tt&amp;gt; &amp;lt;= 4)&lt;br /&gt;
|Set the shadow map cascade range for each cascade. Default values are 5m, 50m, 500m and 5000m for 4 cascades.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/rembrandt/no-16bit-buffer=false&amp;lt;/tt&amp;gt;&lt;br /&gt;
|By default, Rembrandt uses 8 bit buffers for normals (so the property is set to true by default). This may create banding artifacts on specular highlights. If it's unacceptable and the GPU supports it, set to false to have better precision for normals and effects relying on normal direction.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Guidelines for shader writers ==&lt;br /&gt;
=== Predefined uniforms ===&lt;br /&gt;
These glsl uniforms don't need to be declared in the effect file.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ViewMatrix&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In fullscreen pass only, view matrix used to transform the screen position to view direction&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ViewMatrixInverse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In fullscreen pass only, view matrix inverse used to transform the screen position to view direction&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ProjectionMatrixInverse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In fullscreen pass only, projection matrix inverse used to transform the screen position to view direction&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_SunAmbientColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_SunDiffuseColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_SunSpecularColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_SunDirection&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec3&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_FogColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_FogDensity&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ShadowNumber&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ShadowDistances&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_DepthInColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;bool&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Tells if the depth is stored in a depth texture or a color texture&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_Planes&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec3&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Used to convert the value of the depth buffer to a depth that can be used to compute the eye space position of the fragment&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_BufferSize&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec2&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Dimensions of the buffer, used to convert gl_FragCoord into the range [0..1][0..1]&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;osg_ViewMatrix&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Defined by OSG, used only when working on actual geometry&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;osg_ViewMatrixInverse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Defined by OSG, used only when working on actual geometry&lt;br /&gt;
|}&lt;br /&gt;
They still have to be declared in the fragment or the vertex shader to be used.&lt;br /&gt;
&lt;br /&gt;
=== Utility functions ===&lt;br /&gt;
&lt;br /&gt;
To ease the maintenance of shaders, several utility functions are available for the fragment shader. These functions are put together in two files : &amp;lt;tt&amp;gt;gbuffer-functions.frag&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;gbuffer-encode.frag&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== gbuffer-encode.frag ====&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;void encode_gbuffer(vec3 normal, vec3 color, int mId, float specular, float shininess, float emission, float depth)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Used to encode all the values of the G-Buffer in material shaders&lt;br /&gt;
&lt;br /&gt;
==== gbuffer-functions.frag ====&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec2 normal_encode(vec3 n)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Used to compress normals into the G-Buffer in material shaders. Normally called from &amp;lt;tt&amp;gt;encode_gbuffer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 normal_decode(vec2 enc)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Reconstruct normals from the G-Buffer. Used in fullscreen shaders and light shaders&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 float_to_color(in float f)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Encode float values in the range [0..1] in the 24 bits of a color. This function is used by &amp;lt;tt&amp;gt;encode_gbuffer()&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;/sim/rendering/use-color-for_depth&amp;lt;/tt&amp;gt; is true, for old cards that don't provide depth information with enough resolution inside fullscreen or light shaders.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;float color_to_float(vec3 color)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Decode float values in the range [0..1] from the 24 bits of a color. This function is used by &amp;lt;tt&amp;gt;position()&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;/sim/rendering/use-color-for_depth&amp;lt;/tt&amp;gt; is true, for old cards that don't provide depth information with enough resolution inside fullscreen or light shaders.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 position( vec3 viewDir, float depth )&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Reconstruct eye space position from the view direction and the depth read from the depth buffer&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 position( vec3 viewDir, vec3 depthColor )&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Reconstruct eye space position from the view direction and the depth encoded in a color read from the depth buffer&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 position( vec3 viewDir, vec2 coords, sampler2D depth_tex )&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Reconstruct eye space position from the view direction and the depth buffer (real depth or color, according to the value of &amp;lt;tt&amp;gt;/sim/rendering/use-color-for_depth&amp;lt;/tt&amp;gt;) at a given fragment on screen, given by &amp;lt;tt&amp;gt;coords&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Usage ====&lt;br /&gt;
&lt;br /&gt;
For material shaders, it is necessary to provide both &amp;lt;tt&amp;gt;gbuffer-functions.frag&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;gbuffer-encode.frag&amp;lt;/tt&amp;gt; in the effect file, like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;program&amp;gt;&lt;br /&gt;
		&amp;lt;vertex-shader&amp;gt;Shaders/ubershader.vert&amp;lt;/vertex-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/ubershader-gbuffer.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/gbuffer-functions.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/gbuffer-encode.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
	&amp;lt;/program&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For fullscreen passes shaders, only &amp;lt;tt&amp;gt;gbuffer-functions.frag&amp;lt;/tt&amp;gt; should be provided, like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;program&amp;gt;&lt;br /&gt;
		&amp;lt;vertex-shader&amp;gt;Shaders/sunlight.vert&amp;lt;/vertex-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/sunlight.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/gbuffer-functions.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
	&amp;lt;/program&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the main function of the shader, the functions referenced need to be declared first. With no #include files, the whole function prototype needs to be typed :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void encode_gbuffer(vec3 normal, vec3 color, int mId, float specular, float shininess, float emission, float depth);&lt;br /&gt;
&lt;br /&gt;
main() {&lt;br /&gt;
    vec3 normal;&lt;br /&gt;
    vec3 color;&lt;br /&gt;
    int mId;&lt;br /&gt;
    float specular;&lt;br /&gt;
    float shininess;&lt;br /&gt;
    float emission;&lt;br /&gt;
    float depth;&lt;br /&gt;
&lt;br /&gt;
    // Do shader computations&lt;br /&gt;
&lt;br /&gt;
    encode_gbuffer(normal, color, mId, specular, shininess, emission, depth);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Geometry Stage ===&lt;br /&gt;
The Geometry Stage is there to fill the G-buffer. '''Shading doesn't occur at this stage, so light or fog computation should not be part of the shader'''. The required operation in the Fragment Shader is to fill every individual buffer with sensible value :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&lt;br /&gt;
|depth (gl_FragDepth)||GL_DEPTH_COMPONENT32||colspan=&amp;quot;4&amp;quot;|Fragment depth&lt;br /&gt;
|-&lt;br /&gt;
|gl_FragData[0]||GL_RG16||colspan=&amp;quot;2&amp;quot;|normal.x * 0.5 + 0.5||colspan=&amp;quot;2&amp;quot;|normal.y * 0.5 + 0.5&lt;br /&gt;
|-&lt;br /&gt;
|gl_FragData[1]||GL_RGBA8||diffuse.r||diffuse.g||diffuse.b||material id * 1/255.0&lt;br /&gt;
|-&lt;br /&gt;
|gl_FragData[2]||GL_RGBA8||specular.l||specular.s||emission.l||pixel valid if != 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is the default layout expected by the sunlight shader. material Id can be used to detect a different layout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
#Depth buffer, modified with gl_FragDepth, will record the distance between the fragment and the camera. Default behavior is to avoid to touch it, living the GPU rasterizer doing sensible things by interpolating vertex gl_Position from the Vertex or the Geometry Shader. If altering the computed depth is required, like in the Urban shader, the value of gl_FragDepth should be set.&lt;br /&gt;
#Normal buffer, modified with gl_FragData[0].xyz, will record the normal of the fragment in eye coordinates. gl_FragData[0].w is reserved for future use. The interpolated normal is usually simply stored but bump mapping or relief mapping affecting the normal can be computed here.&lt;br /&gt;
#Diffuse color buffer, modified with gl_FragData[1].rgb, will hold the unshaded color of the fragment, usually modulating the material diffuse+ambient color with the texture map. Diffuse color from environment mapping should also go here.&lt;br /&gt;
#Specular color, modified with gl_FragData[2].rgb, and specular shininess in gl_FragData[2].a, will retain the specular color of the fragment.&lt;br /&gt;
#Emission color, modified with gl_FragData[3].rgb&lt;br /&gt;
In anyway, don't use gl_FragColor as it is incompatible with MRT (Multi Render Target) and would affect the four last buffers with the same value. In that case, the model will glow (emission buffer initialized) and parts will disappear at certain view angles because normals are not initialized properly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:red;font-size:1.5em;font-weight:bold&amp;quot;&amp;gt;This layout is going to change in the official repository when the merge will be done. The goal of this change is to fill more useful data into less texture memory and get rid of a stupid IP issue on float textures&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Additional light pass ===&lt;br /&gt;
There would be a single shader for each light type used. The plan is to create lights like animations in the model XML file. The light shader will retrieve scene geometry by combining screen space position converted in view space ray by the inverse of the projection matrix (an helper function should be provided), and the fragment depth at that screen position read from the depth buffer. With the help of the fragment normal, the diffuse and specular color and the properties of the light the shader implements, it will be possible to add to the lighting buffer the contribution of the light rendered.&lt;br /&gt;
&lt;br /&gt;
=== Fog Pass ===&lt;br /&gt;
Using the fragment depth, it will be possible to compute any fog distribution. For the moment, the simple fog equation is implemented.&lt;br /&gt;
&lt;br /&gt;
=== Bloom Pass ===&lt;br /&gt;
This is a two-pass effect that blurs the lighting buffer in a small texture. This texture is then added to the lighting buffer at the display stage.&lt;br /&gt;
&lt;br /&gt;
=== Required Effects ===&lt;br /&gt;
Several pass are implemented using the effect system. For this purpose, some effects are referenced in the core code using reserved names. these effects are:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Kind&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/ssao&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on a full screen quad&lt;br /&gt;
|Compute ambient occlusion from the normal buffer and the depth buffer&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/ambient&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on a full screen quad&lt;br /&gt;
|Copies the diffuse color buffer multiplied by the ambient light to the lighting buffer. Ambient Occlusion can also affect ambient light.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/light-spot&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on real geometry of the light volume&lt;br /&gt;
|Computes the light contribution of a spot light defined in a &amp;lt;tt&amp;gt;light&amp;lt;/tt&amp;gt; animation having a &amp;lt;tt&amp;gt;light-type&amp;lt;/tt&amp;gt; of '''&amp;lt;tt&amp;gt;spot&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/fog&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on a full screen quad&lt;br /&gt;
|Computes the fog from the G-buffer and the lighting parameters&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/display&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on a full screen quad&lt;br /&gt;
|Renders the composite final image from the G-buffer and the lighting buffer&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Guidelines for modelers ==&lt;br /&gt;
&lt;br /&gt;
=== Porting aircraft ===&lt;br /&gt;
* Rembrandt computes shadows =&amp;gt; no more fake shadows in the model&lt;br /&gt;
* Rembrandt computes ambient occlusion =&amp;gt; no ambient occlusion baked into textures&lt;br /&gt;
* Rembrandt has light =&amp;gt; static lightmap are not needed, emissive color to see models at night is not needed and would interfere&lt;br /&gt;
* Rembrandt has glow =&amp;gt; incorrectly used emissive colors may blur displays and make some text unreadable. Light size may have to be adjusted&lt;br /&gt;
* Rembrandt has strict needs with shaders =&amp;gt; shaders need to be adjusted to comply with the new framework otherwise the view will be plain wrong&lt;br /&gt;
* Rembrandt can't do transparent surfaces =&amp;gt; transparent surface need to be properly registered to render them with the classical path&lt;br /&gt;
&lt;br /&gt;
=== Registering all translucent surfaces ===&lt;br /&gt;
&lt;br /&gt;
Every model is, by default, rendered using the &amp;lt;tt&amp;gt;Effects/model-default&amp;lt;/tt&amp;gt; effect. This effect initialize the G-buffer, ignoring transparent surfaces, by doing alpha testing and rendering all the geometry in the default bin. It is not possible to redirect rendering to transparent bins when the associated texture has alpha channel because most models use a single texture atlas and even opaque parts are rendered with texture with alpha channel.&lt;br /&gt;
&lt;br /&gt;
If a model needs to have transparent or translucent surfaces, these surface objects need to be assigned a different effect that sets explicitly the render bin to &amp;quot;DepthSortedBin&amp;quot;, or sets the rendering hint to &amp;quot;transparent&amp;quot;. This tells the renderer to render this object using forward rendering, so lighting and fog need to be enabled, and if a shader program is used, they should be computed in the classical way. The &amp;lt;tt&amp;gt;Effects/model-transparent&amp;lt;/tt&amp;gt; can be used to register simple transparent/translucent surfaces. You assign this effect to an object (or multiple objects) like:&lt;br /&gt;
 &amp;lt;effect&amp;gt;&lt;br /&gt;
  &amp;lt;inherits-from&amp;gt;Effects/model-transparent&amp;lt;/inherits-from&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;TheObject&amp;lt;/object-name&amp;gt;&lt;br /&gt;
 &amp;lt;/effect&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If opaque surface need to have special effect, for example to apply bump mapping, this effect should use the &amp;quot;RenderBin&amp;quot; bin, or the rendering hint set to &amp;quot;opaque&amp;quot;, and the G-buffer needs to be initialized correctly in the Geometry stage.&lt;br /&gt;
&lt;br /&gt;
=== Adding lights to a model ===&lt;br /&gt;
&lt;br /&gt;
There are two things to consider: the appearance of the light source and the illuminated area. For the appearance of the light source (what you see when you look at the bulb), you need a model with an emissive material that will produce the glow effect and that is visible at night.&lt;br /&gt;
&lt;br /&gt;
For the effect of the source on its environment (the lit area), we must have in the 3D model (the .ac file) a volume that includes the effect (Light Volume). It can be a large cone for spotlights or a sphere for point light. It's important that the light volume is closed, convex and it's normals are oriented outward.&lt;br /&gt;
&lt;br /&gt;
The light volume must be part of the geometry of the model and be referenced in the animation file. No need to add a color or an effect to this volume. Light calculation is only done on the fragments covered by the light volume, but has no influence on the color or the attenuation of the light.&lt;br /&gt;
&lt;br /&gt;
All available animations are possible on the light volume, except '''material''' and '''texture'''. It is not possible to change color of lights for the moment, except switching to another animation. Axis and position are in object space and are transformed by the subsequent animations.&lt;br /&gt;
&lt;br /&gt;
==== Spotlights ====&lt;br /&gt;
{|cellpadding=10|&lt;br /&gt;
|valign=top|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;animation&amp;gt;&lt;br /&gt;
   &amp;lt;type&amp;gt;light&amp;lt;/type&amp;gt;&lt;br /&gt;
   &amp;lt;light-type&amp;gt;spot&amp;lt;/light-type&amp;gt;&lt;br /&gt;
   &amp;lt;name&amp;gt;LightSrcRight&amp;lt;/name&amp;gt;&lt;br /&gt;
   &amp;lt;object-name&amp;gt;LightRight&amp;lt;/object-name&amp;gt;&lt;br /&gt;
   &amp;lt;nopreview/&amp;gt;&lt;br /&gt;
   &amp;lt;position&amp;gt;&lt;br /&gt;
     &amp;lt;x&amp;gt;0.169&amp;lt;/x&amp;gt;&lt;br /&gt;
     &amp;lt;y&amp;gt;0.570&amp;lt;/y&amp;gt;&lt;br /&gt;
     &amp;lt;z&amp;gt;0.713&amp;lt;/z&amp;gt;&lt;br /&gt;
   &amp;lt;/position&amp;gt;&lt;br /&gt;
   &amp;lt;direction&amp;gt;&lt;br /&gt;
     &amp;lt;x&amp;gt;-0.9988&amp;lt;/x&amp;gt;&lt;br /&gt;
     &amp;lt;y&amp;gt;0.0349&amp;lt;/y&amp;gt;&lt;br /&gt;
     &amp;lt;z&amp;gt;-0.0349&amp;lt;/z&amp;gt;&lt;br /&gt;
   &amp;lt;/direction&amp;gt;&lt;br /&gt;
   &amp;lt;ambient&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.03&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.03&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.03&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/ambient&amp;gt;&lt;br /&gt;
   &amp;lt;diffuse&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.7&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.7&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.6&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/diffuse&amp;gt;&lt;br /&gt;
   &amp;lt;specular&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.7&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.7&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.7&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/specular&amp;gt;&lt;br /&gt;
   &amp;lt;dim-factor&amp;gt;&lt;br /&gt;
      &amp;lt;property&amp;gt;dimming/property&amp;lt;/property&amp;gt;&lt;br /&gt;
      &amp;lt;!-- optional begin --&amp;gt;&lt;br /&gt;
      &amp;lt;expression /&amp;gt;&lt;br /&gt;
      &amp;lt;interpolation /&amp;gt;&lt;br /&gt;
      &amp;lt;factor&amp;gt;1&amp;lt;/factor&amp;gt;&lt;br /&gt;
      &amp;lt;offset&amp;gt;0&amp;lt;/offset&amp;gt;&lt;br /&gt;
      &amp;lt;min&amp;gt;0&amp;lt;/min&amp;gt;&lt;br /&gt;
      &amp;lt;max&amp;gt;1&amp;lt;/max&amp;gt;&lt;br /&gt;
      &amp;lt;!-- optional end --&amp;gt;&lt;br /&gt;
   &amp;lt;/dim-factor&amp;gt;&lt;br /&gt;
   &amp;lt;attenuation&amp;gt;&lt;br /&gt;
     &amp;lt;c&amp;gt;1.0&amp;lt;/c&amp;gt;&lt;br /&gt;
     &amp;lt;l&amp;gt;0.002&amp;lt;/l&amp;gt;&lt;br /&gt;
     &amp;lt;q&amp;gt;0.00005&amp;lt;/q&amp;gt;&lt;br /&gt;
   &amp;lt;/attenuation&amp;gt;&lt;br /&gt;
   &amp;lt;exponent&amp;gt;30.0&amp;lt;/exponent&amp;gt;&lt;br /&gt;
   &amp;lt;cutoff&amp;gt;39&amp;lt;/cutoff&amp;gt;&lt;br /&gt;
   &amp;lt;near-m&amp;gt;3.5&amp;lt;/near-m&amp;gt;&lt;br /&gt;
   &amp;lt;far-m&amp;gt;39&amp;lt;/far-m&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|valign=top|&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Install the &amp;lt;tt&amp;gt;'''light'''&amp;lt;/tt&amp;gt; animation&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;light-type&amp;lt;/tt&amp;gt;&lt;br /&gt;
|This is a &amp;lt;tt&amp;gt;'''spot'''&amp;lt;/tt&amp;gt; light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Name given to this animation&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;object-name&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Name of the light volume in the 3d model (typically a cone with an apex at &amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt;, along &amp;lt;tt&amp;gt;direction&amp;lt;/tt&amp;gt; axis if &amp;lt;tt&amp;gt;cutoff&amp;lt;/tt&amp;gt; is lesser than 90 degrees, or a sphere centered at &amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt; if &amp;lt;tt&amp;gt;cutoff&amp;lt;/tt&amp;gt; is greater than 90 degrees )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;nopreview&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Hide light volume in fgrun 3d preview&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In object space, position of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;direction&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In object space, direction to the center of the spot&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;ambient&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Ambient color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;diffuse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Diffuse color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;specular&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Specular color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;dim-factor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Group of parameters to control a factor that is applied to ambient, diffuse and specular at the same time&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;attenuation&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Three element vector. &amp;lt;c&amp;gt; element is the constant factor, &amp;lt;l&amp;gt; element is the linear factor and &amp;lt;q&amp;gt; element is the quadratic factor.&amp;lt;br /&amp;gt;&lt;br /&gt;
Attenuation of color at distance d is [[File:Spotlight_attenuation.png]]&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;exponent&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Attenuation is multiplied by &amp;lt;tt&amp;gt;pow( dot( lightDir, &amp;lt;direction&amp;gt; ), &amp;lt;exponent&amp;gt; )&amp;lt;/tt&amp;gt;, lightDir being vector from light position to point, in camera space.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;cutoff&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Point is lit by this source if &amp;lt;tt&amp;gt;dot( lightDir, &amp;lt;direction&amp;gt; ) &amp;gt; &amp;lt;cutoff&amp;gt;&amp;lt;/tt&amp;gt; , lightDir being vector from light position to point, in camera space.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;near-m&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Minimum distance of influence, from position, in meters&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;far-m&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Maximum distance of influence, from position, in meters&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Point lights ====&lt;br /&gt;
{|cellpadding=10|&lt;br /&gt;
|valign=top|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;animation&amp;gt;&lt;br /&gt;
   &amp;lt;type&amp;gt;light&amp;lt;/type&amp;gt;&lt;br /&gt;
   &amp;lt;light-type&amp;gt;point&amp;lt;/light-type&amp;gt;&lt;br /&gt;
   &amp;lt;name&amp;gt;LightSrcRight&amp;lt;/name&amp;gt;&lt;br /&gt;
   &amp;lt;object-name&amp;gt;LightRight&amp;lt;/object-name&amp;gt;&lt;br /&gt;
   &amp;lt;nopreview/&amp;gt;&lt;br /&gt;
   &amp;lt;position&amp;gt;&lt;br /&gt;
     &amp;lt;x&amp;gt;0.169&amp;lt;/x&amp;gt;&lt;br /&gt;
     &amp;lt;y&amp;gt;0.570&amp;lt;/y&amp;gt;&lt;br /&gt;
     &amp;lt;z&amp;gt;0.713&amp;lt;/z&amp;gt;&lt;br /&gt;
   &amp;lt;/position&amp;gt;&lt;br /&gt;
   &amp;lt;ambient&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.03&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.03&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.03&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/ambient&amp;gt;&lt;br /&gt;
   &amp;lt;diffuse&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.7&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.7&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.6&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/diffuse&amp;gt;&lt;br /&gt;
   &amp;lt;specular&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.7&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.7&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.7&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/specular&amp;gt;&lt;br /&gt;
   &amp;lt;dim-factor&amp;gt;&lt;br /&gt;
      &amp;lt;property&amp;gt;dimming/property&amp;lt;/property&amp;gt;&lt;br /&gt;
      &amp;lt;!-- optional begin --&amp;gt;&lt;br /&gt;
      &amp;lt;expression /&amp;gt;&lt;br /&gt;
      &amp;lt;interpolation /&amp;gt;&lt;br /&gt;
      &amp;lt;factor&amp;gt;1&amp;lt;/factor&amp;gt;&lt;br /&gt;
      &amp;lt;offset&amp;gt;0&amp;lt;/offset&amp;gt;&lt;br /&gt;
      &amp;lt;min&amp;gt;0&amp;lt;/min&amp;gt;&lt;br /&gt;
      &amp;lt;max&amp;gt;1&amp;lt;/max&amp;gt;&lt;br /&gt;
      &amp;lt;!-- optional end --&amp;gt;&lt;br /&gt;
   &amp;lt;/dim-factor&amp;gt;&lt;br /&gt;
   &amp;lt;attenuation&amp;gt;&lt;br /&gt;
     &amp;lt;c&amp;gt;1.0&amp;lt;/c&amp;gt;&lt;br /&gt;
     &amp;lt;l&amp;gt;0.002&amp;lt;/l&amp;gt;&lt;br /&gt;
     &amp;lt;q&amp;gt;0.00005&amp;lt;/q&amp;gt;&lt;br /&gt;
   &amp;lt;/attenuation&amp;gt;&lt;br /&gt;
   &amp;lt;near-m&amp;gt;3.5&amp;lt;/near-m&amp;gt;&lt;br /&gt;
   &amp;lt;far-m&amp;gt;39&amp;lt;/far-m&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|valign=top|&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Install the &amp;lt;tt&amp;gt;'''light'''&amp;lt;/tt&amp;gt; animation&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;light-type&amp;lt;/tt&amp;gt;&lt;br /&gt;
|This is a &amp;lt;tt&amp;gt;'''point'''&amp;lt;/tt&amp;gt; light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Name given to this animation&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;object-name&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Name of the light volume in the 3d model (typically a sphere centered on &amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt;, with a radius of &amp;lt;tt&amp;gt;far-m&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;nopreview&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Hide light volume in fgrun 3d preview&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In object space, position of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;ambient&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Ambient color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;diffuse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Diffuse color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;specular&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Specular color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;dim-factor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Group of parameters to control a factor that is applied to ambient, diffuse and specular at the same time&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;attenuation&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Three element vector. &amp;lt;c&amp;gt; element is the constant factor, &amp;lt;l&amp;gt; element is the linear factor and &amp;lt;q&amp;gt; element is the quadratic factor.&amp;lt;br /&amp;gt;&lt;br /&gt;
Attenuation of color at distance d is [[File:Spotlight_attenuation.png]]&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;near-m&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Minimum distance of influence, from position, in meters&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;far-m&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Maximum distance of influence, from position, in meters&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initial TODO List ==&lt;br /&gt;
*Fix shadow rendering when using multi threading in OSG&lt;br /&gt;
*&amp;lt;del&amp;gt;Implement Cascaded Shadow Map (need to be optimized - frustum calculation and night&amp;lt;/del&amp;gt;)&lt;br /&gt;
*Honor &amp;lt;noshadow&amp;gt; animation directive&lt;br /&gt;
*See what happens with glow in fog&lt;br /&gt;
*Test multi-screen&lt;br /&gt;
*Restore splashscreen&lt;br /&gt;
*&amp;lt;del&amp;gt;Draw transparent objects with forward rendering (may need to capture the transparent bin from the geometry stage and move it in the display stage)&amp;lt;/del&amp;gt; (OK - needs model contribution)&lt;br /&gt;
*&amp;lt;del&amp;gt;Add spotlights as animations (nearly finished)&amp;lt;/del&amp;gt;&lt;br /&gt;
*&amp;lt;del&amp;gt;find a solution for ambient and emissive color of material (may need an additional buffer)&amp;lt;/del&amp;gt;&lt;br /&gt;
*implement strength of glow (in the emissive buffer alpha channel)&lt;br /&gt;
**provide levels 0 to 5 - we are currently at level 5&lt;br /&gt;
**level 0 should be ok for MFDs that are currenly unreadable because blurred&lt;br /&gt;
*Provide a shader for transparent objects that could render to the emissive buffer too (using MRT)&lt;br /&gt;
*&amp;lt;del&amp;gt;Use stencil buffer to limit light range&amp;lt;/del&amp;gt;(no - done in light shader)&lt;br /&gt;
**needed for cockpit light to implement fake shadows and avoid lighting the runway from the cabin through the airframe&lt;br /&gt;
*Use effect system instead of hard-coded shaders (mostly done)&lt;br /&gt;
*Convert existing shaders to deferred rendering&lt;br /&gt;
**Modify shadows to allow multiple casters (limited list)&lt;br /&gt;
**Implement a priority list of light sources, based on priority and distance from the viewer&lt;br /&gt;
**&amp;lt;del&amp;gt;Add new animation to link a light source to a model&amp;lt;/del&amp;gt; (need to provide point light animation duplicating spot light)&lt;br /&gt;
*Tidy up the architecture&lt;br /&gt;
*Restore depth partitioning using depth ranges&lt;br /&gt;
*Restore stereo and other options currently available in CameraGroup&lt;br /&gt;
*Implement quality vs performance user control&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Merge in next&amp;quot; TODO List ==&lt;br /&gt;
*&amp;lt;del&amp;gt;Design and implement a configurable pipeline&amp;lt;/del&amp;gt; (done)&lt;br /&gt;
*Implement lightfield shader&lt;br /&gt;
&lt;br /&gt;
== Gallery ==&lt;br /&gt;
{{#ev:youtube|PXHhtQb5yzc}} {{#ev:youtube|peEzEapavkg}} {{#ev:youtube|RIetPh8iJXk}} {{#ev:youtube|oaNFrxgQY1c}} {{#ev:youtube|8xGzy12hlis}} {{#ev:youtube|ZyuHBlm3xXU}} {{#ev:youtube|RgH9GZRukOI}} {{#ev:youtube|UQvbHnBkpaM}} {{#ev:youtube|v02phoOqWHE}}{{#ev:youtube|dlSo4sBa7Nk}}&lt;br /&gt;
&lt;br /&gt;
{{Appendix|all|&lt;br /&gt;
* {{cite web |url=http://http.download.nvidia.com/developer/presentations/2004/6800_Leagues/6800_Leagues_Deferred_Shading.pdf |title=Deferred Shading |author=Shawn Hargreaves and Mark Harris }}&lt;br /&gt;
* {{cite web |url=http://bat710.univ-lyon1.fr/~jciehl/Public/educ/GAMA/2007/Deferred_Shading_Tutorial_SBGAMES2005.pdf |title=Deferred Shading Tutorial |author=Fabio Policarpo and Francisco Fonseca }}&lt;br /&gt;
* {{cite web |url=http://www.guerrilla-games.com/publications/dr_kz2_rsx_dev07.pdf |title=Deferred Rendering in Killzone 2 |author=Michal Valient |month=July |year=2007 }}&lt;br /&gt;
* {{cite web |url=http://www.anandtech.com/show/5011/nvidiaea-posts-battlefield-3-graphics-tech-talk |title=Battlefield 3 Graphics Tech Talk |author=Johan Andersson |month=October |year=2011 }}&lt;br /&gt;
* {{cite web |url=http://www.disney.co.uk/cms_res/blackrockstudio/pdf/Rendering_Techniques_in_SplitSecond.pdf |title=Rendering Techniques in Split/Second |author=Jeremy Moore and David Jefferies |year=2009 }}&lt;br /&gt;
* {{cite web |url=http://www.crytek.com/sites/default/files/A_bit_more_deferred_-_CryEngine3.ppt |title=&amp;quot;A bit more Deferred&amp;quot; - CryEngine 3 (PPT) |author=Martin Mittring }}&lt;br /&gt;
* {{cite web |url=http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter09.html |title=Deferred Shading in S.T.A.L.K.E.R. |author=Oles Shishkovtsov }}&lt;br /&gt;
* {{cite web |url=http://http.developer.nvidia.com/GPUGems3/gpugems3_ch19.html |title=Deferred Shading in Tabula Rasa |author=Rusty Koonce }}&lt;br /&gt;
* {{cite web |url=http://aras-p.info/texts/CompactNormalStorage.html |title=Compact Normal Storage for small g-buffers |author=Aras Pranckevičius |date=4 August 2009 |accessdate=12 April 2012 }}&lt;br /&gt;
* {{cite web |url=http://the-witness.net/news/2010/03/graphics-tech-shadow-maps-part-1/ |title=Graphics Tech: Shadow Maps (part 1) |author=Jonathan Blow |date=3 March 2010 |accessdate=13 April 2012 }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Shader development]]&lt;br /&gt;
[[Category:Core development projects]]&lt;/div&gt;</summary>
		<author><name>Mcginnly</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=User:Mcginnly&amp;diff=49935</id>
		<title>User:Mcginnly</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=User:Mcginnly&amp;diff=49935"/>
		<updated>2012-05-16T17:15:05Z</updated>

		<summary type="html">&lt;p&gt;Mcginnly: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Links==&lt;br /&gt;
*[[Howto:Animate models]]&lt;br /&gt;
*[[Howto:Make a clickable panel]]&lt;br /&gt;
*[[Creating instruments for FG]]&lt;br /&gt;
*[[Bindings]]&lt;/div&gt;</summary>
		<author><name>Mcginnly</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=User:Mcginnly&amp;diff=49934</id>
		<title>User:Mcginnly</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=User:Mcginnly&amp;diff=49934"/>
		<updated>2012-05-16T17:14:10Z</updated>

		<summary type="html">&lt;p&gt;Mcginnly: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Links==&lt;br /&gt;
*[[Howto:Animate models]]&lt;br /&gt;
*[[Howto:Make a clickable panel]]&lt;br /&gt;
*[[Creating instruments for FG]]&lt;/div&gt;</summary>
		<author><name>Mcginnly</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=User:Mcginnly&amp;diff=49933</id>
		<title>User:Mcginnly</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=User:Mcginnly&amp;diff=49933"/>
		<updated>2012-05-16T17:13:09Z</updated>

		<summary type="html">&lt;p&gt;Mcginnly: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Links==&lt;br /&gt;
*[[Howto:Animate models]]&lt;br /&gt;
*[[Howto:Make a clickable panel]]&lt;/div&gt;</summary>
		<author><name>Mcginnly</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=User:Mcginnly&amp;diff=49890</id>
		<title>User:Mcginnly</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=User:Mcginnly&amp;diff=49890"/>
		<updated>2012-05-16T15:16:33Z</updated>

		<summary type="html">&lt;p&gt;Mcginnly: Created page with &amp;quot;==Links== *Howto:Animate models&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Links==&lt;br /&gt;
*[[Howto:Animate models]]&lt;/div&gt;</summary>
		<author><name>Mcginnly</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Talk:Map_dialog&amp;diff=49884</id>
		<title>Talk:Map dialog</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Talk:Map_dialog&amp;diff=49884"/>
		<updated>2012-05-16T13:56:52Z</updated>

		<summary type="html">&lt;p&gt;Mcginnly: taxiways?&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Unplanned improvements==&lt;br /&gt;
How about taxiway designations? --[[User:Mcginnly|Mcginnly]] 09:56, 16 May 2012 (EDT)&lt;/div&gt;</summary>
		<author><name>Mcginnly</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Project_Rembrandt&amp;diff=49878</id>
		<title>Project Rembrandt</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Project_Rembrandt&amp;diff=49878"/>
		<updated>2012-05-15T00:36:26Z</updated>

		<summary type="html">&lt;p&gt;Mcginnly: /* Repositories */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
== Why this name ? ==&lt;br /&gt;
[http://en.wikipedia.org/wiki/Rembrandt Rembrandt] was a dutch painter living in the 17th century, famous as one of the master of [http://en.wikipedia.org/wiki/Chiaroscuro chiaroscuro].&lt;br /&gt;
&lt;br /&gt;
This project is about changing the way [[FlightGear]] renders lights, [[shadows]] and shades, and aims at making Rembrandt painting style possible in FG.&lt;br /&gt;
&lt;br /&gt;
== What is it ? ==&lt;br /&gt;
The idea driving the project is to implement [http://en.wikipedia.org/wiki/Deferred_shading deferred rendering] inside FlightGear.&lt;br /&gt;
From the beginning FlightGear had a forward renderer that tries to render all properties of an object in one pass (shading, lighting, fog, ...), making it difficult to render more sophisticated shading &lt;br /&gt;
(see the [[FlightGear Newsletter December 2011#Shaders|'Uber-shader']]) because one has to take into account all aspects of the [http://www.wired.com/magazine/2010/07/st_equation_3danimation/ rendering equation].&lt;br /&gt;
&lt;br /&gt;
[[Image:project_rembrandt_1.png|thumb|300px|Main view with the content of buffers displayed at corners]]&lt;br /&gt;
On the contrary, deferred rendering is about separating operations in simplified stages and collecting the intermediary results in hidden buffers that can be used by the next stage.&lt;br /&gt;
&lt;br /&gt;
;First stage is the Geometry Stage :&lt;br /&gt;
: we render all the scene into 4 textures, using multi render targets, to do it in one pass: one for the depth buffer, one for the normals (lower left of the image), one for the diffuse colors (lower right) and one for the specular colors (upper right).&lt;br /&gt;
&lt;br /&gt;
;Next stage is the Shadow Stage :&lt;br /&gt;
: we render the scene again into a depth texture from the point of view of the lights. There will be one texture for every light casting shadows.&lt;br /&gt;
&lt;br /&gt;
;Then comes the Lighting Stage, with several substages :&lt;br /&gt;
:*&amp;lt;u&amp;gt;Sky pass&amp;lt;/u&amp;gt;: the sky is first drawn using classical method.&lt;br /&gt;
:*&amp;lt;u&amp;gt;Ambient pass&amp;lt;/u&amp;gt;: the diffuse buffer is modulated with the ambient color of the scene and is drawn as a screen-aligned textured quad&lt;br /&gt;
:*&amp;lt;u&amp;gt;Sunlight pass&amp;lt;/u&amp;gt;: a second screen aligned quad is drawn and a shader computes the view position of every pixel to compute its diffuse and specular color, using the normal stored in the first stage. The resulting color is blended with the previous pass. Shadows are computed here by comparing the position of the pixel with the position of the light occluder stored in the shadow map.&lt;br /&gt;
:*&amp;lt;u&amp;gt;Additional light pass&amp;lt;/u&amp;gt;: the scene graph will be traversed another time to display light volumes (cone or frusta for spot lights, sphere for omni-directional lights) and their shader will add the light contributed by the source only on pixels receiving light.&lt;br /&gt;
:*&amp;lt;u&amp;gt;Fog pass&amp;lt;/u&amp;gt;: a new screen aligned quad is draw and the position of the pixel is computed to evaluate the amount of fog the pixel has. The fog color is blended with the result of the previous stage.&lt;br /&gt;
:*&amp;lt;u&amp;gt;Transparent objects pass&amp;lt;/u&amp;gt;: transparent objects (and clouds) are finally rendered using classical method.&lt;br /&gt;
&lt;br /&gt;
:All lighting computations are accumulated in a single buffer that will be used for the last stage, in addition of the one computed by the Geometry stage.&lt;br /&gt;
&lt;br /&gt;
;In the end, the Display Stage, with optional Post-Processing effect :&lt;br /&gt;
:The results of the previous buffers are pushed to the main framebuffer to be displayed, optionally modified to show Glow, Motion blur, HDR, redout or blackout, screen-space ambient occlusion, anti-aliasing, etc...&lt;br /&gt;
&lt;br /&gt;
In FG, we end the rendering pipeline by displaying the [[Menubar|GUI]] and the [[HUD]].&lt;br /&gt;
&lt;br /&gt;
All these stages are more precisely described if this [http://bat710.univ-lyon1.fr/~jciehl/Public/educ/GAMA/2007/Deferred_Shading_Tutorial_SBGAMES2005.pdf tutorial] that is the basis of the current code, with some addition and modifications.&lt;br /&gt;
&lt;br /&gt;
== Caveats ==&lt;br /&gt;
Deferred rendering is not capable to display transparent. For the moment, clouds are renderer separately and should be lit and shaded by their own. Transparent surfaces are alpha-tested and not blended. They would have to be drawn in their own bin over the composited image.&lt;br /&gt;
&lt;br /&gt;
It also don't fit with depth partitioning because the depth buffer should be kept to retain the view space position, so for the moment, z-fighting is quite visible. Depth partitioning with non overlapping depth range might be the solution and should be experimented at one point.&lt;br /&gt;
&lt;br /&gt;
The glow pass can make certain MFD (that use emissive color) unreadable because blurred. Should be treated as transparent.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
=== Repositories ===&lt;br /&gt;
The code is in the main branch of the [[FlightGear and Git|official repository]]. Any other location is not maintained anymore.&lt;br /&gt;
&lt;br /&gt;
=== Rendering of transparent surfaces ===&lt;br /&gt;
[[Image:project_rembrandt_5.png|thumb|300px|Transparent surfaces drawn after opaque objects]]&lt;br /&gt;
Transparent surfaces are detected by OSG loader plugins and their state set receive the TRANSPARENT_BIN rendering hint. In the culling pass, the cull visitor orders transparent surfaces in transparent bin. In a cull callback attached to the Geometry camera, after the scenegraph traversal, the transparent bins are removed from the render stage and saved in a temporary collection. In a cull callback attached to the Lighting camera, after the scenegraph traversal, the transparent bins saved at the previous stage, are added to the render stage of the Lighting camera with a high order num. That way, the transparent surface are drawn on top of the scene lighted from the Gbuffer.&lt;br /&gt;
&lt;br /&gt;
=== Memory consumption ===&lt;br /&gt;
For each camera defined in the camera group, there is a separate shadow map, so the video memory usage is :&lt;br /&gt;
* G-buffer and Lighting buffer: 20 bytes per pixel. For an HD screen (1920x1080) memory requirement is 40 Mb&lt;br /&gt;
* Shadow map: 3 x shadow_map_size x shadow_map_size bytes (if size is 8192, whole map size is 192 Mb&lt;br /&gt;
Not counting textures, display list or vertex buffers for models and terrain&lt;br /&gt;
&lt;br /&gt;
3 HD screens require 120 Mb of memory for the buffers (shadow excluded), you're asking 3x8192x8192x3 = 576 Mb (megabytes) of memory for the shadows alone.&lt;br /&gt;
&lt;br /&gt;
If you are seeing error messages during startup or FlightGear doesn't start up properly, it's probably because you don't have enough free video memory. Reduce the size of the shadow map in preferences.xml by locating &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;map-size type=&amp;quot;int&amp;quot;&amp;gt;8192&amp;lt;/map-size&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And put 4096 or 2048 instead.&lt;br /&gt;
You can also use a startup parameter: --prop:/sim/rendering/shadows/map-size=2048&lt;br /&gt;
&lt;br /&gt;
=== Configurable pipeline ===&lt;br /&gt;
&lt;br /&gt;
The Rembrandt renderer uses an XML file to setup its pipeline for each viewport described in the camera group. This file describes the way the intermediary buffers are setup and how the different rendering stages are sequenced. The general outline of a pipeline file is as follow :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
	&amp;lt;!-- BUFFERS --&amp;gt;&lt;br /&gt;
	&amp;lt;buffer&amp;gt;&lt;br /&gt;
		&amp;lt;!-- First buffer definition --&amp;gt;&lt;br /&gt;
	&amp;lt;/buffer&amp;gt;&lt;br /&gt;
	&amp;lt;buffer&amp;gt;&lt;br /&gt;
		&amp;lt;!-- nth buffer definition --&amp;gt;&lt;br /&gt;
	&amp;lt;/buffer&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;!-- STAGES --&amp;gt;&lt;br /&gt;
	&amp;lt;stage&amp;gt;&lt;br /&gt;
		&amp;lt;!-- First stage definition --&amp;gt;&lt;br /&gt;
	&amp;lt;/stage&amp;gt;&lt;br /&gt;
	&amp;lt;stage&amp;gt;&lt;br /&gt;
		&amp;lt;!-- nth stage definition --&amp;gt;&lt;br /&gt;
	&amp;lt;/stage&amp;gt;&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Buffers ====&lt;br /&gt;
A buffer is a texture used as a storage area in the GPU. It's size is usually a multiple of the screen size, but fixed size is supported (typical for shadow map). The description of a buffer is described below :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;buffer&amp;gt;&lt;br /&gt;
		&amp;lt;name&amp;gt;buffer-name&amp;lt;/name&amp;gt;&lt;br /&gt;
		&amp;lt;internal-format&amp;gt;rgba8&amp;lt;/internal-format&amp;gt; &amp;lt;!-- rgb8, rgba8, rgb16, rgba16, rg16, depth-component24, depth-component32 or OpenGL hex value --&amp;gt;&lt;br /&gt;
		&amp;lt;source-format&amp;gt;rgba&amp;lt;/source-format&amp;gt; &amp;lt;!-- rg, rgb, rgba, depth-component or OpenGL hex value --&amp;gt;&lt;br /&gt;
		&amp;lt;source-type&amp;gt;unsigned-byte&amp;lt;/source-type&amp;gt; &amp;lt;!-- unsigned-byte, unsigned-short, unsigned-int, float or OpenGL hex value --&amp;gt;&lt;br /&gt;
		&amp;lt;width&amp;gt;screen&amp;lt;/width&amp;gt; &amp;lt;!-- screen, value or &amp;lt;property&amp;gt;/a/width/property&amp;lt;/property&amp;gt; --&amp;gt;&lt;br /&gt;
		&amp;lt;height&amp;gt;screen&amp;lt;/height&amp;gt; &amp;lt;!-- screen, value or &amp;lt;property&amp;gt;/a/height/property&amp;lt;/property&amp;gt; --&amp;gt;&lt;br /&gt;
		&amp;lt;scale-factor&amp;gt;1.0&amp;lt;/scale-factor&amp;gt;&lt;br /&gt;
		&amp;lt;wrap-mode&amp;gt;clamp-to-border&amp;lt;/wrap-mode&amp;gt; &amp;lt;!-- clamp, clamp-to-border, clamp-to-edge, mirror, repeat or OpenGL hex value --&amp;gt;&lt;br /&gt;
		&amp;lt;!-- optional, for shadow map --&amp;gt;&lt;br /&gt;
		&amp;lt;shadow-comparison&amp;gt;true&amp;lt;/shadow-comparison&amp;gt;&lt;br /&gt;
		&amp;lt;!-- optional condition --&amp;gt;&lt;br /&gt;
		&amp;lt;condition&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Valid boolean expression --&amp;gt;&lt;br /&gt;
		&amp;lt;/condition&amp;gt;&lt;br /&gt;
	&amp;lt;/buffer&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Stages ====&lt;br /&gt;
A stage is an unit of rendering to a group of buffer. Most stages are predefined and their type is not free. When a type is not specified, the name is used. Stage types are :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!align=&amp;quot;left&amp;quot;| Stage type&lt;br /&gt;
!align=&amp;quot;left&amp;quot;| Purpose&lt;br /&gt;
|-&lt;br /&gt;
|geometry&lt;br /&gt;
|The geometry stage initialize most of the buffers and works on the real objects and geometry. Transparent objects are set aside and will be used untouched in the lighting stage. Other opaque geometry is rendered with the standard effects that do the hard work to put sensible data in the buffers.&lt;br /&gt;
|-&lt;br /&gt;
|shadow&lt;br /&gt;
|In this stage, the geometry is rendered in the normal map from the perspective of the sun.&lt;br /&gt;
|-&lt;br /&gt;
|lighting&lt;br /&gt;
|This stage uses the buffers filled by the previous stages to light every pixel of the scene. The result is rendered in another buffer to allow post effects.&lt;br /&gt;
|-&lt;br /&gt;
|fullscreen&lt;br /&gt;
|Stages of this type are used to alter the whole scene or transform data from a particular buffer.&lt;br /&gt;
|-&lt;br /&gt;
|display&lt;br /&gt;
|Final rendering of the scene to the screen or the texture defined in the camera group.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A stage description is outlined below :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;stage&amp;gt;&lt;br /&gt;
		&amp;lt;name&amp;gt;stage-name&amp;lt;/name&amp;gt;&lt;br /&gt;
		&amp;lt;type&amp;gt;stage-type&amp;lt;/type&amp;gt; &amp;lt;!-- optional if name is one of the predefined type except fullscreen --&amp;gt;&lt;br /&gt;
		&amp;lt;order-num&amp;gt;-1&amp;lt;/order-num&amp;gt;&lt;br /&gt;
		&amp;lt;effect&amp;gt;Effects/fullscreen-effect&amp;lt;/effect&amp;gt; &amp;lt;!-- only if type == fullscreen --&amp;gt;&lt;br /&gt;
		&amp;lt;needs-du-dv&amp;gt;true&amp;lt;/needs-du-dv&amp;gt; &amp;lt;!-- only if type == fullscreen --&amp;gt;&lt;br /&gt;
		&amp;lt;scale-factor&amp;gt;0.25&amp;lt;/scale-factor&amp;gt; &amp;lt;!-- only if type == fullscreen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
		&amp;lt;!-- optional condition --&amp;gt;&lt;br /&gt;
		&amp;lt;condition&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Valid boolean expression --&amp;gt;&lt;br /&gt;
		&amp;lt;/condition&amp;gt;&lt;br /&gt;
&lt;br /&gt;
		&amp;lt;attachment&amp;gt;&lt;br /&gt;
			&amp;lt;!-- First attachment definition --&amp;gt;&lt;br /&gt;
		&amp;lt;/attachment&amp;gt;&lt;br /&gt;
		&amp;lt;attachment&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Nth attachment definition --&amp;gt;&lt;br /&gt;
		&amp;lt;/attachment&amp;gt;&lt;br /&gt;
&lt;br /&gt;
		&amp;lt;!-- Passes only for the lighting stage --&amp;gt;&lt;br /&gt;
		&amp;lt;pass&amp;gt;&lt;br /&gt;
			&amp;lt;!-- First pass definition --&amp;gt;&lt;br /&gt;
		&amp;lt;/pass&amp;gt;&lt;br /&gt;
		&amp;lt;pass&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Nth pass definition --&amp;gt;&lt;br /&gt;
		&amp;lt;/pass&amp;gt;&lt;br /&gt;
	&amp;lt;/stage&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Stages render in buffers (except for the display stage). Attachments describe which buffers are affected by each stage.&lt;br /&gt;
&lt;br /&gt;
===== Attachments =====&lt;br /&gt;
Attachment describe bindings between buffer and attachment point :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;attachment&amp;gt;&lt;br /&gt;
		&amp;lt;component&amp;gt;color0&amp;lt;/component&amp;gt; &amp;lt;!-- depth, stencil, packed-depth-stencil, color0, color1, color2 or color3 --&amp;gt;&lt;br /&gt;
		&amp;lt;buffer&amp;gt;buffer-name&amp;lt;/buffer&amp;gt;&lt;br /&gt;
		&amp;lt;!-- optional condition --&amp;gt;&lt;br /&gt;
		&amp;lt;condition&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Valid boolean expression --&amp;gt;&lt;br /&gt;
		&amp;lt;/condition&amp;gt;&lt;br /&gt;
	&amp;lt;/attachment&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Passes =====&lt;br /&gt;
Passes are only available in the &amp;lt;tt&amp;gt;lighting&amp;lt;/tt&amp;gt; stage. Three kind of stage are allowed :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!align=&amp;quot;left&amp;quot;| Pass type&lt;br /&gt;
!align=&amp;quot;left&amp;quot;| Purpose&lt;br /&gt;
|-&lt;br /&gt;
|sky-clouds&lt;br /&gt;
|Renders the skydome, sun, moon, planet, stars and clouds&lt;br /&gt;
|-&lt;br /&gt;
|lights&lt;br /&gt;
|Renders additional spot and point lights&lt;br /&gt;
|-&lt;br /&gt;
|fullscreen&lt;br /&gt;
|Fullscreen pass analog to a fullscreen stage except that it renders in the buffers attached to the lighting stage&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;pass&amp;gt;&lt;br /&gt;
		&amp;lt;name&amp;gt;pass-name&amp;lt;/name&amp;gt;&lt;br /&gt;
		&amp;lt;type&amp;gt;pass-type&amp;lt;/type&amp;gt; &amp;lt;!-- optional if name is one of the predefined type except fullscreen --&amp;gt;&lt;br /&gt;
		&amp;lt;order-num&amp;gt;-1&amp;lt;/order-num&amp;gt;&lt;br /&gt;
		&amp;lt;effect&amp;gt;Effects/fullscreen-effect&amp;lt;/effect&amp;gt; &amp;lt;!-- only if type == fullscreen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
		&amp;lt;!-- optional condition --&amp;gt;&lt;br /&gt;
		&amp;lt;condition&amp;gt;&lt;br /&gt;
			&amp;lt;!-- Valid boolean expression --&amp;gt;&lt;br /&gt;
		&amp;lt;/condition&amp;gt;&lt;br /&gt;
	&amp;lt;/pass&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Running Flightgear with Rembrandt ==&lt;br /&gt;
&lt;br /&gt;
The Rembrandt renderer is now integrated in the main repository but needs to be enabled to run. Use the &amp;lt;tt&amp;gt;--enable-rembrandt&amp;lt;/tt&amp;gt; option to start Flightgear with this new renderer.&lt;br /&gt;
&lt;br /&gt;
Rembrandt is quite demanding in GPU resources and may fail to run with the default options. The more frequent symptom is an OSG message in the console :&lt;br /&gt;
&lt;br /&gt;
 RenderStage::runCameraSetUp(), FBO setup failed, FBO status= 0x8cd6&lt;br /&gt;
 Warning: RenderStage::runCameraSetUp(State&amp;amp;) Pbuffer does not support multiple color outputs.&lt;br /&gt;
&lt;br /&gt;
Some card also exhibit messages like this :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgram &amp;quot;&amp;quot; FAILED&lt;br /&gt;
 Program &amp;quot;&amp;quot; infolog:&lt;br /&gt;
 Fragment info&lt;br /&gt;
 -------------&lt;br /&gt;
 0(37) : error C6013: Only arrays of texcoords may be indexed in this profile, and only with a loop index variable&lt;br /&gt;
 0(36) : error C6013: Only arrays of texcoords may be indexed in this profile, and only with a loop index variable&lt;br /&gt;
 0(35) : error C6013: Only arrays of texcoords may be indexed in this profile, and only with a loop index variable&lt;br /&gt;
 0(34) : error C6013: Only arrays of texcoords may be indexed in this profile, and only with a loop index variable&lt;br /&gt;
&lt;br /&gt;
There is a number of additional options that can help to avoid these problems :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/rembrandt/use-color-for-depth=true&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Some old NVidia cards, such as 7600GT, don't give enough resolution for depth and that result in &amp;quot;fog curtains&amp;quot; at few meters from the viewer. One trick is to encode depth in another texture and get the proper value afterward. This option enables that.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/enabled=false&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Disable shadows altogether. This setting is changeable at runtime in the rendering option dialog.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/num-cascades=1&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Avoid the &amp;quot;error C6013&amp;quot; message on old cards at the cost of resolution in the cockpit. Set &amp;lt;tt&amp;gt;/sim/rendering/shadows/cascade-far-m[0]&amp;lt;/tt&amp;gt; to change the shadow map range. The more the range, the less the resolution (default value is 5 meters)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/map-size=&amp;lt;power-of-two&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Set the shadow map size. Useful values are 1024, 2048, 4096 or 8192. Few cards have the resources to support 16384.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/num-cascades&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Set the shadow map cascade number. Less cascades means less time spent in shadow map generation, but also means lower shadow quality. Integer between 1 and 4.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/shadows/cascade-far-m[i]&amp;lt;/tt&amp;gt;&lt;br /&gt;
(1 &amp;lt;= i &amp;lt;= &amp;lt;tt&amp;gt;/sim/rendering/shadows/num-cascades&amp;lt;/tt&amp;gt; &amp;lt;= 4)&lt;br /&gt;
|Set the shadow map cascade range for each cascade. Default values are 5m, 50m, 500m and 5000m for 4 cascades.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;--prop:/sim/rendering/rembrandt/no-16bit-buffer=false&amp;lt;/tt&amp;gt;&lt;br /&gt;
|By default, Rembrandt uses 8 bit buffers for normals (so the property is set to true by default). This may create banding artifacts on specular highlights. If it's unacceptable and the GPU supports it, set to false to have better precision for normals and effects relying on normal direction.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Guidelines for shader writers ==&lt;br /&gt;
=== Predefined uniforms ===&lt;br /&gt;
These glsl uniforms don't need to be declared in the effect file.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ViewMatrix&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In fullscreen pass only, view matrix used to transform the screen position to view direction&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ViewMatrixInverse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In fullscreen pass only, view matrix inverse used to transform the screen position to view direction&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ProjectionMatrixInverse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In fullscreen pass only, projection matrix inverse used to transform the screen position to view direction&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_SunAmbientColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_SunDiffuseColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_SunSpecularColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_SunDirection&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec3&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_FogColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_FogDensity&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ShadowNumber&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_ShadowDistances&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_DepthInColor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;bool&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Tells if the depth is stored in a depth texture or a color texture&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_Planes&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec3&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Used to convert the value of the depth buffer to a depth that can be used to compute the eye space position of the fragment&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;fg_BufferSize&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;vec2&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Dimensions of the buffer, used to convert gl_FragCoord into the range [0..1][0..1]&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;osg_ViewMatrix&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Defined by OSG, used only when working on actual geometry&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;osg_ViewMatrixInverse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;mat4&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Defined by OSG, used only when working on actual geometry&lt;br /&gt;
|}&lt;br /&gt;
They still have to be declared in the fragment or the vertex shader to be used.&lt;br /&gt;
&lt;br /&gt;
=== Utility functions ===&lt;br /&gt;
&lt;br /&gt;
To ease the maintenance of shaders, several utility functions are available for the fragment shader. These functions are put together in two files : &amp;lt;tt&amp;gt;gbuffer-functions.frag&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;gbuffer-encode.frag&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== gbuffer-encode.frag ====&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;void encode_gbuffer(vec3 normal, vec3 color, int mId, float specular, float shininess, float emission, float depth)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Used to encode all the values of the G-Buffer in material shaders&lt;br /&gt;
&lt;br /&gt;
==== gbuffer-functions.frag ====&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec2 normal_encode(vec3 n)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Used to compress normals into the G-Buffer in material shaders. Normally called from &amp;lt;tt&amp;gt;encode_gbuffer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 normal_decode(vec2 enc)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Reconstruct normals from the G-Buffer. Used in fullscreen shaders and light shaders&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 float_to_color(in float f)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Encode float values in the range [0..1] in the 24 bits of a color. This function is used by &amp;lt;tt&amp;gt;encode_gbuffer()&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;/sim/rendering/use-color-for_depth&amp;lt;/tt&amp;gt; is true, for old cards that don't provide depth information with enough resolution inside fullscreen or light shaders.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;float color_to_float(vec3 color)&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Decode float values in the range [0..1] from the 24 bits of a color. This function is used by &amp;lt;tt&amp;gt;position()&amp;lt;/tt&amp;gt; if the &amp;lt;tt&amp;gt;/sim/rendering/use-color-for_depth&amp;lt;/tt&amp;gt; is true, for old cards that don't provide depth information with enough resolution inside fullscreen or light shaders.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 position( vec3 viewDir, float depth )&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Reconstruct eye space position from the view direction and the depth read from the depth buffer&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 position( vec3 viewDir, vec3 depthColor )&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Reconstruct eye space position from the view direction and the depth encoded in a color read from the depth buffer&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;vec3 position( vec3 viewDir, vec2 coords, sampler2D depth_tex )&amp;lt;/tt&amp;gt;&lt;br /&gt;
:Reconstruct eye space position from the view direction and the depth buffer (real depth or color, according to the value of &amp;lt;tt&amp;gt;/sim/rendering/use-color-for_depth&amp;lt;/tt&amp;gt;) at a given fragment on screen, given by &amp;lt;tt&amp;gt;coords&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Usage ====&lt;br /&gt;
&lt;br /&gt;
For material shaders, it is necessary to provide both &amp;lt;tt&amp;gt;gbuffer-functions.frag&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;gbuffer-encode.frag&amp;lt;/tt&amp;gt; in the effect file, like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;program&amp;gt;&lt;br /&gt;
		&amp;lt;vertex-shader&amp;gt;Shaders/ubershader.vert&amp;lt;/vertex-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/ubershader-gbuffer.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/gbuffer-functions.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/gbuffer-encode.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
	&amp;lt;/program&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For fullscreen passes shaders, only &amp;lt;tt&amp;gt;gbuffer-functions.frag&amp;lt;/tt&amp;gt; should be provided, like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;program&amp;gt;&lt;br /&gt;
		&amp;lt;vertex-shader&amp;gt;Shaders/sunlight.vert&amp;lt;/vertex-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/sunlight.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
		&amp;lt;fragment-shader&amp;gt;Shaders/gbuffer-functions.frag&amp;lt;/fragment-shader&amp;gt;&lt;br /&gt;
	&amp;lt;/program&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the main function of the shader, the functions referenced need to be declared first. With no #include files, the whole function prototype needs to be typed :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void encode_gbuffer(vec3 normal, vec3 color, int mId, float specular, float shininess, float emission, float depth);&lt;br /&gt;
&lt;br /&gt;
main() {&lt;br /&gt;
    vec3 normal;&lt;br /&gt;
    vec3 color;&lt;br /&gt;
    int mId;&lt;br /&gt;
    float specular;&lt;br /&gt;
    float shininess;&lt;br /&gt;
    float emission;&lt;br /&gt;
    float depth;&lt;br /&gt;
&lt;br /&gt;
    // Do shader computations&lt;br /&gt;
&lt;br /&gt;
    encode_gbuffer(normal, color, mId, specular, shininess, emission, depth);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Geometry Stage ===&lt;br /&gt;
The Geometry Stage is there to fill the G-buffer. '''Shading doesn't occur at this stage, so light or fog computation should not be part of the shader'''. The required operation in the Fragment Shader is to fill every individual buffer with sensible value :&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&lt;br /&gt;
|depth (gl_FragDepth)||GL_DEPTH_COMPONENT32||colspan=&amp;quot;4&amp;quot;|Fragment depth&lt;br /&gt;
|-&lt;br /&gt;
|gl_FragData[0]||GL_RG16||colspan=&amp;quot;2&amp;quot;|normal.x * 0.5 + 0.5||colspan=&amp;quot;2&amp;quot;|normal.y * 0.5 + 0.5&lt;br /&gt;
|-&lt;br /&gt;
|gl_FragData[1]||GL_RGBA8||diffuse.r||diffuse.g||diffuse.b||material id * 1/255.0&lt;br /&gt;
|-&lt;br /&gt;
|gl_FragData[2]||GL_RGBA8||specular.l||specular.s||emission.l||pixel valid if != 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is the default layout expected by the sunlight shader. material Id can be used to detect a different layout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
#Depth buffer, modified with gl_FragDepth, will record the distance between the fragment and the camera. Default behavior is to avoid to touch it, living the GPU rasterizer doing sensible things by interpolating vertex gl_Position from the Vertex or the Geometry Shader. If altering the computed depth is required, like in the Urban shader, the value of gl_FragDepth should be set.&lt;br /&gt;
#Normal buffer, modified with gl_FragData[0].xyz, will record the normal of the fragment in eye coordinates. gl_FragData[0].w is reserved for future use. The interpolated normal is usually simply stored but bump mapping or relief mapping affecting the normal can be computed here.&lt;br /&gt;
#Diffuse color buffer, modified with gl_FragData[1].rgb, will hold the unshaded color of the fragment, usually modulating the material diffuse+ambient color with the texture map. Diffuse color from environment mapping should also go here.&lt;br /&gt;
#Specular color, modified with gl_FragData[2].rgb, and specular shininess in gl_FragData[2].a, will retain the specular color of the fragment.&lt;br /&gt;
#Emission color, modified with gl_FragData[3].rgb&lt;br /&gt;
In anyway, don't use gl_FragColor as it is incompatible with MRT (Multi Render Target) and would affect the four last buffers with the same value. In that case, the model will glow (emission buffer initialized) and parts will disappear at certain view angles because normals are not initialized properly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:red;font-size:1.5em;font-weight:bold&amp;quot;&amp;gt;This layout is going to change in the official repository when the merge will be done. The goal of this change is to fill more useful data into less texture memory and get rid of a stupid IP issue on float textures&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Additional light pass ===&lt;br /&gt;
There would be a single shader for each light type used. The plan is to create lights like animations in the model XML file. The light shader will retrieve scene geometry by combining screen space position converted in view space ray by the inverse of the projection matrix (an helper function should be provided), and the fragment depth at that screen position read from the depth buffer. With the help of the fragment normal, the diffuse and specular color and the properties of the light the shader implements, it will be possible to add to the lighting buffer the contribution of the light rendered.&lt;br /&gt;
&lt;br /&gt;
=== Fog Pass ===&lt;br /&gt;
Using the fragment depth, it will be possible to compute any fog distribution. For the moment, the simple fog equation is implemented.&lt;br /&gt;
&lt;br /&gt;
=== Bloom Pass ===&lt;br /&gt;
This is a two-pass effect that blurs the lighting buffer in a small texture. This texture is then added to the lighting buffer at the display stage.&lt;br /&gt;
&lt;br /&gt;
=== Required Effects ===&lt;br /&gt;
Several pass are implemented using the effect system. For this purpose, some effects are referenced in the core code using reserved names. these effects are:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Kind&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/ssao&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on a full screen quad&lt;br /&gt;
|Compute ambient occlusion from the normal buffer and the depth buffer&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/ambient&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on a full screen quad&lt;br /&gt;
|Copies the diffuse color buffer multiplied by the ambient light to the lighting buffer. Ambient Occlusion can also affect ambient light.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/light-spot&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on real geometry of the light volume&lt;br /&gt;
|Computes the light contribution of a spot light defined in a &amp;lt;tt&amp;gt;light&amp;lt;/tt&amp;gt; animation having a &amp;lt;tt&amp;gt;light-type&amp;lt;/tt&amp;gt; of '''&amp;lt;tt&amp;gt;spot&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/fog&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on a full screen quad&lt;br /&gt;
|Computes the fog from the G-buffer and the lighting parameters&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;Effects/display&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Works on a full screen quad&lt;br /&gt;
|Renders the composite final image from the G-buffer and the lighting buffer&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Guidelines for modelers ==&lt;br /&gt;
&lt;br /&gt;
=== Porting aircraft ===&lt;br /&gt;
* Rembrandt computes shadows =&amp;gt; no more fake shadows in the model&lt;br /&gt;
* Rembrandt computes ambient occlusion =&amp;gt; no ambient occlusion baked into textures&lt;br /&gt;
* Rembrandt has light =&amp;gt; static lightmap are not needed, emissive color to see models at night is not needed and would interfere&lt;br /&gt;
* Rembrandt has glow =&amp;gt; incorrectly used emissive colors may blur displays and make some text unreadable. Light size may have to be adjusted&lt;br /&gt;
* Rembrandt has strict needs with shaders =&amp;gt; shaders need to be adjusted to comply with the new framework otherwise the view will be plain wrong&lt;br /&gt;
* Rembrandt can't do transparent surfaces =&amp;gt; transparent surface need to be properly registered to render them with the classical path&lt;br /&gt;
&lt;br /&gt;
=== Registering all translucent surfaces ===&lt;br /&gt;
&lt;br /&gt;
Every model is, by default, rendered using the &amp;lt;tt&amp;gt;Effects/model-default&amp;lt;/tt&amp;gt; effect. This effect initialize the G-buffer, ignoring transparent surfaces, by doing alpha testing and rendering all the geometry in the default bin. It is not possible to redirect rendering to transparent bins when the associated texture has alpha channel because most models use a single texture atlas and even opaque parts are rendered with texture with alpha channel.&lt;br /&gt;
&lt;br /&gt;
If a model needs to have transparent or translucent surfaces, these surface objects need to be assigned a different effect that sets explicitly the render bin to &amp;quot;DepthSortedBin&amp;quot;, or sets the rendering hint to &amp;quot;transparent&amp;quot;. This tells the renderer to render this object using forward rendering, so lighting and fog need to be enabled, and if a shader program is used, they should be computed in the classical way. The &amp;lt;tt&amp;gt;Effects/model-transparent&amp;lt;/tt&amp;gt; can be used to register simple transparent/translucent surfaces. You assign this effect to an object (or multiple objects) like:&lt;br /&gt;
 &amp;lt;effect&amp;gt;&lt;br /&gt;
  &amp;lt;inherits-from&amp;gt;Effects/model-transparent&amp;lt;/inherits-from&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;TheObject&amp;lt;/object-name&amp;gt;&lt;br /&gt;
 &amp;lt;/effect&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If opaque surface need to have special effect, for example to apply bump mapping, this effect should use the &amp;quot;RenderBin&amp;quot; bin, or the rendering hint set to &amp;quot;opaque&amp;quot;, and the G-buffer needs to be initialized correctly in the Geometry stage.&lt;br /&gt;
&lt;br /&gt;
=== Adding lights to a model ===&lt;br /&gt;
&lt;br /&gt;
There are two things to consider: the appearance of the light source and the illuminated area. For the appearance of the light source (what you see when you look at the bulb), you need a model with an emissive material that will produce the glow effect and that is visible at night.&lt;br /&gt;
&lt;br /&gt;
For the effect of the source on its environment (the lit area), we must have in the 3D model (the .ac file) a volume that includes the effect (Light Volume). It can be a large cone for spotlights or a sphere for point light. It's important that the light volume is closed, convex and it's normals are oriented outward.&lt;br /&gt;
&lt;br /&gt;
The light volume must be part of the geometry of the model and be referenced in the animation file. No need to add a color or an effect to this volume. Light calculation is only done on the fragments covered by the light volume, but has no influence on the color or the attenuation of the light.&lt;br /&gt;
&lt;br /&gt;
All available animations are possible on the light volume, except '''material''' and '''texture'''. It is not possible to change color of lights for the moment, except switching to another animation. Axis and position are in object space and are transformed by the subsequent animations.&lt;br /&gt;
&lt;br /&gt;
==== Spotlights ====&lt;br /&gt;
{|cellpadding=10|&lt;br /&gt;
|valign=top|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;animation&amp;gt;&lt;br /&gt;
   &amp;lt;type&amp;gt;light&amp;lt;/type&amp;gt;&lt;br /&gt;
   &amp;lt;light-type&amp;gt;spot&amp;lt;/light-type&amp;gt;&lt;br /&gt;
   &amp;lt;name&amp;gt;LightSrcRight&amp;lt;/name&amp;gt;&lt;br /&gt;
   &amp;lt;object-name&amp;gt;LightRight&amp;lt;/object-name&amp;gt;&lt;br /&gt;
   &amp;lt;nopreview/&amp;gt;&lt;br /&gt;
   &amp;lt;position&amp;gt;&lt;br /&gt;
     &amp;lt;x&amp;gt;0.169&amp;lt;/x&amp;gt;&lt;br /&gt;
     &amp;lt;y&amp;gt;0.570&amp;lt;/y&amp;gt;&lt;br /&gt;
     &amp;lt;z&amp;gt;0.713&amp;lt;/z&amp;gt;&lt;br /&gt;
   &amp;lt;/position&amp;gt;&lt;br /&gt;
   &amp;lt;direction&amp;gt;&lt;br /&gt;
     &amp;lt;x&amp;gt;-0.9988&amp;lt;/x&amp;gt;&lt;br /&gt;
     &amp;lt;y&amp;gt;0.0349&amp;lt;/y&amp;gt;&lt;br /&gt;
     &amp;lt;z&amp;gt;-0.0349&amp;lt;/z&amp;gt;&lt;br /&gt;
   &amp;lt;/direction&amp;gt;&lt;br /&gt;
   &amp;lt;ambient&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.03&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.03&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.03&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/ambient&amp;gt;&lt;br /&gt;
   &amp;lt;diffuse&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.7&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.7&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.6&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/diffuse&amp;gt;&lt;br /&gt;
   &amp;lt;specular&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.7&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.7&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.7&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/specular&amp;gt;&lt;br /&gt;
   &amp;lt;dim-factor&amp;gt;&lt;br /&gt;
      &amp;lt;property&amp;gt;dimming/property&amp;lt;/property&amp;gt;&lt;br /&gt;
      &amp;lt;!-- optional begin --&amp;gt;&lt;br /&gt;
      &amp;lt;expression /&amp;gt;&lt;br /&gt;
      &amp;lt;interpolation /&amp;gt;&lt;br /&gt;
      &amp;lt;factor&amp;gt;1&amp;lt;/factor&amp;gt;&lt;br /&gt;
      &amp;lt;offset&amp;gt;0&amp;lt;/offset&amp;gt;&lt;br /&gt;
      &amp;lt;min&amp;gt;0&amp;lt;/min&amp;gt;&lt;br /&gt;
      &amp;lt;max&amp;gt;1&amp;lt;/max&amp;gt;&lt;br /&gt;
      &amp;lt;!-- optional end --&amp;gt;&lt;br /&gt;
   &amp;lt;/dim-factor&amp;gt;&lt;br /&gt;
   &amp;lt;attenuation&amp;gt;&lt;br /&gt;
     &amp;lt;c&amp;gt;1.0&amp;lt;/c&amp;gt;&lt;br /&gt;
     &amp;lt;l&amp;gt;0.002&amp;lt;/l&amp;gt;&lt;br /&gt;
     &amp;lt;q&amp;gt;0.00005&amp;lt;/q&amp;gt;&lt;br /&gt;
   &amp;lt;/attenuation&amp;gt;&lt;br /&gt;
   &amp;lt;exponent&amp;gt;30.0&amp;lt;/exponent&amp;gt;&lt;br /&gt;
   &amp;lt;cutoff&amp;gt;39&amp;lt;/cutoff&amp;gt;&lt;br /&gt;
   &amp;lt;near-m&amp;gt;3.5&amp;lt;/near-m&amp;gt;&lt;br /&gt;
   &amp;lt;far-m&amp;gt;39&amp;lt;/far-m&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|valign=top|&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Install the &amp;lt;tt&amp;gt;'''light'''&amp;lt;/tt&amp;gt; animation&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;light-type&amp;lt;/tt&amp;gt;&lt;br /&gt;
|This is a &amp;lt;tt&amp;gt;'''spot'''&amp;lt;/tt&amp;gt; light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Name given to this animation&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;object-name&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Name of the light volume in the 3d model (typically a cone with an apex at &amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt;, along &amp;lt;tt&amp;gt;direction&amp;lt;/tt&amp;gt; axis if &amp;lt;tt&amp;gt;cutoff&amp;lt;/tt&amp;gt; is lesser than 90 degrees, or a sphere centered at &amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt; if &amp;lt;tt&amp;gt;cutoff&amp;lt;/tt&amp;gt; is greater than 90 degrees )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;nopreview&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Hide light volume in fgrun 3d preview&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In object space, position of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;direction&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In object space, direction to the center of the spot&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;ambient&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Ambient color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;diffuse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Diffuse color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;specular&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Specular color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;dim-factor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Group of parameters to control a factor that is applied to ambient, diffuse and specular at the same time&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;attenuation&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Three element vector. &amp;lt;c&amp;gt; element is the constant factor, &amp;lt;l&amp;gt; element is the linear factor and &amp;lt;q&amp;gt; element is the quadratic factor.&amp;lt;br /&amp;gt;&lt;br /&gt;
Attenuation of color at distance d is [[File:Spotlight_attenuation.png]]&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;exponent&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Attenuation is multiplied by &amp;lt;tt&amp;gt;pow( dot( lightDir, &amp;lt;direction&amp;gt; ), &amp;lt;exponent&amp;gt; )&amp;lt;/tt&amp;gt;, lightDir being vector from light position to point, in camera space.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;cutoff&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Point is lit by this source if &amp;lt;tt&amp;gt;dot( lightDir, &amp;lt;direction&amp;gt; ) &amp;gt; &amp;lt;cutoff&amp;gt;&amp;lt;/tt&amp;gt; , lightDir being vector from light position to point, in camera space.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;near-m&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Minimum distance of influence, from position, in meters&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;far-m&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Maximum distance of influence, from position, in meters&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Point lights ====&lt;br /&gt;
{|cellpadding=10|&lt;br /&gt;
|valign=top|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;animation&amp;gt;&lt;br /&gt;
   &amp;lt;type&amp;gt;light&amp;lt;/type&amp;gt;&lt;br /&gt;
   &amp;lt;light-type&amp;gt;point&amp;lt;/light-type&amp;gt;&lt;br /&gt;
   &amp;lt;name&amp;gt;LightSrcRight&amp;lt;/name&amp;gt;&lt;br /&gt;
   &amp;lt;object-name&amp;gt;LightRight&amp;lt;/object-name&amp;gt;&lt;br /&gt;
   &amp;lt;nopreview/&amp;gt;&lt;br /&gt;
   &amp;lt;position&amp;gt;&lt;br /&gt;
     &amp;lt;x&amp;gt;0.169&amp;lt;/x&amp;gt;&lt;br /&gt;
     &amp;lt;y&amp;gt;0.570&amp;lt;/y&amp;gt;&lt;br /&gt;
     &amp;lt;z&amp;gt;0.713&amp;lt;/z&amp;gt;&lt;br /&gt;
   &amp;lt;/position&amp;gt;&lt;br /&gt;
   &amp;lt;ambient&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.03&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.03&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.03&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/ambient&amp;gt;&lt;br /&gt;
   &amp;lt;diffuse&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.7&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.7&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.6&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/diffuse&amp;gt;&lt;br /&gt;
   &amp;lt;specular&amp;gt;&lt;br /&gt;
     &amp;lt;r&amp;gt;0.7&amp;lt;/r&amp;gt;&lt;br /&gt;
     &amp;lt;g&amp;gt;0.7&amp;lt;/g&amp;gt;&lt;br /&gt;
     &amp;lt;b&amp;gt;0.7&amp;lt;/b&amp;gt;&lt;br /&gt;
     &amp;lt;a&amp;gt;1.0&amp;lt;/a&amp;gt;&lt;br /&gt;
   &amp;lt;/specular&amp;gt;&lt;br /&gt;
   &amp;lt;dim-factor&amp;gt;&lt;br /&gt;
      &amp;lt;property&amp;gt;dimming/property&amp;lt;/property&amp;gt;&lt;br /&gt;
      &amp;lt;!-- optional begin --&amp;gt;&lt;br /&gt;
      &amp;lt;expression /&amp;gt;&lt;br /&gt;
      &amp;lt;interpolation /&amp;gt;&lt;br /&gt;
      &amp;lt;factor&amp;gt;1&amp;lt;/factor&amp;gt;&lt;br /&gt;
      &amp;lt;offset&amp;gt;0&amp;lt;/offset&amp;gt;&lt;br /&gt;
      &amp;lt;min&amp;gt;0&amp;lt;/min&amp;gt;&lt;br /&gt;
      &amp;lt;max&amp;gt;1&amp;lt;/max&amp;gt;&lt;br /&gt;
      &amp;lt;!-- optional end --&amp;gt;&lt;br /&gt;
   &amp;lt;/dim-factor&amp;gt;&lt;br /&gt;
   &amp;lt;attenuation&amp;gt;&lt;br /&gt;
     &amp;lt;c&amp;gt;1.0&amp;lt;/c&amp;gt;&lt;br /&gt;
     &amp;lt;l&amp;gt;0.002&amp;lt;/l&amp;gt;&lt;br /&gt;
     &amp;lt;q&amp;gt;0.00005&amp;lt;/q&amp;gt;&lt;br /&gt;
   &amp;lt;/attenuation&amp;gt;&lt;br /&gt;
   &amp;lt;near-m&amp;gt;3.5&amp;lt;/near-m&amp;gt;&lt;br /&gt;
   &amp;lt;far-m&amp;gt;39&amp;lt;/far-m&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|valign=top|&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Install the &amp;lt;tt&amp;gt;'''light'''&amp;lt;/tt&amp;gt; animation&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;light-type&amp;lt;/tt&amp;gt;&lt;br /&gt;
|This is a &amp;lt;tt&amp;gt;'''point'''&amp;lt;/tt&amp;gt; light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Name given to this animation&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;object-name&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Name of the light volume in the 3d model (typically a sphere centered on &amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt;, with a radius of &amp;lt;tt&amp;gt;far-m&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;nopreview&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Hide light volume in fgrun 3d preview&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;position&amp;lt;/tt&amp;gt;&lt;br /&gt;
|In object space, position of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;ambient&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Ambient color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;diffuse&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Diffuse color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;specular&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Specular color of the light&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;dim-factor&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Group of parameters to control a factor that is applied to ambient, diffuse and specular at the same time&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;attenuation&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Three element vector. &amp;lt;c&amp;gt; element is the constant factor, &amp;lt;l&amp;gt; element is the linear factor and &amp;lt;q&amp;gt; element is the quadratic factor.&amp;lt;br /&amp;gt;&lt;br /&gt;
Attenuation of color at distance d is [[File:Spotlight_attenuation.png]]&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;near-m&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Minimum distance of influence, from position, in meters&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;far-m&amp;lt;/tt&amp;gt;&lt;br /&gt;
|Maximum distance of influence, from position, in meters&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initial TODO List ==&lt;br /&gt;
*Fix shadow rendering when using multi threading in OSG&lt;br /&gt;
*&amp;lt;del&amp;gt;Implement Cascaded Shadow Map (need to be optimized - frustum calculation and night&amp;lt;/del&amp;gt;)&lt;br /&gt;
*Honor &amp;lt;noshadow&amp;gt; animation directive&lt;br /&gt;
*See what happens with glow in fog&lt;br /&gt;
*Test multi-screen&lt;br /&gt;
*Restore splashscreen&lt;br /&gt;
*&amp;lt;del&amp;gt;Draw transparent objects with forward rendering (may need to capture the transparent bin from the geometry stage and move it in the display stage)&amp;lt;/del&amp;gt; (OK - needs model contribution)&lt;br /&gt;
*&amp;lt;del&amp;gt;Add spotlights as animations (nearly finished)&amp;lt;/del&amp;gt;&lt;br /&gt;
*&amp;lt;del&amp;gt;find a solution for ambient and emissive color of material (may need an additional buffer)&amp;lt;/del&amp;gt;&lt;br /&gt;
*implement strength of glow (in the emissive buffer alpha channel)&lt;br /&gt;
**provide levels 0 to 5 - we are currently at level 5&lt;br /&gt;
**level 0 should be ok for MFDs that are currenly unreadable because blurred&lt;br /&gt;
*Provide a shader for transparent objects that could render to the emissive buffer too (using MRT)&lt;br /&gt;
*&amp;lt;del&amp;gt;Use stencil buffer to limit light range&amp;lt;/del&amp;gt;(no - done in light shader)&lt;br /&gt;
**needed for cockpit light to implement fake shadows and avoid lighting the runway from the cabin through the airframe&lt;br /&gt;
*Use effect system instead of hard-coded shaders (mostly done)&lt;br /&gt;
*Convert existing shaders to deferred rendering&lt;br /&gt;
**Modify shadows to allow multiple casters (limited list)&lt;br /&gt;
**Implement a priority list of light sources, based on priority and distance from the viewer&lt;br /&gt;
**&amp;lt;del&amp;gt;Add new animation to link a light source to a model&amp;lt;/del&amp;gt; (need to provide point light animation duplicating spot light)&lt;br /&gt;
*Tidy up the architecture&lt;br /&gt;
*Restore depth partitioning using depth ranges&lt;br /&gt;
*Restore stereo and other options currently available in CameraGroup&lt;br /&gt;
*Implement quality vs performance user control&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Merge in next&amp;quot; TODO List ==&lt;br /&gt;
*Design and implement a configurable pipeline&lt;br /&gt;
*Implement lightfield shader&lt;br /&gt;
&lt;br /&gt;
== Gallery ==&lt;br /&gt;
{{#ev:youtube|PXHhtQb5yzc}} {{#ev:youtube|peEzEapavkg}} {{#ev:youtube|RIetPh8iJXk}} {{#ev:youtube|oaNFrxgQY1c}} {{#ev:youtube|8xGzy12hlis}} {{#ev:youtube|ZyuHBlm3xXU}} {{#ev:youtube|RgH9GZRukOI}} {{#ev:youtube|UQvbHnBkpaM}} {{#ev:youtube|v02phoOqWHE}}{{#ev:youtube|dlSo4sBa7Nk}}&lt;br /&gt;
&lt;br /&gt;
== Model modification log ==&lt;br /&gt;
;c172p&lt;br /&gt;
:Add an effect to the propeller disk (object Propeller.Fast) to put it in a transparent bin&lt;br /&gt;
;Models/Airport/apt-light.xml &amp;amp; Models/Airport/apt-light-ba.ac&lt;br /&gt;
:Add a spot light animation and a light volume&lt;br /&gt;
;Scenery/Objects/w130n30/w123n37/942050.stg&lt;br /&gt;
:Change KSFO_light.xml to apt-light.xml&lt;br /&gt;
;Aircraft/followme/Models/followme.xml &amp;amp; .ac&lt;br /&gt;
:Add light volumes and spotlight animations for headlights&lt;br /&gt;
&lt;br /&gt;
== Effect/Shader modification log ==&lt;br /&gt;
;Default shaders&lt;br /&gt;
:render to the G-buffer&lt;br /&gt;
;Urban effect&lt;br /&gt;
:render to the G-buffer&lt;br /&gt;
;Spot light effect&lt;br /&gt;
:new effect to render spot lights from the animation file&lt;br /&gt;
;model-transparent&lt;br /&gt;
:new effect to classify transparent surfaces (those that are not bound to the glass shader or other shader that use explicitly the transparent bin )&lt;br /&gt;
&lt;br /&gt;
{{Appendix|all|&lt;br /&gt;
* {{cite web |url=http://http.download.nvidia.com/developer/presentations/2004/6800_Leagues/6800_Leagues_Deferred_Shading.pdf |title=Deferred Shading |author=Shawn Hargreaves and Mark Harris }}&lt;br /&gt;
* {{cite web |url=http://bat710.univ-lyon1.fr/~jciehl/Public/educ/GAMA/2007/Deferred_Shading_Tutorial_SBGAMES2005.pdf |title=Deferred Shading Tutorial |author=Fabio Policarpo and Francisco Fonseca }}&lt;br /&gt;
* {{cite web |url=http://www.guerrilla-games.com/publications/dr_kz2_rsx_dev07.pdf |title=Deferred Rendering in Killzone 2 |author=Michal Valient |month=July |year=2007 }}&lt;br /&gt;
* {{cite web |url=http://www.anandtech.com/show/5011/nvidiaea-posts-battlefield-3-graphics-tech-talk |title=Battlefield 3 Graphics Tech Talk |author=Johan Andersson |month=October |year=2011 }}&lt;br /&gt;
* {{cite web |url=http://www.disney.co.uk/cms_res/blackrockstudio/pdf/Rendering_Techniques_in_SplitSecond.pdf |title=Rendering Techniques in Split/Second |author=Jeremy Moore and David Jefferies |year=2009 }}&lt;br /&gt;
* {{cite web |url=http://www.crytek.com/sites/default/files/A_bit_more_deferred_-_CryEngine3.ppt |title=&amp;quot;A bit more Deferred&amp;quot; - CryEngine 3 (PPT) |author=Martin Mittring }}&lt;br /&gt;
* {{cite web |url=http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter09.html |title=Deferred Shading in S.T.A.L.K.E.R. |author=Oles Shishkovtsov }}&lt;br /&gt;
* {{cite web |url=http://http.developer.nvidia.com/GPUGems3/gpugems3_ch19.html |title=Deferred Shading in Tabula Rasa |author=Rusty Koonce }}&lt;br /&gt;
* {{cite web |url=http://aras-p.info/texts/CompactNormalStorage.html |title=Compact Normal Storage for small g-buffers |author=Aras Pranckevičius |date=4 August 2009 |accessdate=12 April 2012 }}&lt;br /&gt;
* {{cite web |url=http://the-witness.net/news/2010/03/graphics-tech-shadow-maps-part-1/ |title=Graphics Tech: Shadow Maps (part 1) |author=Jonathan Blow |date=3 March 2010 |accessdate=13 April 2012 }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Shader development]]&lt;br /&gt;
[[Category:Core development projects]]&lt;/div&gt;</summary>
		<author><name>Mcginnly</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Design_an_autopilot&amp;diff=49846</id>
		<title>Howto:Design an autopilot</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Design_an_autopilot&amp;diff=49846"/>
		<updated>2012-05-13T23:29:55Z</updated>

		<summary type="html">&lt;p&gt;Mcginnly: hundert &amp;gt; hundred - aglicising&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This [[:Category:Howto|howto]] will guide you through the process of designing a stable and fully functional [[autopilot]] in [[FlightGear]]. We won't cover every single aspect, because there are hundreds of [[aircraft]] out there, with dozens of different autopilot configurations. However, after reading this howto, you should be able to be creative and create unexisting configurations.&lt;br /&gt;
&lt;br /&gt;
For a technical reference of the used elements, check [[Autopilot Configuration Reference]].&lt;br /&gt;
&lt;br /&gt;
== Pre-design ==&lt;br /&gt;
Why not make things slightly easier, before we start working on the autopilot? Since we will be updating the autopilot hundreds of times, making tiny adjustments each time, we don't want to reload FlightGear every time. Therefore, we assign an &amp;quot;reload autopilot configuration&amp;quot; action to a key on our keyboard. We've chosen Shift-F5, but it could be any key. Add the code to your &amp;lt;tt&amp;gt;[[$FG ROOT]]/keyboard.xml&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;key n=&amp;quot;261&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;F5&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;repeatable type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/repeatable&amp;gt;&lt;br /&gt;
  &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
   &amp;lt;desc&amp;gt;Reload autopilot configuration&amp;lt;/desc&amp;gt;&lt;br /&gt;
   &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     fgcommand('reinit', props.Node.new({ subsystem: &amp;quot;xml-autopilot&amp;quot; }));&lt;br /&gt;
     print(&amp;quot;xml-autopilot reinitialized!&amp;quot;);&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
 &amp;lt;/key&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating the autopilot configuration file ==&lt;br /&gt;
Create an autopilot.xml file with the following content, somewhere inside your aircraft's root (eg. &amp;lt;tt&amp;gt;Aircraft/747-400/Systems/autopilot.xml&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A first controller: wing leveler ==&lt;br /&gt;
Let's start with a simple wing leveler that keeps your bank angle at zero (or any arbitrary value later). This could be a PID controller with the input from your current roll and a reference of zero. Output should go to your aileron-cmd. Start with:&lt;br /&gt;
* '''Kp:'''   0.00&lt;br /&gt;
* '''Ti:''' 100.00&lt;br /&gt;
* '''Td:'''   0.00&lt;br /&gt;
&lt;br /&gt;
Be sure to add an &amp;lt;enable&amp;gt; element to easily enable/disable your controller if it gets unstable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;pid-controller&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Heading hold&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/locks/heading&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;value&amp;gt;wing-leveler&amp;lt;/value&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/orientation/roll-deg&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;0&amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/controls/flight/aileron&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;Kp&amp;gt;0.00&amp;lt;/Kp&amp;gt;&lt;br /&gt;
   &amp;lt;Ti&amp;gt;100.0&amp;lt;/Ti&amp;gt;&lt;br /&gt;
   &amp;lt;Td&amp;gt;0.0&amp;lt;/Td&amp;gt;&lt;br /&gt;
   &amp;lt;u_min&amp;gt;-1.0&amp;lt;/u_min&amp;gt;&lt;br /&gt;
   &amp;lt;u_max&amp;gt;1.0&amp;lt;/u_max&amp;gt;&lt;br /&gt;
  &amp;lt;/config&amp;gt;&lt;br /&gt;
 &amp;lt;/pid-controller&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since this is our first controller, we will give a short explenation of each part.&lt;br /&gt;
&lt;br /&gt;
* '''Name:''' is only used for debugging.&lt;br /&gt;
* '''Debug:''' &lt;br /&gt;
* '''Enable:''' when the condition is true, the controller will be activated. In this case that will be when &amp;lt;tt&amp;gt;/autopilot/locks/heading=wing-leveler&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* '''Input:''' is the property that will be monitored by the controller. As our aim is to have a roll of zero degree, our input property is our roll orientation. &lt;br /&gt;
* '''Reference:''' most of the time this is a property, like input, but for this one we'll use a static value. The controller will try to get the value of the input to this reference-value.&lt;br /&gt;
* '''Output:''' the controller controls flight surfaces, in order to get the input value to the reference one.&lt;br /&gt;
* '''Config:''' thit is the tricky part. All these settings affect the behaviour (response time, surface deflection etc.) of the controller.&lt;br /&gt;
** '''u_min:''' the minimum output.&lt;br /&gt;
** '''u_max:''' the maximum output.&lt;br /&gt;
&lt;br /&gt;
To get an idea of the Kp-value, you need to do a simple calclulation. The PID controller computes &amp;quot;reference - input&amp;quot;. If you want wings leveled (zero roll) and your current bank angle is, say 30°, the result of &amp;quot;reference - input&amp;quot; is -30. If you think you need full aileron deflection to get from 30 degrees bank to zero in a reasonable time, you need a factor of 1/30=0.033, because aileron-cmd is in the range of -1 to +1. This is the approximate value for your Kp.&lt;br /&gt;
&lt;br /&gt;
Now enter your aircraft and climb to cruise altitude and cruise speed. Bank your aircraft, to 15°-20°. Enable your controller (in our example that is by setting &amp;lt;tt&amp;gt;/autopilot/locks/heading=wing-leveler&amp;lt;/tt&amp;gt;. [[Property Browser|Look here]] if you need help on setting properties.) and - nothing happens (because Kp is still zero). Set the value of Kp to 0.01 and hit Shift-F5 to reload your configuration and check what happens. Does the controller tries to level the wings or do things go worse? If the ailerons move in the wrong direction, you need to reverse the sign of Kp. &lt;br /&gt;
&lt;br /&gt;
Once you found the correct sign for Kp, slowly (in steps as little as 0.005) increase the value of Kp to get a fast response. Don't forget to reload the config with Shift-F5 after every edit of your file. There is one pitfall that can drive you crazy: the PID-controller computes delta-values for its correction and it starts with the current setting of your aileron when it is enabled or reloaded. If you have your aileron set to -0.2 when you hit Shift-F5, the controller will apply its corrections to a value of -0.2 which will most certainly fail! Make sure that you have your flight controls neutral (press 5) when (re-)enabling PID-controllers!&lt;br /&gt;
&lt;br /&gt;
You will achive good results by only setting Kp for a roll-computer as a wing-leveler. Slowly increase your Kp until it is just about to become unstable, than divide the current value of Kp by two and use that value. Try several configurations of your aircraft - slow flight, low altitude, fast cruise at higher altitudes. Fly turns with several bank angles, left and right. Whenever you enable your controller, it should level your wings within a few seconds and without bouncing back and forth.&lt;br /&gt;
&lt;br /&gt;
Once you are satisfied with Kp - and not before! - decrease the value for Ti by dividing by a value of 10 and check the response of your controller. When it tends to become unstable, multiply it's Ti by two. Now you should have a fast and stable wing-leveler.&lt;br /&gt;
&lt;br /&gt;
Finally (for the wing-leveler) you can turn it into a roll-hold by setting your target roll as a property for the reference. If you had &amp;lt;reference&amp;gt;0.0&amp;lt;/reference&amp;gt;, bind your reference to a property (&amp;lt;reference&amp;gt;autopilot/settings/target-roll-deg&amp;lt;/reference&amp;gt;) and your aircraft should roll to any value you set in target-roll-deg. The complete wing-leveler will look similar to the one below (though, the config values may vary and the reference might be replaced by a property).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;pid-controller&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Heading hold&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/locks/heading&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;value&amp;gt;wing-leveler&amp;lt;/value&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/orientation/roll-deg&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;0&amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/controls/flight/aileron&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;Kp&amp;gt;0.015&amp;lt;/Kp&amp;gt;&lt;br /&gt;
   &amp;lt;Ti&amp;gt;10.0&amp;lt;/Ti&amp;gt;&lt;br /&gt;
   &amp;lt;Td&amp;gt;0.0&amp;lt;/Td&amp;gt;&lt;br /&gt;
   &amp;lt;u_min&amp;gt;-1.0&amp;lt;/u_min&amp;gt;&lt;br /&gt;
   &amp;lt;u_max&amp;gt;1.0&amp;lt;/u_max&amp;gt;&lt;br /&gt;
  &amp;lt;/config&amp;gt;&lt;br /&gt;
 &amp;lt;/pid-controller&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the base for any lateral hold mode, so try to spend some time on it. It can take some hours if this is your first autopilot.&lt;br /&gt;
&lt;br /&gt;
== Pitch hold ==&lt;br /&gt;
So, let's move over to a pitch hold. Our goal is to have a controller that maintains an arbitrary pich. The only difference to the wing leveler is that you are only interested in elevator position changes, not absolute values. To put it in other words: increase elevator for more pitch, decrease for less pitch and maintain elevator position if the pitch is right. This calls for a pid-controller, because it only computes offset values. And you will end up with a relative small value for Kp to avoid rapid imediate movements and a relative small value for Ti to have a greater effect over time.&lt;br /&gt;
&lt;br /&gt;
Start again with a no-op pid-controller (Kp=0, Ti=100.000 and Td=0). Input is your current pitch (&amp;lt;tt&amp;gt;/orientation/pitch-deg&amp;lt;/tt&amp;gt;), reference is a target-pitch property (you wouldn't want a constant zero here, &amp;lt;tt&amp;gt;/autopilot/settings/target-pitch-deg&amp;lt;/tt&amp;gt;) and output goes to elevator-cmd (&amp;lt;tt&amp;gt;/autopilot/internal/elevator-cmd&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&lt;br /&gt;
Again increase you Kp slowly and check each step in FlightGear. I'd expect something like -0.025 resulting in an instanteanous full elevator deflection on a 40 degrees pitch offset. Do not try too large values; it results in instable behaviour very quickly. Now, decrease the value of Ti, probably down to 10 or so. The smaller it gets, the faster the elevator moves and the easier it is to get an unstable loop. Again it is very likely that you won't need Td to get a stable controller.&lt;br /&gt;
&lt;br /&gt;
== Simulating servos ==&lt;br /&gt;
Once you have this two axies running, you might want to think about simulating the slow movements of the servo or hydraulic motors that drive the control surfaces. You might have noticed, that the controls react rapidly when enabled which is unrealistic. In a [[Seneca]], the aileron servo takes 12 seconds to move from left to right. The elevator needs 26 seconds and the pitch trim takes 45 seconds for full travel.&lt;br /&gt;
&lt;br /&gt;
There is a filter to simulate that behaviour, it's the noise-spike filter. Here is a sample with 25 seconds transition time from -1 to +1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;SERVO-DRIVER:elevator&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;feedback-if-disabled&amp;gt;true&amp;lt;/feedback-if-disabled&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/locks/altitude&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;value&amp;gt;pitch-hold&amp;lt;/value&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/autopilot/internal/elevator-cmd&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;/controls/flight/elevator&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;noise-spike&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;max-rate-of-change&amp;gt;0.08&amp;lt;/max-rate-of-change&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The formula for max-rate-of-change is (max-out - min-out)/transition-time. In our example (1--1)/25=2/25=0.08. Try it out, disable your pitch-hold controller and enable the servo-driver. Set your some/internal/elevator-cmd property to +1 and see your elevator moving to fully up or down within 12.5 seconds. Now set your property to -1 and it will take 25 seconds for the elevator to move to the other direction. The feedback-if-disabled property is needed, if this stage is driven from a pid-controller. &lt;br /&gt;
&lt;br /&gt;
We said before that PID-controllers compute offsets to the curren value of it's output. If you disable the servo-driver from your A/P master switch, the value of your elevator is fed back to the internal value of the elevator-cmd so the pid-controller has a reasonable value to start from when it is enabled. Create servo drivers for elevator, aileron and the trim channels if you intend to use them. A good location for the internal driver properties is /autopilot/internal - but that is up to you.Now change your pitch and roll PID-controller so that they no longer directly drive the output properties but the internal properties. You might need to adjust the Kp and Ti values of the PID-controller because you introduced some lag with the driver. But you should end up with perfectly smooth operation of the two main channels. &lt;br /&gt;
&lt;br /&gt;
Spend some time optimizing these pitch and roll channels, they will be used by all other modes and '''have''' to be stable in any case!&lt;br /&gt;
&lt;br /&gt;
== A simple auto throttle ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;pid-controller&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Auto throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/locks/speed&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;value&amp;gt;speed-with-throttle&amp;lt;/value&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/instruments/airspeed-indicator/indicated-speed-kt&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/settings/target-speed-kt&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/internal/throttle-cmd&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;Kp&amp;gt;0.15&amp;lt;/Kp&amp;gt;&lt;br /&gt;
   &amp;lt;Ti&amp;gt;20.0&amp;lt;/Ti&amp;gt;&lt;br /&gt;
   &amp;lt;Td&amp;gt;0.00001&amp;lt;/Td&amp;gt;&lt;br /&gt;
   &amp;lt;u_min&amp;gt;0.0&amp;lt;/u_min&amp;gt;&lt;br /&gt;
   &amp;lt;u_max&amp;gt;1.0&amp;lt;/u_max&amp;gt;&lt;br /&gt;
  &amp;lt;/config&amp;gt;&lt;br /&gt;
 &amp;lt;/pid-controller&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And a filter, as our autopilot does not move the throttle levers up/down in split seconds (you can imagine how that would be potentially harmful to the flight crew). Depending on the number of engines of your aircraft, you might want to add more or delete some output properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;SERVO-DRIVER:throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;feedback-if-disabled&amp;gt;true&amp;lt;/feedback-if-disabled&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/locks/speed&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;value&amp;gt;speed-with-throttle&amp;lt;/value&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/autopilot/internal/throttle-cmd&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/controls/engines/engine[0]/throttle&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/controls/engines/engine[1]/throttle&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/controls/engines/engine[2]/throttle&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/controls/engines/engine[3]/throttle&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;noise-spike&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;max-rate-of-change&amp;gt;0.1&amp;lt;/max-rate-of-change&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vertical speed hold ==&lt;br /&gt;
Let's start with some thinking. For vertical-speed-hold, the controller has to compare your current rate-of-climb with your reference rate-of-climb. The ROC will be controlled by setting the pitch of the aircraft. We already have a pitch-hold controller, so we will set the target-pitch from our rate-of-climb controller. To not make our passengers barf when we enable our controller, it's important to set the target-pitch relative to our current pitch - which once again calls for a pid-controller (because of it's relative output). &lt;br /&gt;
&lt;br /&gt;
To get the current pitch to a property which will be modified by a pid-controller later, we will now create a controller which serves as a so called &amp;quot;sample-and-hold&amp;quot; element. It simply copies the input property value to the output property value until it is disabled. The same property, that disables the sample-and-hold controller will enable the pid-controller that computes the pitch for the rate-of climb.Here is a sample-and-hold controller implemented with a gain-filter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;AP:Pitch sample and hold&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;condition&amp;gt;&lt;br /&gt;
    &amp;lt;not&amp;gt;&lt;br /&gt;
     &amp;lt;property&amp;gt;/autopilot/locks/roc-lock&amp;lt;/property&amp;gt;&lt;br /&gt;
    &amp;lt;/not&amp;gt;&lt;br /&gt;
   &amp;lt;/condition&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;gain&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;gain&amp;gt;1.0&amp;lt;/gain&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/orientation/pitch-deg&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;/autopilot/internal/target-pitch-deg&amp;lt;/output&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You probably have to adjust the property names. Note the condition element in the &amp;lt;enable&amp;gt; section - it has the same syntax as in the well-known &amp;lt;animation&amp;gt; elements. As long as the roc-lock property is false, input is copied to output. When it becomes true, the output property is no longer written by this filter and the next step can use this value as a start. &lt;br /&gt;
&lt;br /&gt;
Right behind this filter, add a pid-controller using your current rate-of-climb as input and a target-rate-of-climb as reference. Enable this pid if your pitch sample-and-hold is not enabled (use the same condition, just remove the &amp;lt;not&amp;gt; elements). Your output goes to target-pitch-deg which should be the same property as the input of your pitch-hold controller. Use the same procedure to obtain the values for Kp and Ti. Kp will be small. The offset computes in feet per minute and 100fpm should result in a few degrees pitch change. Something like 0.01 or smaller will probably do. I'd expect Integrator time around 10-50. You should clamp the target-pitch to something less than +/- 90° - probably -10° and +20° or whatever is a reasonable value for your aircraft. It could look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;pid-controller&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Vertical speed pitch hold&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;condition&amp;gt;&lt;br /&gt;
    &amp;lt;property&amp;gt;/autopilot/locks/roc-lock&amp;lt;/property&amp;gt;&lt;br /&gt;
   &amp;lt;/condition&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/internal/vert-speed-fpm&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;/autopilot/settings/vertical-speed-fpm&amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/settings/target-pitch-deg&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;Kp&amp;gt;0.001&amp;lt;/Kp&amp;gt;&lt;br /&gt;
   &amp;lt;Ti&amp;gt;10.0&amp;lt;/Ti&amp;gt;&lt;br /&gt;
   &amp;lt;Td&amp;gt;0.0&amp;lt;/Td&amp;gt;&lt;br /&gt;
   &amp;lt;u_min&amp;gt;-10.0&amp;lt;/u_min&amp;gt;&lt;br /&gt;
   &amp;lt;u_max&amp;gt;10.0&amp;lt;/u_max&amp;gt;&lt;br /&gt;
  &amp;lt;/config&amp;gt;&lt;br /&gt;
 &amp;lt;/pid-controller&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logic-controlled properties ==&lt;br /&gt;
These two new elements should give you a rate-of-climb hold mode for your autopilot. If you are not yet confused which controllers should be enabled in what mode, you will be very soon as we will add even more elements. If you are in the need for some logic-controlled properties, the autopilot can do this, too - no need for [[nasal]] helpers! There is a &amp;lt;logic&amp;gt; element that does all the magic:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;logic&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Electrical Power&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;&lt;br /&gt;
   &amp;lt;greater-than&amp;gt;&lt;br /&gt;
    &amp;lt;property&amp;gt;systems/electrical/outputs/autopilot&amp;lt;/property&amp;gt;&lt;br /&gt;
    &amp;lt;value type=&amp;quot;double&amp;quot;&amp;gt;10.0&amp;lt;/value&amp;gt;&lt;br /&gt;
   &amp;lt;/greater-than&amp;gt;&lt;br /&gt;
  &amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;autopilot/has-power&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;autopilot/servicable&amp;lt;/output&amp;gt;&lt;br /&gt;
 &amp;lt;/logic&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This creates two boolean properties: has-power and serviceable, and sets them to true if the electrical system provides more than 10.0 volts. You can build complex logic tables to drive your analog stages of the autopilot.&lt;br /&gt;
&lt;br /&gt;
== Altitude hold ==&lt;br /&gt;
Now, that you have a ROC-hold mode, you most certainly want an altitude-hold with preselect. This will be a simple linear amplifier without any time dependencies. Again, you have to compare your current altitude with a reference value, but this time there will be no integrator involved. The bigger your offset from the reference altitude is, the bigger your rate of climb/descent should be. Let's assume, 1000ft offset should result in 500fpm ROC. The maximum rate of descent should be 1000fpm and the maximum rate of climb should be 2000fpm. Since there is no integrator involved, we use a simple gain filter to compute the rate of climb:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Target Rate of Climb Computer (ALT HOLD)&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/locks/altitude&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;value&amp;gt;altitude-hold&amp;lt;/value&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;gain&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;position/altitude-ft&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;autopilot/settings/target-altitude-ft&amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;gain&amp;gt;-0.5&amp;lt;/gain&amp;gt; &amp;lt;!-- 1000ft offset gives 500fpm roc --&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;autopilot/internal/target-roc-fpm&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;min&amp;gt;-1000&amp;lt;/min&amp;gt;&lt;br /&gt;
  &amp;lt;max&amp;gt;2000&amp;lt;/max&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If everything goes well, your chain of controllers for altitude hold looks something like this:&lt;br /&gt;
# '''Target Rate Of Climb Computer''' target-rate-of-climb = (reference-altitude - current-altitude) * 5 &lt;br /&gt;
# '''Target Pitch Computer''' computes target-pitch-deg as a function of current-roc and target-roc &lt;br /&gt;
# '''Elevator Command Computer''' computes elevator-deflection as a function of current pitch and target pitch &lt;br /&gt;
# '''Elevator Servo Driver''' makes smooth movements of the elevator &lt;br /&gt;
&lt;br /&gt;
This is nearly all for altitude-hold with altitude-preselect. You can add an altitude-sample-and-hold stage to add a &amp;quot;hold my current altitude&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
== Heading hold ==&lt;br /&gt;
For heading hold, you build a two stage system. The first is a comparator comparing your selected heading and the indicated heading. 1. Stage, compute heading offset. Note the period element at the bottom, it normalizes the output into the periodic -180 to +180 range&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Heading Offset Computer&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;gain&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;gain&amp;gt;1.0&amp;lt;/gain&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/autopilot/settings/heading-bug-deg&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;/orientation/heading-magnetic-deg&amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;/autopilot/internal/heading-offset-deg&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;period&amp;gt;&lt;br /&gt;
   &amp;lt;min&amp;gt;-180&amp;lt;/min&amp;gt;&lt;br /&gt;
   &amp;lt;max&amp;gt;180&amp;lt;/max&amp;gt;&lt;br /&gt;
  &amp;lt;/period&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second stage computes a bank angle from a heading offset. At least for smaller planes, a rule of thumb says &amp;quot;roll out at half the bank angle&amp;quot;. If you fly a right hand turn at a bank angle of, say, 20° and want to end at a heading of 270°, you start your roll out at 20°/2 = 10° before your target heading. So you start rolling out at 280°. We turn this rule around and say our bank angle is twice the heading error but not more that 30° This results in a simple gain filter. You might want to make the target roll computer switchable with an enable element, otherwise it will overwrite your target-roll-deg at all times.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Target Roll Computer&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/locks/heading&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;value&amp;gt;dg-heading-hold&amp;lt;/value&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;gain&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/autopilot/internal/heading-offset-deg&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;/autopilot/internal/target-roll-deg&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;gain&amp;gt;2.5&amp;lt;/gain&amp;gt;&lt;br /&gt;
  &amp;lt;min&amp;gt;-30.0&amp;lt;/min&amp;gt;&lt;br /&gt;
  &amp;lt;max&amp;gt;30.0&amp;lt;/max&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Most aircraft have pilot selectable bank-limits. You can implement these by editing the min and max options to something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
  &amp;lt;min&amp;gt;&lt;br /&gt;
   &amp;lt;property&amp;gt;/autopilot/settings/bank-limit&amp;lt;/property&amp;gt;&lt;br /&gt;
   &amp;lt;scale&amp;gt;-1.0&amp;lt;/scale&amp;gt;&lt;br /&gt;
  &amp;lt;/min&amp;gt;&lt;br /&gt;
  &amp;lt;max&amp;gt;/autopilot/settings/bank-limit&amp;lt;/max&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This filter feeds your wing leveler which is already done, but it requires a little edit in the &amp;lt;enable&amp;gt; and &amp;lt;reference&amp;gt; parts in order to obtain a pilot-selectable roll:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
  &amp;lt;enable&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/locks/heading&amp;lt;/prop&amp;gt;&lt;br /&gt;
   &amp;lt;value&amp;gt;dg-heading-hold&amp;lt;/value&amp;gt;&lt;br /&gt;
   &amp;lt;/condition&amp;gt;&lt;br /&gt;
  &amp;lt;/enable&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
  &amp;lt;reference&amp;gt;&lt;br /&gt;
   &amp;lt;prop&amp;gt;/autopilot/internal/target-roll-deg&amp;lt;/prop&amp;gt;&lt;br /&gt;
  &amp;lt;/reference&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also play with the min/max values to have a nice standard rate turn. The bank angle for the standard turn is a function of your true airspeed; you can build a controller calculating the correct bank angle and feed this value into min/max (which is a commen feature on airliners).&lt;br /&gt;
&lt;br /&gt;
Decreasing the gain of 2.5 should help, if your roll-rate is too slow. &lt;br /&gt;
&lt;br /&gt;
== NAV modes ==&lt;br /&gt;
In lateral nav mode, the primary goal of the autopilot is to intercept and maintain a certain ground track. This could be a VOR radial, a LOC course or back course or a GPS track. For most autopilots these are basically the same and it does not know anything about the source of the signal. Everything it knows is your current heading, your desired course and a course offset. And these are the properties, we need for our NAV hold mode.&lt;br /&gt;
&lt;br /&gt;
Now, how does the autopilot knows which direction to steer? Lets assume you want to intercept the radial 270 of some VOR. VOR radials &amp;quot;radiate&amp;quot; away from the station, so the 270 radial points away from the station with a heading of 270degrees (which is west).Lets further assume you are somewhere south-west of the VOR station - this is between radial 180 and 270 - and you fly on a heading of 250 (this will become important later).&lt;br /&gt;
&lt;br /&gt;
Now you have the most important facts at hand you need for navigation: &lt;br /&gt;
* Q1: Where am I? &lt;br /&gt;
* A1: South-west of the VOR &lt;br /&gt;
* Q2: Where would I want to be? &lt;br /&gt;
* A2: On radial 270 of the VOR &lt;br /&gt;
&lt;br /&gt;
As a rule of thumb, interception of radials should occour at angles of 30° to 45°. Intercepting at angles lower than 30° takes ages to get you there, intercepting at greater than 45° angles might result in a very steep turn to not overshoot the radial. We pick 45° because I like this value most.Our next question to answer is &lt;br /&gt;
* Q3: Which way should I fly to get where I want to be?&lt;br /&gt;
* A3: To intercept the course of 270° at a 45° angle, fly 270°+45°=315° &lt;br /&gt;
&lt;br /&gt;
Now that we know which way we should fly we can easily answer &lt;br /&gt;
* Q4: Which direction do I have to turn?&lt;br /&gt;
* A4: You are currently heading 250°. You want to fly heading 315°, so turn right by 65°. &lt;br /&gt;
&lt;br /&gt;
That's basically all the magic about navigation. Now let's implement this in the autopilot. One part is already done: Q4/A4 is your heading-hold stage, so it's probably best to move backwards from that stage.&lt;br /&gt;
&lt;br /&gt;
First, add a new, switchable input element to your heading offset computer. Just change this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Heading Offset Computer&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;gain&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;gain&amp;gt;1.0&amp;lt;/gain&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/autopilot/settings/heading-bug-deg&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;/orientation/heading-magnetic-deg&amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;/autopilot/internal/heading-offset-deg&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;period&amp;gt;&lt;br /&gt;
   &amp;lt;min&amp;gt;-180&amp;lt;/min&amp;gt;&lt;br /&gt;
   &amp;lt;max&amp;gt;180&amp;lt;/max&amp;gt;&lt;br /&gt;
  &amp;lt;/period&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to this (that is, adding the upper input part):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Heading Offset Computer&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;gain&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;gain&amp;gt;1.0&amp;lt;/gain&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;&lt;br /&gt;
   &amp;lt;condition&amp;gt;&lt;br /&gt;
    &amp;lt;equals&amp;gt;&lt;br /&gt;
     &amp;lt;property&amp;gt;/autopilot/locks/heading&amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;value&amp;gt;nav1-hold&amp;lt;/value&amp;gt;&lt;br /&gt;
    &amp;lt;/equals&amp;gt;&lt;br /&gt;
   &amp;lt;/condition&amp;gt;&lt;br /&gt;
   &amp;lt;property&amp;gt;/autopilot/internal/intercept-heading-deg&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/autopilot/settings/heading-bug-deg&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;/orientation/heading-magnetic-deg&amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;/autopilot/internal/heading-offset-deg&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;period&amp;gt;&lt;br /&gt;
   &amp;lt;min&amp;gt;-180&amp;lt;/min&amp;gt;&lt;br /&gt;
   &amp;lt;max&amp;gt;180&amp;lt;/max&amp;gt;&lt;br /&gt;
  &amp;lt;/period&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, if /autopilot/locks/heading equals &amp;quot;nav1-hold&amp;quot;, the heading offset computer uses the intercept-heading-deg property as the target heading to fly.For any other value, the old heading-bug value is used. You can already test, if it works. Use the property browser to set this stage to nav-hold and enter any arbitrary value into intercept-heading-deg. Your aircraft should turn to the entered heading on the shortest path. It is crucical that this mode is stable, so spend some time again and double check.&lt;br /&gt;
&lt;br /&gt;
Next, we need to compute the intercept-heading-deg automatically. This is based on the offset from the desired course with a maximum intercept angle of 45°. The [[CDI]] is our friend, it tells us about our course offset, so we use that property in our stage feeding the Heading Offset Computer.&lt;br /&gt;
&lt;br /&gt;
This is a very simple stage, it just substracts a course error (which we will compute in the next stage) from our selected course and normalizes the output into the [0..360] degree interval:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;filter&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Intercept Heading Computer&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;gain&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;gain&amp;gt;1.0&amp;lt;/gain&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/autopilot/internal/selected-course&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;reference&amp;gt;/autopilot/internal/course-error-deg&amp;lt;/reference&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;/autopilot/internal/intercept-heading-deg&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;period&amp;gt;&lt;br /&gt;
   &amp;lt;min&amp;gt;0&amp;lt;/min&amp;gt;&lt;br /&gt;
   &amp;lt;max&amp;gt;360&amp;lt;/max&amp;gt;&lt;br /&gt;
  &amp;lt;/period&amp;gt;&lt;br /&gt;
 &amp;lt;/filter&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This stage only makes sense with a preceding one computing the course error from the cdi deflection. We want something that spits out 45 for a full CDI deflection and one might think of a &amp;lt;gain&amp;gt; filter to do this. But we also want an automatic wind correction in case of cross wind. For that we also need an integrator. Because we need to compute absolute values for the output, a pi-simple-controller is our choice here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;pi-simple-controller&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;cdi-integrator&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;debug&amp;gt;false&amp;lt;/debug&amp;gt;&lt;br /&gt;
  &amp;lt;config&amp;gt;&lt;br /&gt;
   &amp;lt;Kp&amp;gt;45.0&amp;lt;/Kp&amp;gt;&lt;br /&gt;
   &amp;lt;Ki&amp;gt;0.40&amp;lt;/Ki&amp;gt;&lt;br /&gt;
  &amp;lt;/config&amp;gt;&lt;br /&gt;
  &amp;lt;input&amp;gt;/autopilot/internal/cdi-deflection&amp;lt;/input&amp;gt;&lt;br /&gt;
  &amp;lt;output&amp;gt;/autopilot/internal/course-error-deg&amp;lt;/output&amp;gt;&lt;br /&gt;
  &amp;lt;min&amp;gt;-45.0&amp;lt;/min&amp;gt;&lt;br /&gt;
  &amp;lt;max&amp;gt;45.0&amp;lt;/max&amp;gt;&lt;br /&gt;
 &amp;lt;/pi-simple-controller&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It takes our CDI deflection and compares to zero (note the missing reference element which defaults to zero). The result is multiplied by Kp (45) and a value of 0.4° per second is added to the offset. The output is clipped to 45°.&lt;br /&gt;
&lt;br /&gt;
You now have all stages, you need for the LNAV section. To compute the values in the correct order, they should be in the order&lt;br /&gt;
# cdi-integrator&lt;br /&gt;
# intercept heading computer&lt;br /&gt;
# heading offset computer&lt;br /&gt;
&lt;br /&gt;
== Related content ==&lt;br /&gt;
{{Forum|46|Autopilot}}&lt;br /&gt;
* [[Autopilot Configuration Reference]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Aircraft enhancement|Autopilot Design an]]&lt;br /&gt;
[[Category:Howto|Autopilot Design an]]&lt;/div&gt;</summary>
		<author><name>Mcginnly</name></author>
	</entry>
</feed>