Howto:Shader programming in FlightGear: Difference between revisions

Jump to navigation Jump to search
m
→‎Effects file: added link to new page
No edit summary
m (→‎Effects file: added link to new page)
(22 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{forum|47|Effects & Shaders}}
{{forum|47|Effects & Shaders}}
{{Rendering}}
<!--
{{WIP|More to follow}}
-->


This is meant to become an introduction to shader programming in FlightGear, for the time being (03/2010), this is work in progress, please feel free to ask questions or suggest topics.
This is meant to become an introduction to '''shader programming in FlightGear''', for the time being (03/2010), this is work in progress, please feel free to ask questions or suggest topics.


Your help in improving and updating this article is appreciated, thanks!
Your help in improving and updating this article is appreciated, thanks!
Line 9: Line 13:
For an OpenGL quick reference, please see: http://www.khronos.org/files/opengl-quick-reference-card.pdf for an GLSL quick reference see [http://www-evasion.imag.fr/Membres/Sebastien.Barbier/Enseignement/glsl_quickref.pdf glsl_quickref.pdf]
For an OpenGL quick reference, please see: http://www.khronos.org/files/opengl-quick-reference-card.pdf for an GLSL quick reference see [http://www-evasion.imag.fr/Membres/Sebastien.Barbier/Enseignement/glsl_quickref.pdf glsl_quickref.pdf]


= Intro =
== What is GLSL? ==
GLSL (OpenGL Shading Language or "GLslang") is the official OpenGL shading language and allows you to write programs, so called "shaders" in a high level shading language that is based on the C programming language to create OpenGL fragment (pixel) and vertex shaders.
''GLSL'' (''OpenGL Shading Language'' or "GLslang") is the official OpenGL shading language and allows you to write programs, so called "shaders" in a high level shading language that is based on the C programming language to create OpenGL fragment (pixel) and vertex shaders.


With the recent advances in graphics cards, new features have been added to allow for increased flexibility in the rendering pipeline at the vertex and fragment level. Programmability at this level is achieved with the use of fragment and vertex shaders.
With the recent advances in graphics cards, new features have been added to allow for increased flexibility in the rendering pipeline at the vertex and fragment level. Programmability at this level is achieved with the use of fragment and vertex shaders.
Line 18: Line 22:
Shaders are written and stored as plain text files, which can be uploaded (as strings) and executed on the GPU (processor of the graphics card).
Shaders are written and stored as plain text files, which can be uploaded (as strings) and executed on the GPU (processor of the graphics card).


= What is a Shader =
== What is a shader? ==
A shader is a programmable replacement for parts of the fixed OpenGL function pipeline, you can imagine it sort of like a "plugin" to customize rendering for specific scene elements.
A ''shader'' is a programmable replacement for parts of the fixed OpenGL function pipeline, you can imagine it sort of like a "plugin" to customize rendering for specific scene elements.


GLSL shaders are not stand-alone applications; they require an application that utilizes the OpenGL API.  
GLSL shaders are not stand-alone applications; they require an application that utilizes the OpenGL API.  
Line 27: Line 31:
Actually each vertex and fragment shader must have one entry point (the main function) each, but you can create and link more shaders.
Actually each vertex and fragment shader must have one entry point (the main function) each, but you can create and link more shaders.


GLSL shaders themselves are simply a set of strings that are passed to the hardware vendor’s driver for compilation from within an application using the OpenGL API's entry points. Shaders can be created on the fly from within an application or read in as text files, but must be sent to the driver in the form of a string.
GLSL shaders themselves are simply a set of strings that are passed to the hardware vendors driver for compilation from within an application using the OpenGL APIs entry points. Shaders can be created on the fly from within an application or read in as text files, but must be sent to the driver in the form of a string.  
 
GLSL has explicit ties to the OpenGL API - to the extent that much of the OpenGL 'state' (eg which light sources are bound, what material properties are currently set up) is presented as pre-defined global variables in GLSL.


GLSL has explicit ties to the OpenGL API - to the extent that much of the OpenGL "state" (for example which light sources are bound, what material properties are currently set up) is presented as pre-defined global variables in GLSL.


Shaders offer:
Shaders offer:
Line 37: Line 40:
* Performance Benefits
* Performance Benefits


Shaders have access to the render state (parameters, matrices, lights, materials ...) and textures.
Shaders have access to textures and the render state (parameters, matrices, lights, materials etc).
A "pass" is the rendering of a 3D Model with a vertex and pixel shader pair.
A "pass" is the rendering of a 3D Model with a vertex and pixel shader pair.
An effect can require multiple passes, while each pass can use a different shader and/or model pair.
An effect can require multiple passes, while each pass can use a different shader and/or model pair.
Line 44: Line 47:
To make it simple, a shader is a program that is loaded on the GPU and called for every vertex or pixel: this gives programmers the possibility to implement techniques and visual effects and execute them faster. In modern games or simulators lots of shaders are used: lights, water, skinning, reflections and much more.  
To make it simple, a shader is a program that is loaded on the GPU and called for every vertex or pixel: this gives programmers the possibility to implement techniques and visual effects and execute them faster. In modern games or simulators lots of shaders are used: lights, water, skinning, reflections and much more.  


We can create as many shader programs as needed (you can have many shaders of the same type (vertex or fragment) attached to the same program, but only one of them can define the entrypoint:the main() function).
We can create as many shader programs as needed.  You can have many shaders of the same type (vertex or fragment) attached to the same program, but only one of them can define the entry point — the <code>main()</code> function.


Each Shader program is assigned an handler, and you can have as many programs linked and ready to use as you want (and your hardware allows).
Each Shader program is assigned an handler, and you can have as many programs linked and ready to use as you want (and your hardware allows).
Line 54: Line 57:
* Cross platform compatibility on multiple operating systems, including Linux, Mac OS and Windows.
* Cross platform compatibility on multiple operating systems, including Linux, Mac OS and Windows.
* The ability to write shaders that can be used on any hardware vendor’s graphics card that supports the OpenGL Shading Language.
* The ability to write shaders that can be used on any hardware vendor’s graphics card that supports the OpenGL Shading Language.
* Each hardware vendor includes the GLSL compiler in their driver, thus allowing each vendor to create code optimized for their particular graphics card’s architecture.
* Each hardware vendor includes the GLSL compiler in their driver, thus allowing each vendor to create code optimized for their particular graphics cards architecture.
 
= Language Features =


== Language features ==
While GLSL has a C-Like syntax, it introduces some new types and keywords. To get a detailed view of the language, please see the GLSL specification you can find on http://www.opengl.org/documentation/glsl/
While GLSL has a C-Like syntax, it introduces some new types and keywords. To get a detailed view of the language, please see the GLSL specification you can find on http://www.opengl.org/documentation/glsl/


The OpenGL Shading Language provides many operators familiar to those with a background in using the C programming language. This gives shader developers flexibility when writing shaders. GLSL contains the operators in C and C++, with the exception of pointers. Bitwise operators were added in version 1.30.
The OpenGL Shading Language provides many operators familiar to those with a background in using the C programming language. This gives shader developers flexibility when writing shaders. GLSL contains the operators in C and C++, with the exception of pointers. Bitwise operators were added in version 1.30.


Similar to the C programming language, GLSL supports loops and branching, including if, else, if/else, for, do-while, break, continue, etc.
Similar to the C programming language, GLSL supports loops and branching, including <code>if</code>, <code>else</code>, <code>if</code>/<code>else</code>, <code>for</code>, <code>do-while</code>, <code>break</code>, <code>continue</code>, etc.
 
User defined functions are supported, and a wide variety of commonly used functions are provided built-in as well. This allows the graphics card manufacturer the ability to optimize these built-in functions at the hardware level if they are inclined to do so. Many of these functions are similar to those found in the math library of the C programming language such as <code>exp()</code> and <code>abs()</code> while others are specific to graphics programming such as <code>smoothstep()</code> and <code>texture2D()</code>.
 
