====== Shader ======
This article is about shader programs. Shaders are defined in [[modding:ScriptedInfo]] files named **shaders.dei**.
===== Variables =====
==== Declaring a variable ====
Shader variables are uniforms, i.e, constants that can be changed at runtime without recompiling the shader.
Variables must be declared separately from their declaration in the shader source code. This lets Doomsday know which uniforms are intended to be externally modifiable. Also, Doomsday can initialize the variables to a specified initial values — useful when the shader is used in a context where the value of a particular variable is not specified.
The variable declaration looks like this:
variable uVariableName { value = 0.0 }
The given initial value may either be a single number or an array:
* ''value = 0'' → float
* ''value <0, 0>'' → vec2
* ''value <0, 0, 0>'' → vec3
* ''value <0, 0, 0, 0>'' → vec4
The corresponding uniform in the shader source code would look like:
uniform highp float uVariableName;
===== Built-in variables =====
The renderer provides built-in variables that can be used in any shader. To use one of these, the shader definition needs to declare the variable but omit any default value initializers. For example:
shader my_custom_shader {
variable uMapTime {}
...
The GLSL source code also needs to declare a uniform with the exact same name, using the type from the table below.
^ Variable ^ Type ^ Description |
| ''uMapTime''| float | Time in the current map, in seconds since the map was started. Does not increase while the game is paused. |
| ''uProjectionMatrix'' | mat4 | Transformation from 3D view space (eye at origin) to 2D screen space. The value of the uniform is updated once per frame/eye. |
| ''uViewMatrix'' | mat4 | Transforms from world space to view space. VGA aspect correction is included. The value of the uniform is updated once per frame/eye. |
==== Model renderer uniforms ====
In addition to the variables above, the model renderer automatically provides a set of uniforms for model shaders. To use these, one simply needs to declare the variable in GLSL and use it (no declarations in Doomsday's shader definition are needed). The values are updated for each model that is rendered.
^ Uniform ^ Type ^ Description |
| ''uMvpMatrix'' | mat4 | The combined model-view-projection matrix. |
| ''uWorldMatrix'' | mat4 | Transforms from model space to world space. |
| ''uReflectionMatrix'' | mat4 | Rotation-only matrix for orienting a reflection cube map around the model. |
| ''uEyePos'' | vec3 | Model space eye position. |
| ''uAmbientLight'' | vec3 | Ambient light intensity (RGB). |
| ''uLightDirs'' | vec3[4] | Model space light directions. |
| ''uLightIntensities'' | vec4[4] | Light intensities (RGBA). A is the maximum of the R, G and B components. |
===== Preprocessor definitions =====
A shader definition may specify a dictionary of macros that will apply to both vertex and fragment shaders in the shader program.
For example, the "model.skeletal.generic" shader defines the macros PREDEF_TRANSFORM_UV, PREDEF_TRANSFORM_EMISSION, and PREDEF_TRANSFORM_ALPHA. These can then be used to modify the texture UV, emission color, and surface opacity.
defines $= {'PREDEF_TRANSFORM_UV(uv)': 'uv = uv + vec2(0.5, 0.0)',
'PREDEF_TRANSFORM_EMISSION(color)': 'color.r *= 2.0',
'PREDEF_TRANSFORM_ALPHA(alpha)': ''}
This becomes particularly useful when combined with custom GLSL functions. Additional functions can be included as separate source files. Below is an example of using Doomsday Script to modify an inherited shader.
shader model.thing.misc3.uvscroll {
inherits: model.skeletal.unlit.diffuse
script {
self.include.fragment += ['uvscroll.glsl']
self.defines['PREDEF_TRANSFORM_UV(uv)'] = 'uv = scrolledUV(uv, uMapTime)'
}
}
===== Example =====
Below is an example that demonstrates the use of a shader definition:
* Declaring variables and their initial values.
* Defining which texture maps are expected to be present, and therefore are available in the shader via attributes.
* Including GLSL source files.
* The shader source code.
shader "example" {
variable uAlphaLimit { value = 0 }
variable uAlpha { value = 1.0 }
variable uColor { value <1, 1, 1> }
variable uOffsetUV { value <0, 0> }
# Mapping when used with ModelDrawable.
textureMapping
include.vertex
vertex = "/* put GLSL source code here */"
include.fragment
fragment = "
uniform highp float uAlphaLimit;
uniform highp float uAlpha;
uniform highp vec3 uColor; // diffuse color multiplier
uniform highp vec2 uOffsetUV;
/* put GLSL source code here */"
}