Writing a Shader

Shader Language Overview

Harfang uses bgfx as its rendering system, the cross-platform shader language is based on GLSL with a few key differences:

  • No bool/int uniforms, all uniforms must be float.
  • Attributes and varyings can be accessed only from main() function.
  • Must use SAMPLER2D/3D/CUBE/etc. macros instead of sampler2D/3D/Cube/etc. tokens.
  • Must use vec2/3/4_splat(<value>) instead of vec2/3/4(<value>).
  • Must use mtxFromCols/mtxFromRows when constructing matrices in shaders.
  • Must use mul(x, y) when multiplying vectors and matrices.
  • Must use varying.def.sc to define input/output semantic and precision instead of using attribute/in and varying/in/out.
  • $input/$output tokens must appear at the begining of shader.

Data Flow

In a shader, vertex attributes such as position or normal are send to the vertex shader as a stream of attributes. The vertex shader outputs are then interpolated across the rendered primitive and passed to the fragment shader as varyings to compute the final pixel color.

Writing a Shader

A shader is composed of 3 files: a definition file, the vertex and fragment source files:

  • example_vs.sc: Source for the vertex program.
  • example_fs.sc: Source for the fragment program.
  • example_varying.def: Shader definition file.

Both the vertex and fragment program must declare a main function.

void main() { ... }

The shader definition file must list all inputs and outputs of the shader programs and associate them with standard semantics like POSITION or NORMAL (see HLSL Semantics for a complete list).

vec3 vNormal : NORMAL;

vec3 a_position  : POSITION;
vec3 a_normal : NORMAL;

In the vertex program use $input to declare an attribute and $output to declare a varying. $input/$output tokens must appear at the begining of the program.

By convention attributes must be named one of the following: a_position, a_normal, a_tangent, a_bitangent, a_color0, a_color1, a_color2, a_color3, a_indices, a_weight, a_texcoord0, a_texcoord1, a_texcoord2, a_texcoord3, a_texcoord4, a_texcoord5, a_texcoord6, a_texcoord7, i_data0, i_data1, i_data2, i_data3 or i_data4.

The following vertex program declares that it takes two attributes as input and outputs to a single varying.

$input a_position, a_normal
$output vNormal

#include <bgfx_shader.sh>

void main() {
	vNormal = mul(u_model[0], vec4(a_normal * 2.0 - 1.0, 0.0)).xyz;
	gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));

Note: Attributes and varyings can only be accessed from the shader main function.

Outputs from the vertex program then become inputs to the fragment program. The fragment program outputs its result to standard GLSL variables such as gl_FragColor (see GLSL Language Specifications).

$input vNormal

#include <bgfx_shader.sh>

void main() {
	vec3 normal = normalize(vNormal);
	gl_FragColor = vec4(normal.x, normal.y, normal.z, 1.0);

Passing Constants to a Shader

Constant values can be passed to a shader programs by using uniforms. This is done using UniformSetValue and UniformSetTexture.

Predefined Uniforms

The bgfx_shader.sh include file defines the following predefined uniforms.

vec4u_viewRectView rectangle for current view, in pixels. (x, y, width, height)
vec4u_viewTexelInverse width and height. (1.0 / width, 1.0 / height, undef, undef)
mat4u_viewView matrix.
mat4u_invViewInverse view matrix.
mat4u_projProjection matrix.
mat4u_invProjInverse projection matrix.
mat4u_viewProjConcaneted view projection matrix.
mat4u_invViewProjConcatenated inverted view projection matrix.
mat4u_model[BGFX_CONFIG_MAX_BONES]Array of model matrices.
mat4u_modelViewConcatenated model view matrix, only the first model matrix from array is used.
mat4u_modelViewProjConcatenated model view projection matrix.
vec4u_alphaRefAlpha reference value for alpha test.