== Error Reports, Debugging, Troubleshooting ==


User defined functions are supported, and a wide variety of commonly used functions are provided built-in as well. This allows the graphics card manufacturer the ability to optimize these built-in functions at the hardware level if they are inclined to do so. Many of these functions are similar to those found in the math library of the C programming language such as exp() and abs() while others are specific to graphics programming such as smoothstep() and texture2D().
Shaders are compiled at FG startup.


= Shader Types =
Shader compilation errors can be found in the fgfs.log file.  More about the [[Commonly_used_debugging_tools#fgfs.log|fgfs.log here]].


There are two types of shaders in GLSL: "vertex shaders" and "fragment shaders" (with geometry shaders being a part of OpenGL 3.2).
As of FG 2016.4.4, shaders do not seem to recompile upon Debug/Reload Aircraft Model or File/Reset. So the only option to re-compile/test a shader is to quit a re-start FG altogether.
 
== Shader types ==
There are two types of shaders in GLSL: ''vertex shaders'' and ''fragment shaders'' (with geometry shaders being a part of OpenGL 3.2).


These are executed by vertex and fragment processors in the graphics hardware.
These are executed by vertex and fragment processors in the graphics hardware.
Line 76: Line 85:
* Geometry shaders create geometry on the GPU
* Geometry shaders create geometry on the GPU


Typically, vertex shader files use the file extension ".vert", while fragment shader files use the ".frag" extension.  
Typically, vertex shader files use the file extension <code>.vert</code>, while fragment shader files use the <code>.frag</code> extension.  
In FlightGear, these files can be found in the "Shaders" subdirectory of the base package, i.e. $FG_ROOT/Shaders
In FlightGear, these files can be found in the <code>Shaders</code> subdirectory of the base package, in essence <code>$FG_ROOT/Shaders</code>.


For a list of currently available shaders, you may want to take a look at: http://gitorious.org/fg/fgdata/trees/master/Shaders
For a list of currently available shaders, you may want to take a look at: {{fg root file|Shaders}}.


So, shaders generally go around in pairs - one shader (the "Vertex shader") is a short program that takes in one vertex from the main CPU and produces one vertex that is passed on to the GPU rasterizer which uses the vertices to create triangles - which it then chops up into individual pixel-sized fragments.  
So, shaders generally go around in pairs - one shader (the ''vertex shader'') is a short program that takes in one vertex from the main CPU and produces one vertex that is passed on to the GPU rasterizer which uses the vertices to create triangles - which it then chops up into individual pixel-sized fragments.  


A vertex shader is run once per vertex, while a fragment shader is run once per fragment covered by the primitive being rendered (a point, a line or a triangle). A fragment equate a pixel except in the case of multi-sampling where a pixel can be the weighted average of several fragments. Multi-sampling is used to remove aliasing and jagged edges.
A vertex shader is run once per vertex, while a fragment shader is run once per fragment covered by the primitive being rendered (a point, a line or a triangle). A fragment equate a pixel except in the case of multi-sampling where a pixel can be the weighted average of several fragments. Multi-sampling is used to remove aliasing and jagged edges.
Many such executions can happen in parallel. There is no communication or ordering between
Many such executions can happen in parallel. There is no communication or ordering between executions. Vertex shaders are flexible and quick.
executions. Vertex shaders are flexible and quick.


=== Vertex shaders ===
{{FGCquote
  |The vertex shader doesn't know anything about the mesh it renders, it just knows one single vertex at a time and all the info that is attached to the vertex (normals, tangents, binormals, color,...)  And the vertex shader doesn't really draw anything, it just takes care of all the things which have to do with 'where in space' you are.
The way this works is that for all the vertices of an object you want to render, the position of the object gets attached to all vertices (currently in the color spot). The vertex shader then just adds the offset vector to the vertex coordinate with respect to the origin.
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/32326487/
    |title=<nowiki>Re: [Flightgear-devel] cities in FG & how to move forward</nowiki>
    |author=<nowiki>Renk Thorsten</nowiki>
    |date=<nowiki>2014-05-11</nowiki>
  }}
}}


{| class="wikitable"
! Input
| Vertex attributes
|-
! Output
| At least vertex position (in the clip space)
|-
! Restrictions
| Cannot access any vertex other than the current one
|-
! ''Note''
| ''Loading a vertex shader turns off parts of the OpenGL pipeline (vertex shaders fully replace the "Texturing & Lighting unit").''
|}


== Vertex Shaders ==
Objects in a computer graphics scene are usually meshes that are made up of polygons. The corner of each of those polygons is called a ''vertex''.
Input: Vertex attributes
A vertex shader receives input in the form of per-vertex variables called ''attribute variables'', and per-polygon variables called ''uniform variables''.
 
Output: At least vertex position (in the clip space)
 
Restrictions: Cannot access any vertex other than the current one
 
Note: Loading a vertex shader turns off parts of the OpenGL pipeline (vertex shaders fully replace the "Texturing & Lighting unit")
 
Objects in a computer graphics scene are usually meshes that are made up of polygons. The corner of each of those polygons is called a "vertex".
A vertex shader receives input in the form of per-vertex variables called "attribute variables", and per-polygon variables called "uniform variables".
The vertex shader must specify the coordinates of the vertex in question. This way, the geometry of the object can be modified.  
The vertex shader must specify the coordinates of the vertex in question. This way, the geometry of the object can be modified.  


Vertex shaders operate on each vertex, the vertex shader is executed for every vertex related OpenGL call (e.g. glVertex* or glDrawArrays).
Vertex shaders operate on each vertex, the vertex shader is executed for every vertex related OpenGL call (for example <code>glVertex*</code> or <code>glDrawArrays</code>).
Accordingly, this means for example, that for meshes that contain e.g. 5000 vertices, the vertex shader will also be executed 5000 times.
Accordingly, this means for example, that for meshes that contain for example 5000 vertices, the vertex shader will also be executed 5000 times.


A single vertex itself is composed of a number of "attributes" (vertex attrib), such as: position, texture coordinates, normal and color for the most common.  
A single vertex itself is composed of a number of ''attributes'' (vertex attrib), such as: position, texture coordinates, normal and color for the most common.  
The position (attribute) is the most important one. The coordinates (x, y and z) of the vertex's entering position are those which have been given by the 3D modeler during the creation of the 3D model. The vertex's position is defined in the local space of the mesh (or object space).  
The position (attribute) is the most important one. The coordinates (x, y and z) of the vertex's entering position are those which have been given by the 3D modeler during the creation of the 3D model. The vertex's position is defined in the local space of the mesh (or object space).  


A vertex shader provides almost full control over what is happening with each vertex. Consequently, all per-vertex operations of the fixed function OpenGL pipeline are replaced by the custom vertex shader.  
A vertex shader provides almost full control over what is happening with each vertex. Consequently, all per-vertex operations of the fixed function OpenGL pipeline are replaced by the custom vertex shader.  


Vertex Shaders take application geometry and per-vertex attributes as input and transform the input data in some meaningful way.
Vertex shaders take application geometry and per-vertex attributes as input and transform the input data in some meaningful way.


* A vertex shader '''must''' write to <code>gl_Position</code>
* A vertex shader '''can''' write to <code>gl_PointSize</code>, <code>gl_ClipVertex</code>
* <code>gl_Vertex</code> is an attribute supplying the untransformed vertex coordinate
* <code>gl_Position</code> is an special output variable for the transformed vertex coordinate


* A vertex shader MUST write to gl_Position
A vertex shader can also set other variables which are called ''varying variables''.
* A vertex shader CAN write to gl_PointSize, gl_ClipVertex
The values of these variables are passed on to the second kind of shader, the ''fragment shader''.  
* gl_Vertex is an attribute supplying the untransformed vertex coordinate
The fragment shader is run for every pixel on the screen where the polygons of the mesh appear. The fragment shader is responsible for setting the final color of that little piece of the mesh
* gl_Position is an special output variable for the transformed vertex coordinate
 
