Version

A surface shader holds all the variants of a shader required to fully draw a surface. This includes all forward rendering passes such as the ambient pass, the light contribution pass or the shadow map creation pass.

The surface shader declaration syntax is identical to a normal shader declaration (see Shader). A surface shader can access the engine state values like a normal shader.

The only difference with a shader is that instead of providing a single color output, the surface shader provides output values for several surface attributes.

See the SurfaceShader page for the API reference.

Surface drawing attributes

The full surface shader logic is stored in the core resource file pkg.core/shaders/surface.i. It expects specific output from each shader stage to correctly render the surface at each stage of the drawing pipeline.

Vertex output

A surface shader vertex program can output to the following attributes:

Symbol Type Default Description
%position% vec3 vPosition (see Shader) Vertex position in model space
%normal% vec3 vNormal (see Shader) Vertex normal in model space

Pixel output

The surface final appareance is controlled by the pixel program by writing to the following attributes:

Symbol Type Default Description
%diffuse% vec3 vec3(1, 1, 1) Diffuse color
%specular% vec3 vec3(0, 0, 0) Specular color
%glossiness% float 0.25 Specular exponent
%constant% vec3 vec3(0, 0, 0) Constant color
%opacity% float 1.0 Opacity
%normal% vec3 vNormalViewMatrix * vNormal (see Shader) Normal in view space

If an attribute is not written to, its default value is used.

Notes

  • When a surface shader is compiled with skinning support USE_SKINNING is defined and the skinning matrix can be accessed from the vertex and pixel shader through the mat4 vSkinMatrix; variable.
  • Writing to %out.position% in the vertex shader means that you take care of outputting the correctly transformed vertex by yourself.

Surface description

Since drawing a surface is usually done in several passes it is impractical to directly specify low-level parameters such as the blending operator to control its appearance. Properly drawing the surface with this level of control would require different values for each render pass and a thorough understanding of the pass itself.

The surface section further describes the surface appearance so that the render system can select appropriate render states for each pass it needs to draw.

Declare this section at the global scope.

// Surface with alpha blending and no Z-write.
surface {
  blend: alpha,
  z-write: false
}

Note: Do not forget to output to the %opacity% surface attribute in your shader when using alpha blending.

The following surface control parameters are available:

Parameter Values Default Description
blend opaque, alpha, additive opaque Blending mode of the surface with the screen content.
z-write true, false true Drawing the surface writes to the depth buffer.
z-test true, false true Perform depth test when drawing the surface.
alpha-test true, false true Skip surface pixels when alpha is below the alpha threshold.
alpha-threshold - 0.5 The alpha value below which a surface pixel is not drawn.
double-sided true, false false Perform back-face culling when drawing the surface.
cast-shadow true, false true The surface casts shadow.
skinned true, false false Surface uses GPU skinning.
terrain true, false false Surface is used to render a terrain heightmap.

Specific surface variables

Depending on the surface description (see the surface section), additional variables are available to use when writing your surface shader.

Description Variable Type Description
terrain TerrainUV vec2 Terrain UV coordinates.

Example

A surface shader providing a single diffuse attribute.

// Surface single texture shader.
in { tex2D diffuse_tex; }

variant {
  vertex {
    out { vec2 v_uv; }

    source %{
      // read from the UV channel 0 and send to the pixel shader
      v_uv = vUV0;
    %}
  }

  pixel {
    source %{
      // sample the texture and output as the surface diffuse color
      %diffuse% = texture2D(diffuse_tex, v_uv).xyz;
    %}
  }
}