Wallpaper Engine

Wallpaper Engine

78 ratings
Advanced: Creating custom shaders
By Biohazard
This guide will show you how to use custom shaders in Wallpaper Engine.
   
Award
Favorite
Favorited
Unfavorite
NEW DOCUMENTATION OUT
Prerequisites
You need to be familiar with shader programming. While GLSL is being used by Wallpaper Engine, you should be able to start working if you know HLSL or Cg instead.
Introduction
Each shader is split into a .vert and a .frag file, which represent the vertex and fragment/pixel shader respectively. You have to supply both files in the shaders/ directory of your project to create a functional shader. To use it, either choose it from the import dropdown in the editor or edit your existing material files to use your shader (the name in the material files needs to match the filename without extension).

You can use the following minimal examples to get started on a new shader:

myshader.vert
attribute vec3 a_Position; attribute vec2 a_TexCoord; uniform mat4 g_ModelViewProjectionMatrix; varying vec2 v_TexCoord; void main() { gl_Position = mul(vec4(a_Position, 1.0), g_ModelViewProjectionMatrix); v_TexCoord = a_TexCoord; }

myshader.frag
uniform sampler2D g_Texture0; varying vec2 v_TexCoord; void main() { gl_FragColor = texture2D(g_Texture0, v_TexCoord); }
GLSL differences
You can expect standard GLSL syntax to work for the most part, but there are a few caveats to take into account.

  • Don't use attributes/varyings in global functions, pass them as function parameters (HLSL uses an input structure which is not global).
  • Use frac instead of fract.
  • Instead of using certain type constructors for explicit conversions like vec3(1.0), use CAST3(1.0). In HLSL these constructors are invalid and C-style casts are used instead like (float3)1.0, which in turn do not work in GLSL. So CAST3, CAST2, CAST4, CAST3x3 will use the specific for each platform.
  • The saturate function is available to clamp a value into [0, 1] range.
  • You can include files with #include "FILENAME".

If you absolutely need to write platform specific code, you can distinct between GLSL and HLSL by using #if GLSL or #if HLSL.
Attributes
Predefined attributes define the per vertex data. By definition, attributes are only available in the vertex shader. The ones commonly used are the following:

  • attribute vec3 a_Position;
  • attribute vec2 a_TexCoord;
  • attribute vec3 a_Normal; // If model was compiled with "normals"
  • attribute vec4 a_Tangent4; // If model was compiled with "tangentspace". This contains tangent and bitangent sign. Decompress with BuildTangentSpace().
Uniforms
To get a complete list over all available uniforms, refer to assets/shaders/readme.txt. Uniforms are either globally defined and available in every shader or defined by you and exposed to the editor or the end user.

For example, commonly required matrix uniforms to transform a model into the world, view and projection are:

  • uniform mat4 g_ModelMatrix;
  • uniform mat4 g_ViewProjectionMatrix;
  • uniform mat4 g_ModelViewProjectionMatrix;
  • uniform mat4 g_ModelViewProjectionMatrixInverse;

And a list of predefined texture uniforms can be used to sample the textures from the material:

  • uniform sampler2D g_Texture0;
  • uniform sampler2D g_Texture1;
  • uniform sampler2D g_Texture2;
  • ...
  • uniform sampler2D g_Texture7;

To expose a custom uniform to the editor, you need to add a JSON snippet as a comment right at the end of the uniform. A custom color would look like this, for example:

uniform vec3 gu_MyTintColor; // {"material":"Tint", "type": "color", "default":"1 0 0"}

The following JSON options exist:

  • material (STRING): Set "material": "MY MATERIAL NAME" to define the name shown in the editor.
  • type (STRING): Set "type": "color" for vec3 uniforms to enable the color picker. Otherwise leave it out to use a slider or text boxes to enter values.
  • default (VARYING): Set "default": "1 0 0" to define a default color (red) or "default": 1.0 to define a default float.
  • range (ARRAY of FLOAT): Set "range": [-1.0, 1.0] to overwrite the slider range. It will use 0 to 1 if you omit it.
Combos
You can use arbitrary preprocessor macros in your code and toggle them in your material file, effectively allowing you to share shaders with different/optional features between multiple materials. For example, if you want to use a certain lighting model on one part of your object but not on the other, you can use #if MYCOMBONAME / #endif around the code you want to toggle. Then add a combos object into your material file that sets MYCOMBONAME to 1 like this:

{ "passes" : [ { "combos" : { "MYCOMBONAME" : 1 }, "shader" : "generic", "textures" : [ "pistols/Pistol0101_D" ] } ] }
Error reporting
Any shader compile errors will be reported by the editor in form of a toast:



Please note that the line number does not match the actual line in your code. As the shader is being translated into HLSL and includes are resolved beforehand, the line numbers can wildly mismatch. In the future you will be able to inspect the translated source code and figure out the issue from there.