A vertex shader can also set other variables which are called "varying variables".  
The values of these variables are passed on to the second kind of shader, the "fragment shader".  
The fragment shader is run for every pixel on the screen where the polygons of the mesh appear.The fragment shader is responsible for setting the final color of that little piece of the mesh


Common tasks for a vertex shader include:
Common tasks for a vertex shader include:
* Vertex position transformation
* Vertex position transformation
* Per vertex lighting
* Per vertex lighting
Line 133: Line 153:
* Setting up data for fragment shaders
* Setting up data for fragment shaders


The vertex shader runs from start to end for each and every vertex that's passed into the graphics card - the fragment process does the same thing at the pixel level. In most scenes there are a heck of a lot more pixel fragments than there are vertices - so the performance of the fragment shader is vastly more important and any work we can do in the vertex shader, we probably should.  
The vertex shader runs from start to end for each and every vertex that's passed into the graphics card the fragment process does the same thing at the pixel level. In most scenes there are a heck of a lot more pixel fragments than there are vertices so the performance of the fragment shader is vastly more important and any work we can do in the vertex shader, we probably should.  


A minum vertex shader example may looks this:
A minum vertex shader example may looks this:
<syntaxhighlight lang="glsl">
void main(void)
{
  gl_Position = ftransform();
}
</syntaxhighlight>


void main(void)
=== Fragment shaders ===
{
{{FGCquote
     gl_Position = ftransform();
  |the fragment shader basically knows only the pixel it is about to render and whatever information is passed from the vertex shader. Based on 'where' the vertex shader says the pixel is, the rasterizer stage determines what the texture for the pixel should be.
}
But there are techniques to do this in a different way, for instance the water depth map uses world coordinates to look up a world texture, and the gardens would have to be drawn in a similar way.
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/32326487/
    |title=<nowiki>Re: [Flightgear-devel] cities in FG & how to move forward</nowiki>
     |author=<nowiki>Renk Thorsten</nowiki>
    |date=<nowiki>2014-05-11</nowiki>
  }}
}}


== Fragment Shaders ==
{| class="wikitable"
Input: Interpolation of the vertex shader outputs
! Input
| Interpolation of the vertex shader outputs
|-
! Output
| Usually a fragment color.
|-
! Restrictions
| Fragment shaders have no knowledge of neighboring pixels.
|-
! ''Note''
| ''Loading a fragment shader turns off parts of the OpenGL pipeline (pixel shaders fully replace the "Texturing Unit").''
|}


Output:Usually a fragment color.
The other shader (the ''fragment shader'' - also (incorrectly) known as the "pixel shader") takes one pixel from the rasterizer and generates one pixel to write or blend into the frame buffer.  
 
Restrictions: Fragment shaders have no knowledge of neighboring pixels.
 
Note: Loading a fragment shader turns off parts of the OpenGL pipeline (pixel shaders fully replace the "Texturing Unit")
 
The other shader (the "Fragment shader" - also known (incorrectly) as the "pixel shader") takes one pixel from the rasterizer and generates one pixel to write or blend into the frame buffer.  


A fragment shader can write to the following special output variables:
A fragment shader can write to the following special output variables:
* gl_FragColor to set the color of the fragment
* <code>gl_FragColor</code> to set the color of the fragment
* gl_FragData[n] to output to a specific render target
* <code>gl_FragData[n]</code> to output to a specific render target
* gl_FragDepth to set the fragment depth
* <code>gl_FragDepth</code> to set the fragment depth
 


Common tasks of fragment shaders include:
Common tasks of fragment shaders include:
* Texturing (even procedural)
* Texturing (even procedural)
* Per pixel lighting and material application
* Per pixel lighting and material application
* ray tracing
* Ray tracing
* Fragment color computation
* Fragment color computation
* Operations on Interpolated Values
* Operations on Interpolated Values
* Doing operations per fragment to make pretty pictures
* Doing operations per fragment to make pretty pictures


A minimum fragment shader may look like this:
A minimum fragment shader may look like this:
 
<syntaxhighlight lang="glsl">
void main(void)
void main(void)
{
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
}
</syntaxhighlight>


A fragment shader takes perspective-correct interpolated attribute values as input and either discards the fragment or outputs the fragment's color.
A fragment shader takes perspective-correct interpolated attribute values as input and either discards the fragment or outputs the fragment's color.
Line 179: Line 215:
Fragment shaders operate on every fragment which is produced by rasterization. Fragment shaders give you nearly full control over what is happening with each fragment. However just like vertex shaders, a fragment shader replaces all per-fragment operations of the fixed function OpenGL pipeline.
Fragment shaders operate on every fragment which is produced by rasterization. Fragment shaders give you nearly full control over what is happening with each fragment. However just like vertex shaders, a fragment shader replaces all per-fragment operations of the fixed function OpenGL pipeline.


= Data Types in GLSL =
== Data types in GLSL ==
Note that there is no implicit type conversion in GLSL, all conversions and initializations have to be done using explicit constructor calls!
Note that there is no implicit type conversion in GLSL, all conversions and initializations have to be done using explicit constructor calls!


== Scalars ==
=== Scalars ===
* float - 32 bit, very nearly IEEE-754 compatible
* <code>float</code> – 32 bit, very nearly IEEE-754 compatible
* int - at least 16 bit, but not backed by a fixed-width register
* <code>int</code> – at least 16 bit, but not backed by a fixed-width register
* bool - like C++, but must be explicitly used for all flow control
* <code>bool</code> – like C++, but must be explicitly used for all flow control


== Vectors ==
=== Vectors ===
* vec2, vec3, vec4 2D, 3D and 4D floating point vector
* <code>vec2</code>, <code>vec3</code>, <code>vec4</code> – 2D, 3D and 4D floating point vector
* ivec2, ivec3, ivec4 2D, 3D and 4D integer vector
* <code>ivec2</code>, <code>ivec3</code>, <code>ivec4</code> – 2D, 3D and 4D integer vector
* bvec2, bvec3, bvec4 2D, 3D and 4D boolean vectors
* <code>bvec2</code>, <code>bvec3</code>, <code>bvec4</code> – 2D, 3D and 4D boolean vectors


Accessing a vector can be done using letters as well as standard C selectors.
Accessing a vector can be done using letters as well as standard C selectors.
Line 199: Line 235:
s,t,p,q for texture coordinates.
s,t,p,q for texture coordinates.


== Matrices ==
=== Matrices ===
* mat2 2x2 floating point matrix
* <code>mat2</code> – 2x2 floating point matrix
* mat3 3x3 floating point matrix
* <code>mat3</code> – 3x3 floating point matrix
* mat4 4x4 floating potint matrix
* <code>mat4</code> – 4x4 floating potint matrix


== Samplers ==
=== Samplers ===
In GLSL, textures are represented and accessed using so called "samplers", which are used for sampling textures and which have to be uniform. The following samplers are available:
In GLSL, textures are represented and accessed using so called "samplers", which are used for sampling textures and which have to be uniform. The following samplers are available:


* sampler1D, sampler2D, sampler3D 1D, 2D and 3D texture
* <code>sampler1D</code>, <code>sampler2D</code>, <code>sampler3D</code> – 1D, 2D and 3D texture
* samplerCube Cube Map texture
* <code>samplerCube</code> – Cube Map texture
* sampler1Dshadow, sampler2Dshadow 1D and 2D depth-component texture
* <code>sampler1Dshadow</code>, <code>sampler2Dshadow</code> – 1D and 2D depth-component texture


== Arrays ==
=== Arrays ===
GLSL supports the same syntax for creating arrays that is already known from C or C++, e.g.:
GLSL supports the same syntax for creating arrays that is already known from C or C++, e.g.:
 
<syntaxhighlight lang="glsl">
vec2 foo[10];
vec2 foo[10];
</syntaxhighlight>


So, arrays can be declared using the same syntax as in C, but can't be initialized when declared. Accessing array's elements is done as in C.
So, arrays can be declared using the same syntax as in C, but can't be initialized when declared. Accessing array's elements is done as in C.


== Structures ==
=== Structures ===
Structures can also be created like in C or C++, e.g.:
Structures can also be created like in C or C++, e.g.:
 
<syntaxhighlight lang="glsl">
struct foo {
struct foo {
   vec3 pos;
   vec3 pos;
};
};
</syntaxhighlight>


= Global Storage Qualifiers =
== Global storage qualifiers ==
Used for communication between shaders and application:
Used for communication between shaders and application:
* <code>const</code> – For declaring non-writable, compile-time constant variables
* <code>attribute</code> – For frequently changing (per vertex) information passed from the application to a vertex shader (no integers, bools, structs, or arrays)
* <code>uniform</code> – For infrequently changing (per primitive) information passed from the application to a vertex or fragment shader:constant shader parameters that can be changed between draws (cannot be written to in a shader, do not change per-vertex or per-fragment)
* <code>varying</code> – For information passed from a vertex shader to a fragment shader, will be interpolated in a perspective-correct manner during rasterization (can write in vertex shader, but only read in fragment shader)


* const - for declaring non-writable, compile-time constant variables
== Functions ==
* attribute - For frequently changing (per vertex) information passed from the application to a vertex shader (no integers, bools, structs, or arrays)
* uniform - for infrequently changing (per primitive) information passed from the application to a vertex or fragment shader:constant shader parameters that can be changed between draws (cannot be written to in a shader, do not change per-vertex or per-fragment)
* varying - for information passed from a vertex shader to a fragment shader, will be interpolated in a perspective-correct manner during rasterization (can write in vertex shader, but only read in fragment shader)
 
= Functions =
* Much like C++
* Much like C++
* Entry point into a shader is void main()
* Entry point into a shader is <code>void main()</code>
* Overloading based on parameter type (but not return type)
* Overloading based on parameter type (but not return type)
* No support for direct or indirect recursion
* No support for direct or indirect recursion
* Call by value-return calling convention
* Call by value-return calling convention


As in C, a shader is structured in functions. At least each type of shader must have a main function declared with the following syntax: void main()
As in C, a shader is structured in functions. At least each type of shader must have a main function declared with the following syntax: <code>void main()</code>
User defined functions may be defined. As in C a function may have a return value, and use the return statement to pass out its result. A function can be void. The return type can have any type, except array.
User defined functions may be defined. As in C a function may have a return value, and use the return statement to pass out its result. A function can be void. The return type can have any type, except array.


== Parameter Qualifiers ==
=== Parameter qualifiers ===
The parameters of a function may have the following qualifiers:
The parameters of a function may have the following qualifiers:
* in - copy in, but don't copy back out (still writable within function)
* <code>in</code> – Copy in, but don't copy back out (still writable within function)
* out - only copy out; undefined at function entry point
* <code>out</code> – Only copy out; undefined at function entry point
* inout - copy in and copy out
* <code>inout</code> – Copy in and copy out


If no qualifier is specified, by default it is considered to be in.
If no qualifier is specified, by default it is considered to be in.


= Built-ins =
== Built-ins ==
== Vertex Shader ==
=== Vertex shader ===
* <code>vec4 gl_Position;</code> – '''Must''' be written
* <code>vec4 gl_ClipPosition;</code> – May be written
* <code>float gl_PointSize;</code> – May be written


* vec4 gl_Position; must be written
=== Fragment shader ===
* vec4 gl_ClipPosition; may be written
* <code>float gl_FragColor;</code> – May be written
* float gl_PointSize; may be written
* <code>float gl_FragDepth;</code> – May be read/written
* <code>vec4 gl_FragCoord;</code> – May be read
* <code>bool gl_FrontFacing;</code> – May be read


== Fragment Shader ==
=== Vertex attributes ===
* float gl_FragColor; may be written
* float gl_FragDepth; may be read/written
* vec4 gl_FragCoord; may be read
* bool gl_FrontFacing; may be read
 
== Vertex Attributes ==
Only available in vertex shaders.
Only available in vertex shaders.


* attribute vec4 gl_Vertex;
* <code>attribute vec4 gl_Vertex;</code>
* attribute vec3 gl_Normal;
* <code>attribute vec3 gl_Normal;</code>
* attribute vec4 gl_Color;
* <code>attribute vec4 gl_Color;</code>
* attribute vec4 gl_SecondaryColor;
* <code>attribute vec4 gl_SecondaryColor;</code>
* attribute vec4 gl_MultiTexCoordn;
* <code>attribute vec4 gl_MultiTexCoordn;</code>
* attribute float gl_FogCoord;
* <code>attribute float gl_FogCoord;</code>


== Uniforms ==
=== Uniforms ===
* uniform mat4 gl_ModelViewMatrix;
* <code>uniform mat4 gl_ModelViewMatrix;</code>
* uniform mat4 gl_ProjectionMatrix;
* <code>uniform mat4 gl_ProjectionMatrix;</code>
* uniform mat4 gl_ModelViewProjectionMatrix;
* <code>uniform mat4 gl_ModelViewProjectionMatrix;</code>
* uniform mat3 gl_NormalMatrix;
* <code>uniform mat3 gl_NormalMatrix;</code>
* uniform mat4 gl_TextureMatrix[n];
* <code>uniform mat4 gl_TextureMatrix[n];</code>


struct gl_MaterialParameters {
<syntaxhighlight lang="glsl">
vec4 emission;
struct gl_MaterialParameters {
vec4 ambient;
  vec4 emission;
vec4 diffuse;
  vec4 ambient;
vec4 specular;
  vec4 diffuse;
float shininess;
  vec4 specular;
};
  float shininess;
};
</syntaxhighlight>


* uniform gl_MaterialParameters gl_FrontMaterial;
* <code>uniform gl_MaterialParameters gl_FrontMaterial;</code>
* uniform gl_MaterialParameters gl_BackMaterial;
* <code>uniform gl_MaterialParameters gl_BackMaterial;</code>


struct gl_LightSourceParameters {
<syntaxhighlight lang="glsl">
vec4 ambient;
struct gl_LightSourceParameters {
vec4 diffuse;
  vec4 ambient;
vec4 specular;
  vec4 diffuse;
vec4 position;
  vec4 specular;
vec4 halfVector;
  vec4 position;
vec3 spotDirection;
  vec4 halfVector;
float spotExponent;
  vec3 spotDirection;
float spotCutoff;
  float spotExponent;
float spotCosCutoff;
  float spotCutoff;
float constantAttenuation
  float spotCosCutoff;
float linearAttenuation
  float constantAttenuation
float quadraticAttenuation
  float linearAttenuation
};
  float quadraticAttenuation
* Uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];
};
</syntaxhighlight>


== Varyings ==
* <code>uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];</code>
An interface between vertex and fragment shaders is provided by varying variables: vertex shaders compute values per vertex and fragment shaders compute values per fragment.
The value of a varying variable defined in a vertex shader, will be interpolated (perspective-correct) over the primitve being rendered and the interpolated value in the fragment shader can be accessed.


Varying variables can only be used with the data types float, vec2, vec3, vec4, mat2, mat3, mat4. (and arrays of them too.)
=== Varyings ===
An interface between vertex and fragment shaders is provided by varying variables: Vertex shaders compute values per vertex and fragment shaders compute values per fragment.
The value of a varying variable defined in a vertex shader, will be interpolated (perspective-correct) over the primitive being rendered and the interpolated value in the fragment shader can be accessed.


* varying vec4 gl_FrontColor // vertex
Varying variables can only be used with the data types <code>float</code>, <code>vec2</code>, <code>vec3</code>, <code>vec4</code>, <code>mat2</code>, <code>mat3</code>, <code>mat4</code>. (and arrays of them too.)
* varying vec4 gl_BackColor; // vertex
* varying vec4 gl_FrontSecColor; // vertex
* varying vec4 gl_BackSecColor; // vertex
* varying vec4 gl_Color; // fragment
* varying vec4 gl_SecondaryColor; // fragment
* varying vec4 gl_TexCoord[]; // both
* varying float gl_FogFragCoord; // both


== Functions ==
* <code>varying vec4 gl_FrontColor; // vertex</code>
* <code>varying vec4 gl_BackColor; // vertex</code>
* <code>varying vec4 gl_FrontSecColor; // vertex</code>
* <code>varying vec4 gl_BackSecColor; // vertex</code>
* <code>varying vec4 gl_Color; // fragment</code>
* <code>varying vec4 gl_SecondaryColor; // fragment</code>
* <code>varying vec4 gl_TexCoord[]; // both</code>
* <code>varying float gl_FogFragCoord; // both</code>


= Anatomy of a Shader =
=== Functions ===
== Anatomy of a shader ==
A shader's entry point is the main function which returns void and takes no arguments (void)
A shader's entry point is the main function which returns void and takes no arguments (void)


 
=== Anatomy of a vertex shader ===
== Anatomy of a Vertex Shader ==
The function <code>void main()</code> is called afresh for each vertex in the 3D object model:
The function 'void main()' is called afresh for each vertex in the 3D object model:
<syntaxhighlight lang="glsl">
 
// Vertex Shader
// Vertex Shader
void main() {
void main() {
   gl_Position = gl_Vertex;
   gl_Position = gl_Vertex;
}
}
 
</syntaxhighlight>
== Anatomy of a Fragment Shader ==
The function 'void main()' is called afresh for each fragment/pixel in the 3D object model:


// Fragment Shader
=== Anatomy of a fragment shader ===
void main() {
The function <code>void main()</code> is called afresh for each fragment/pixel in the 3D object model:
<syntaxhighlight lang="glsl">
// Fragment Shader
void main() {
   gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
   gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
}
</syntaxhighlight>


= A Practical Application in [[Flightgear]] =
== Practical application – ALS landing lights – spotlight ==
[[File:ALS Secondary Light Proof of Concept.png|thumb|300px|ALS secondary light proof of concept]]
[[File:Als Secondary Lights combined with Fog Effect.jpg|thumb|300px|Weather settings to produce fog and ALS landing lights on a runway.]]
[[File:Model on Water and Trees on Land.jpg|thumb|300px|Model on water and trees on land ALS lights effect]]
[[File:Model on Water.jpg|thumb|300px|ALS lights effect over model and water.]]
[[File:ALS Lights over Model and Terrain.jpg|thumb|300px|ALS lights over model and terrain]]


== ALS Landing Lights - Spotlight ==
The ALS landing lights-spotlight (we'll call it ALS lights from now on) is a good example for showing how to incorporate a shader effect into FlightGear as it touches many parts of the visuals we see and many parts of the coding pipeline.
[[File:als secondary light.png|640px|thumbnail|Proof of Concept]]
The ALS Landing Lights-Spotlight (we'll call it ALS Lights from now on) is a good example for showing how to incorporate a shader effect into [[Flightgear]] as it touches many parts of the visuals we see and many parts of the coding pipeline.


In the case of ALS Lights, you have to add the effect to every visual item rendered on the screen that you want to see a light shining on. If you want it to be capable of shining on everything, you have to account for each separate item and how that item is rendered.  That is a lot of code to touch.
In the case of ALS Lights, you have to add the effect to every visual item rendered on the screen that you want to see a light shining on. If you want it to be capable of shining on everything, you have to account for each separate item and how that item is rendered.  That is a lot of code to touch.


The list might include
The list might include
*runway
* Terrain
*terrain
** Runway
*models
** Dirtrunway
**ai
** Agriculture
**aircraft
* Models
**tree
** AI
*weather
** Aircraft
**fog
** Tree
**clouds
** Buildings
**hazes
* Weather
*water
** Fog
**inland
** Clouds
**ocean
** Hazes
**stream
* Water
** Inland
** Ocean
** Stream


Some of these items may be controlled or rendered by the same effect and shader file. They might have to be accounted for individually. They may have special lighting influences that have to be accounted for. You have to take each one separately and account for all its needs.  
Some of these items may be controlled or rendered by the same effect and shader file. They might have to be accounted for individually. They may have special lighting influences that have to be accounted for. You have to take each one separately and account for all its needs.  


The example highlighted in this article is what was added to tree.eff to shine the lights on trees.
The example highlighted in this article is what was added to <code>tree.eff</code> to shine the lights on trees.


=== Program Flow Simplified ===
=== Program flow simplified ===
Preferences/Nasal/XML >> Property Tree >> Effect File >> Shader >> Rendered to Screen
Preferences/Nasal/XML Property tree → Effect file → Shader Rendered to screen


=== Preferences/Nasal/XML ===
=== Preferences/Nasal/XML ===
{{Note|need link to Preferences, Nasal and XML Docs here}}
Any combination of Preferences, [[Nasal|Nasal]] or [[Xml|XML]] manipulates data in the [[Property Tree|property tree]].  
Any combination of Preferences, Nasal or XML manipulates data in the property tree.  
In this case the switch to turn on the landing or spot light and a couple other needed data containers are defined in <code>$FG_ROOT/preferences.xml</code> with the following lines.
In this case the switch to turn on the landing or spot light and a couple other needed data containers are defined in $FG_ROOT/preferences.xml with the following lines.
<syntaxhighlight lang="xml">
<als-secondary-lights>
<als-secondary-lights>
  <use-searchlight type="bool">false</use-searchlight>
<use-searchlight type="bool">false</use-searchlight>
  <use-landing-light type="bool">false</use-landing-light>
<use-landing-light type="bool">false</use-landing-light>
  <use-alt-landing-light type="bool">false</use-alt-landing-light>
<use-alt-landing-light type="bool">false</use-alt-landing-light>
  <landing-light1-offset-deg type="float">0.0</landing-light1-offset-deg>
<landing-light1-offset-deg type="float">0.0</landing-light1-offset-deg>
  <landing-light2-offset-deg type="float">0.0</landing-light2-offset-deg>
<landing-light2-offset-deg type="float">0.0</landing-light2-offset-deg>
</als-secondary-lights>
</als-secondary-lights>
They show up in the Property Tree under sim/rendering/als-secondary-lights and can be activated or manipulated by normal Nasal calls or XML.
</syntaxhighlight>
 
They show up in the property tree under <code>sim/rendering/als-secondary-lights</code> and can be activated or manipulated by normal Nasal calls or XML.


[[File:als_secondary_lights_fog.jpg|1024px|thumbnail|ALS Landing Lights combined with Fog Effect]]
=== Property tree ===
=== Effects File ===
The [[Property Tree|property tree]] is like the CPU of the [[FlightGear]] program at a user level. It's a go-between that allows the user to see and influence many aspects at the heart of the program in ALMOST real time. More of the internals of FlightGear are being exposed to the property tree than ever before. This allows us to have user level access in areas of the code that used to only be reserved for [[Programming Resources|programmers]]. Because of the manner in which the property tree is fed information, and the one step removed from the C source, care must be taken in how it is used. Depending on how it is used it won't be as responsive to manipulation as it would be if you were to change the same information at the C source level.
{{Note|need link to Effects Doc here to explain the details of the effects file}}
The effects file is the mechanism we use to combine and manipulate all the necessary data to create stunning visual effects. It's the link between the data contained and produced in Nasal, XML and the Property Tree and the graphics rendering pipeline. It's there to allow us to create these affects without having to know or use the C++ code base. Its flexible framework allows for an almost infinite range of sophisticated effects.
=== Effects file ===
The effects file is the mechanism we use to combine and manipulate all the necessary data to create stunning visual effects. It's the link between the data contained and produced in Nasal, XML and the property tree and the graphics rendering pipeline. It's there to allow us to create these affects without having to know or use the C++ code base. Its flexible framework allows for an almost infinite range of sophisticated effects.
 
See this page for more details: [[Effect Framework]]


==== Parameters ====
==== Parameters ====
Parameter entries defined in the Effect file correspond to a property tree data container (static or variable). They will contain the data needed by the shader program to perform its magic. The type of information contained in the property tree might be program control data or variable/static data that the shader program can manipulate prior to sending on to render.
Parameter entries defined in the Effect file correspond to a property tree data container (static or variable). They will contain the data needed by the shader program to perform its magic. The type of information contained in the property tree might be program control data or variable/static data that the shader program can manipulate prior to sending on to render.
In the case of ALS Lights, below is some of the data passed to, and used by, the shader.
In the case of ALS lights, below is some of the data passed to, and used by, the shader program.
<small><display_xsize><use>/sim/startup/xsize</use></display_xsize>
 
<syntaxhighlight lang="xml">
<small>
<display_xsize><use>/sim/startup/xsize</use></display_xsize>
  <display_ysize><use>/sim/startup/ysize</use></display_ysize>
  <display_ysize><use>/sim/startup/ysize</use></display_ysize>
  <view_pitch_offset><use>/sim/current-view/pitch-offset-deg</use></view_pitch_offset>
  <view_pitch_offset><use>/sim/current-view/pitch-offset-deg</use></view_pitch_offset>
Line 410: Line 465:
  <tquality_level><use>/sim/rendering/shaders/transition</use></tquality_level>
  <tquality_level><use>/sim/rendering/shaders/transition</use></tquality_level>
</small>
</small>
Note the "use-searchlight" entry, it is pointing to the use-searchlight entry in the property tree under "sim/rendering/als-secondary-lights" that was defined in preferences.xml.
</syntaxhighlight>


Some of this data may play a duel role inside the shader program. In other words it might be used to control other functions in addition to ALS Lights.
Note the <code>use-searchlight</code> entry, it is pointing to the use-searchlight entry in the property tree under <code>sim/rendering/als-secondary-lights</code> that was defined in <code>preferences.xml</code>.
There will also be other parameter entries that have nothing to do with ALS Lights. They might be used for other actions or effects the shader is handling.  
 
Some of this data may play a duel role inside the shader program. In other words it might be used to control other functions in addition to ALS lights.
There will also be other parameter entries that have nothing to do with ALS lights. They might be used for other actions or effects the shader is handling.  


==== Technique ====
==== Technique ====
In general, the shader program and the uniforms are defined in between the technique tags. The technique is assigned an index to distinguish one technique from another (technique n="1"). As is the case with tree.eff, sometimes the shader program and its uniforms are defined and needed in more than one technique. In the case of tree.eff it is used in technique 4 and 5. Which means in [[Flightgear]], the tree shader set to either of the the highest two shader settings still produces ALS Lights when activated.
In general, the shader program and the uniforms are defined in between the technique tags. The technique is assigned an index to distinguish one technique from another (technique n="1"). As is the case with tree.eff, sometimes the shader program and its uniforms are defined and needed in more than one technique. In the case of <code>tree.eff</code> it is used in technique 4 and 5. Which means in FlightGear, the tree shader set to either of the the highest two shader settings still produces ALS lights when activated.
 
==== Shader program ====
Next comes the entry to define what shader program the parameters data is going to be passed to.
This is where you specify what shader program is to be used by the technique. ALS has the lowest techniques, with higher quality preceding lower quality.


==== Shader Program ====
<syntaxhighlight lang="xml">
Next comes the entry to define what Shader Program the parameters data is going to be passed to.
<program>
This is where you specify what shader code is to be used by the technique. ALS has the lowest techniques, with higher quality preceding lower quality.
<fragment-shader>Shaders/tree-ALS.frag</fragment-shader>
<program>
<fragment-shader>Shaders/secondary_lights.frag</fragment-shader>
  <fragment-shader>Shaders/tree-ALS.frag</fragment-shader>
</program>
  <fragment-shader>Shaders/secondary_lights.frag</fragment-shader>
</syntaxhighlight>
</program>
In the case of ALS Lights, so far we only have to deal with the fragment shader.
In the case of ALS Lights, so far we only have to deal with the fragment shader.


The program section of the effect file is a nifty method used to allow users to add shaders to [[Flightgear]] without having to add code at C level language base. The C level base is programed to recognize the XML tag pair of <program></program> and thus incorporate the GLSL program files pointed to between the tags. Otherwise you would have to add the GLSL program calls in the base C requiring a completely different set of programming skills and also the necessity of compiling [[Flightgear]] everytime you want to add new shaders. It can work this way because shader programs are compiled at run-time.
The program section of the effect file is a nifty method used to allow users to add shaders to FlightGear without having to add code at C level language base. The C level base is programed to recognize the XML tag pair of <program></program> and thus incorporate the GLSL program files pointed to between the tags. Otherwise you would have to add the GLSL program calls in the base C requiring a completely different set of programing skills and also the necessity of compiling FlightGear everytime you want to add new shader. It can work this way because shader programs are compiled at run-time.


We'll describe the contents of the shader programs below. For now, suffice it to say tree-ALS.frag contains the main program and secondary_lights.frag has functions that are passed uniform data that is manipulated and returned to main for processing.
We'll describe the contents of the shader programs below. For now, suffice it to say <code>tree-ALS.frag</code> contains the main program and <code>secondary_lights.frag</code> has functions that are passed uniform data that is manipulated and returned to main for processing.


==== Uniforms ====
==== Uniforms ====
The uniforms section is the mechanism that feeds the parameter data to the shader program.
The uniforms section is the mechanism that feeds the parameter data to the shader program.
<small><uniform>
<syntaxhighlight lang="xml">
<small>
<uniform>
   <name>view_pitch_offset</name>
   <name>view_pitch_offset</name>
   <type>float</type>
   <type>float</type>
Line 482: Line 544:
   <type>int</type>
   <type>int</type>
   <value><use>display_ysize</use></value>
   <value><use>display_ysize</use></value>
  </uniform></small>
  </uniform>
Note the name, "use_searchlight", which was originally defined in preferences.xml and then became an entry in parameters is now being passed to the program shader by the uniform. Below in the "Shader Program" section, we will show you how the shader receives the uniform's data.
</small>
</syntaxhighlight>
Note the name, <code>use_searchlight</code>, which was originally defined in <code>preferences.xml</code> and then became an entry in parameters is now being passed to the program shader by the uniform. Below in the "Shader program" section, we will show you how the shader receives the uniform's data.


=== Shader Programs ===
=== Shader programs ===
The shader programs used in this example are "tree-ALS.frag" and "secondary_lights.frag".
The shader programs used in this example are <code>tree-ALS.frag</code> and <code>secondary_lights.frag</code>.


=== secondary_lights.frag ===
=== secondary_lights.frag ===
"secondary_lights.frag" consists of
<code>secondary_lights.frag</code> consists of
*uniform inputs (data coming into the shader to be manipulated
* Uniform inputs (data coming into the shader to be manipulated
*functions that manipulate the uniform data
* Functions that manipulate the uniform data


Following it the actual GLSL code in "secondary_lights.frag".
Following it the actual GLSL code in <code>secondary_lights.frag</code>.


==== Uniform Input ====
==== Uniform input ====
uniform int display_xsize;
<syntaxhighlight lang="glsl">
uniform int display_ysize;
uniform int display_xsize;
uniform float field_of_view;
uniform int display_ysize;
uniform float view_pitch_offset;
uniform float field_of_view;
uniform float view_heading_offset;
uniform float view_pitch_offset;
uniform float view_heading_offset;
</syntaxhighlight>


==== Functions ====
==== Functions ====
float light_distance_fading(in float dist)
<syntaxhighlight lang="glsl">
{
float light_distance_fading(in float dist)
  return min(1.0, 10000.0/(dist*dist));
{
}
  return min(1.0, 10000.0/(dist*dist));
}


float fog_backscatter(in float avisibility)
float fog_backscatter(in float avisibility)
{
{
  return 0.5* min(1.0,10000.0/(avisibility*avisibility));
  return 0.5* min(1.0,10000.0/(avisibility*avisibility));
}
}


vec3 searchlight()
vec3 searchlight()
{
{
  vec2 center = vec2 (float(display_xsize) * 0.5, float(display_ysize) * 0.4);
  vec2 center = vec2 (float(display_xsize) * 0.5, float(display_ysize) * 0.4);
  float headlightIntensity;   
  float headlightIntensity;   
  float lightRadius = (float(display_xsize) *9.16 /field_of_view);
  float lightRadius = (float(display_xsize) *9.16 /field_of_view);
  float angularDist = length(gl_FragCoord.xy -center);
  float angularDist = length(gl_FragCoord.xy -center);
  if (angularDist < lightRadius)
  if (angularDist < lightRadius)
  {
  {
    headlightIntensity = pow(cos(angularDist/lightRadius * 1.57075),2.0);
    headlightIntensity = pow(cos(angularDist/lightRadius * 1.57075),2.0);
    //headlightIntensity = headlightIntensity *  
    //headlightIntensity = headlightIntensity *  
    //headlightIntensity*= clamp(1.0 + 0.15 * log(1000.0/(dist*dist)),0.0,1.0);
    //headlightIntensity*= clamp(1.0 + 0.15 * log(1000.0/(dist*dist)),0.0,1.0);
    return  headlightIntensity * vec3 (0.5,0.5, 0.5);
    return  headlightIntensity * vec3 (0.5,0.5, 0.5);
  }
  }
  else return vec3 (0.0,0.0,0.0);
  else return vec3 (0.0,0.0,0.0);
}
}


vec3 landing_light(in float offset)
vec3 landing_light(in float offset)
{
{
  float fov_h = field_of_view;
  float fov_h = field_of_view;
  float fov_v = float(display_ysize)/float(display_xsize) * field_of_view;  
  float fov_v = float(display_ysize)/float(display_xsize) * field_of_view;  
  float yaw_offset;
  float yaw_offset;
  if (view_heading_offset > 180.0)
  if (view_heading_offset > 180.0)
    {yaw_offset = -360.0+view_heading_offset;}
    {yaw_offset = -360.0+view_heading_offset;}
  else
  else
    {yaw_offset = view_heading_offset;}
    {yaw_offset = view_heading_offset;}
  float x_offset = (float(display_xsize) / fov_h * (yaw_offset + offset));
  float x_offset = (float(display_xsize) / fov_h * (yaw_offset + offset));
  float y_offset = -(float(display_ysize) / fov_v * view_pitch_offset);
  float y_offset = -(float(display_ysize) / fov_v * view_pitch_offset);
  vec2 center = vec2 (float(display_xsize) * 0.5 + x_offset, float(display_ysize) * 0.4 + y_offset);
  vec2 center = vec2 (float(display_xsize) * 0.5 + x_offset, float(display_ysize) * 0.4 + y_offset);
  float landingLightIntensity;   
  float landingLightIntensity;   
  float lightRadius = (float(display_xsize) *9.16 /field_of_view);
  float lightRadius = (float(display_xsize) *9.16 /field_of_view);
  float angularDist = length(gl_FragCoord.xy -center);
  float angularDist = length(gl_FragCoord.xy -center);
  if (angularDist < lightRadius)
  if (angularDist < lightRadius)
  {
  {
    landingLightIntensity = pow(cos(angularDist/lightRadius * 1.57075),2.0);
    landingLightIntensity = pow(cos(angularDist/lightRadius * 1.57075),2.0);
    //landingLightIntensity *= min(1.0, 10000.0/(dist*dist));
    //landingLightIntensity *= min(1.0, 10000.0/(dist*dist));
    return  landingLightIntensity * vec3 (0.5,0.5, 0.5);
    return  landingLightIntensity * vec3 (0.5,0.5, 0.5);
  }
  }
  else return vec3 (0.0,0.0,0.0);
  else return vec3 (0.0,0.0,0.0);
}
}
</syntaxhighlight>


=== tree-ALS.frag ===
=== tree-ALS.frag ===
"tree-ALS.frag" consists of
<code>tree-ALS.frag</code> consists of
*uniform inputs (data coming into the shader to be manipulated
* Uniform inputs (data coming into the shader to be manipulated
*functions that manipulate the uniform data
* Functions that manipulate the uniform data


Following it the actual GLSL code in "tree-ALS.frag".
Following it the actual GLSL code in <code>tree-ALS.frag</code>.
While there is significantly more code in tree-ALS.frag, only the code that was included for the ALS Lights is being shown and discussed here.
While there is significantly more code in <code>tree-ALS.frag</code>, only the code that was included for the ALS lights is being shown and discussed here.


==== Uniform Input ====
==== Uniform input ====
Uniform data is brought into the shader in the following manner.
Uniform data is brought into the shader in the following manner.


uniform float landing_light1_offset;
<syntaxhighlight lang="glsl">
uniform float landing_light2_offset;
uniform float landing_light1_offset;
uniform int use_searchlight;
uniform float landing_light2_offset;
uniform int use_landing_light;
uniform int use_searchlight;
uniform int use_alt_landing_light;
uniform int use_landing_light;
uniform int quality_level;
uniform int use_alt_landing_light;
uniform int tquality_level;
uniform int quality_level;
Note "use_searchlight" and how it is defined as incoming uniform data.
uniform int tquality_level;
</syntaxhighlight>


==== Variable Data ====
Note <code>use_searchlight</code> and how it is defined as incoming uniform data.
Variable data can be defined in the shader program. An example of variable data defined in the shader program that is needed for ALS Lights is
 
vec3 secondary_light = vec3 (0.0,0.0,0.0);
==== Variable data ====
Variable data can be defined in the shader program. An example of variable data defined in the shader program that is needed for ALS lights is
<syntaxhighlight lang="glsl">
vec3 secondary_light = vec3 (0.0,0.0,0.0);
</syntaxhighlight>


==== Functions ====
==== Functions ====
Function calls to the function defined in secondary_lights.frag are
Function calls to the function defined in <code>secondary_lights.frag</code> are
vec3 searchlight();
<syntaxhighlight lang="glsl">
vec3 landing_light(in float offset);
vec3 searchlight();
vec3 landing_light(in float offset);
</syntaxhighlight>
 
You don't have to use any path information or includes in the code because the GLSL compiler program takes care of linking all the shader programs as long as they are defined correctly in the "programs" section of the effect file.
You don't have to use any path information or includes in the code because the GLSL compiler program takes care of linking all the shader programs as long as they are defined correctly in the "programs" section of the effect file.
Variable data can be passed to and returned from GLSL functions just like any other language.
Variable data can be passed to and returned from GLSL functions just like any other language.


==== Main Program ====
==== Main program ====
The "main" function is the heart of the shader program. This is where the shader program manipulates all the data made available to it.
The <code>main()</code> function is the heart of the shader program. This is where the shader program manipulates all the data made available to it.
void main()
<syntaxhighlight lang="glsl">
{
void main()
  vec3 secondary_light = vec3 (0.0,0.0,0.0);
{
  if ((quality_level>5) && (tquality_level>5))
  vec3 secondary_light = vec3 (0.0,0.0,0.0);
  {
  if ((quality_level>5) && (tquality_level>5))
    if (use_searchlight == 1)
  {
    {
    if (use_searchlight == 1)
      secondary_light += searchlight();
    {
    }
      secondary_light += searchlight();
    if (use_landing_light == 1)
    }
    {
    if (use_landing_light == 1)
      secondary_light += landing_light(landing_light1_offset);
    {
    }
      secondary_light += landing_light(landing_light1_offset);
    if (use_alt_landing_light == 1)
    }
    {
    if (use_alt_landing_light == 1)
      secondary_light += landing_light(landing_light2_offset);
    {
    }
      secondary_light += landing_light(landing_light2_offset);
  }
    }
  vec4 fragColor = vec4 (gl_Color.rgb +secondary_light * light_distance_fading(dist),1.0) * texel;
  }
}
  vec4 fragColor = vec4 (gl_Color.rgb +secondary_light * light_distance_fading(dist),1.0) * texel;
Note how "use_searchlight" is used in the main function to determine if the property defined in preferences.xml and manipulated in the property tree is set to true or 1.
}
Some of the variable data contained in the shader program is used for other purposes and is introduced into the shader program from other property, parameter and uniform definitions not pertaining to ALS Lights.
</syntaxhighlight>
 
Note how <code>use_searchlight</code> is used in the main function to determine if the property defined in <code>preferences.xml</code> and manipulated in the property tree is set to true or 1.


==== File List ====
Some of the variable data contained in the shader program is used for other purposes and is introduced into the shader program from other property, parameter and uniform definitions not pertaining to ALS lights.
 
==== File list ====
Files that are directly touched by this effect include  
Files that are directly touched by this effect include  
* preferences.xml
* <code>preferences.xml</code>
* airfield.eff
* <code>agriculture.eff</code>:
** inherits properties from terrain-default
** Inherits properties from <code>crop</code> << <code>terrain-default</code>
** adds program shaders (technique 2)
** Adds program shaders (technique 2)
** fragment airfield-ALS.frag & secondary_lights.frag
*** Fragment <code>agriculture-ALS.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 2)
** Adds uniforms (technique 2)
* building.eff
* <code>airfield.eff</code>:
** inherits properties from model-combined-deferred << model-combined
** Inherits properties from <code>terrain-default</code>
** adds program shaders (technique 4)
** Adds program shaders (technique 2)
*** fragment model-ALS-ultra.frag & secondary_lights.frag
*** Fragment <code>airfield-ALS.frag</code> and <code>secondary_lights.frag</code>
** inherits uniforms from model-combined-deferred << model-combined
** Adds uniforms (technique 2)
* model-combined.eff
* <code>building.eff</code>:
** inherits properties from model-default
** Inherits properties from <code>model-combined-deferred</code> << <code>model-combined</code>
** adds program shaders (technique 4)
** Adds program shaders (technique 4)
*** fragment model-ALS-ultra.frag & secondary_lights.frag
*** Fragment <code>model-ALS-ultra.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 4)
** Inherits uniforms from <code>model-combined-deferred</code> << <code>model-combined</code>
* model-default.eff
* <code>dirt-runway.eff</code>:
** adds properties
** Inherits properties from <code>crop</code> << <code>terrain-default</code>
** adds program shaders (technique 5)
** Adds program shaders (technique 2)
*** fragment model-ALS-base.frag & secondary_lights.frag
*** Fragment <code>drunway-ALS.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 5)
** Adds uniforms (technique 2)
* runway.eff
* <code>model-combined.eff</code>:
** inherits properties from terrain-default
** Inherits properties from <code>model-default</code>
** adds program shaders (technique 2)
** Adds program shaders (technique 4)
*** fragment runway-ALS.frag & secondary_lights.frag
*** Fragment <code>model-ALS-ultra.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 2)
** Adds uniforms (technique 4)
* terrain-default.eff
* <code>model-default.eff</code>:
** adds properties
** Adds properties
** adds program shaders (technique 3)
** Adds program shaders (technique 5)
*** fragment terrain-ALS-ultra.frag & secondary_lights.frag
*** Fragment <code>model-ALS-base.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 3)
** Adds uniforms (technique 5)
* tree.eff
* <code>runway.eff</code>:
** adds properties
** Inherits properties from terrain-default
** adds program shaders (technique 4 and 5)
** Adds program shaders (technique 2)
*** fragment tree-ALS.frag & secondary_lights.frag
*** Fragment <code>runway-ALS.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 4 and 5)
** Adds uniforms (technique 2)
* urban.eff
* <code>terrain-default.eff</code>:
** inherits properties from terrain-default
** Adds properties
** adds program shaders (technique 1 and 2)
** Adds program shaders (technique 3)
*** fragment urban-ALS.frag & secondary_lights.frag
*** Fragment <code>terrain-ALS-ultra.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 1 and 2)
** Adds uniforms (technique 3)
* water.eff
* <code>tree.eff</code>:
** inherits properties from terrain-default
** Adds properties
** adds program shaders (technique 1)
** Adds program shaders (technique 4 and 5)
*** fragment water-ALS-high.frag & secondary_lights.frag
*** Fragment <code>tree-ALS.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 1)
** Adds uniforms (technique 4 and 5)
* water-inland.eff
* <code>urban.eff</code>:
** inherits properties from terrain-default
** Inherits properties from <code>terrain-default</code>
** adds program shaders (technique 2)
** Adds program shaders (technique 1 and 2)
*** fragment water-ALS-high.frag & secondary_lights.frag
*** Fragment <code>urban-ALS.frag</code> and <code>secondary_lights.frag</code>
** adds uniforms (technique 2)
** Adds uniforms (technique 1 and 2)
 
* <code>water.eff</code>:
== General Comments from Forum Discussion ==
** Inherits properties from <code>terrain-default</code>
** Adds program shaders (technique 1)
*** Fragment <code>water-ALS-high.frag</code> and <code>secondary_lights.frag</code>
** Adds uniforms (technique 1)
* <code>water-inland.eff</code>:
** Inherits properties from <code>terrain-default</code>
** Adds program shaders (technique 2)
*** Fragment <code>water-ALS-high.frag</code> and <code>secondary_lights.frag</code>
** Adds uniforms (technique 2)


== General comments from forum discussion ==
{{cquote|In principle, we always do the same steps in the fragment shaders to determine the color of a pixel:
{{cquote|In principle, we always do the same steps in the fragment shaders to determine the color of a pixel:


texel color - what is the base color of the pixel fully lit and unfogged
* texel color - what is the base color of the pixel fully lit and unfogged
lighting - how is this color changed by the light falling onto that pixel, usually the relation is something like fragColor equals texel * light
* lighting - how is this color changed by the light falling onto that pixel, usually the relation is something like fragColor equals texel * light
fogging - how much is the color hidden by haze, usually the relation is something like gl_FragColor equals mix(fragColor, hazeColor, transmission_factor);
* fogging - how much is the color hidden by haze, usually the relation is something like gl_FragColor equals mix(fragColor, hazeColor, transmission_factor);
what is displayed on the screen in the end is whatever gl_FragColor is set to
what is displayed on the screen in the end is whatever gl_FragColor is set to
But the location where this happens isn't always obvious - often (part) of the light is computed in the vertex shader already, in which case it typically enters the fragment shader as gl_Color.
But the location where this happens isn't always obvious - often (part) of the light is computed in the vertex shader already, in which case it typically enters the fragment shader as gl_Color.


Line 760: Line 850:


<references/>
<references/>
{{WIP|more to follow}}


[[Category:Howto|Shader Programming in FlightGear]]
[[Category:Howto|Shader Programming in FlightGear]]
[[Category:Shader development]]
[[Category:Shader development]]
[[Category: Core developer documentation]]
[[Category: Core developer documentation]]
574

edits

Navigation menu