Shaders Effects

Shader effects let users create their own raster effects. You need two files to get started with shader effects.

To use shader effects, both .gre and .frag files have to be placed in:

The .gre and .frag files have to share a name, e.g., exampleEffect.gre and exampleEffect.frag.

Here you can find some examples

Definitions (*.gre file)

Root Element

<ShaderEffect name="Example Effect">
  <!-- Properties (optional) -->
  <!-- Script (optional) -->
  <!-- glValues (optional) -->
  <!-- Margin (optional) -->
</ShaderEffect>

A ShaderEffect root element has only a name attribute. The name will be visible in Friction interface. The ShaderEffect encloses Properties, a Script, glValues, and a Margin for the effect.

Properties

There are four types of properties:

All types of properties are animatable, meaning their values can change with time. All properties have to be defined inside Properties element, and use the Property tag name.

<ShaderEffect name="Example Effect">
    <Properties>
        <Property name="exampleProperty" nameUI="example property"
                  type="float" min="0" max="100" ini="8" step="1"
                  glValue="true" resolutionScaled="true"/>
        <!-- More Properties (optional) -->
    </Properties>
    <!-- Script (optional) -->
    <!-- glValues (optional) -->
    <!-- Margin (optional) -->
</ShaderEffect>

You can see the resulting interface elements in the screenshot below.

example

Property Attributes

vec2 attributes support values like [x, y] or x expanded to [x, x].

Default Attribute Values

Script (optional)

<ShaderEffect name="Example Effect">
    <!-- Properties -->
    <Script>
        <!-- Obviously, it is just an example,
             it would make more sense to
             multiply the value directly from
             the 'Calculate' portion of the script,
             without the function definition -->
        <Definitions> <!-- Optional -->
            <!-- JavaScript functions for use in Calculate -->
            function exampleFunction(x) {
                return 2*x;
            }
        </Definitions>
      
        <!-- Variables defined with 'extern' can be accessed
             from glValue and Margin 'value' scripts. -->
        <Calculate>
            var exampleLocalVariable = Math.PI * exampleProperty;
            extern exampleExternVariable = exampleFunction(exampleLocalVariable);
        </Calculate>
    </Script>
    <!-- glValues -->
    <!-- Margin (optional) -->
</ShaderEffect>

Script is divided into two portions, both of which should be written in JavaScript:

Values for vec2 properties are passed as arrays [x, y].

Friction provides _eRect, an additional variable you can access directly from Calculate, and glValue and Margin scripts. _eRect corresponds to the bounding rectangle [x, y, width, height] for the object the effect is being applied to. Please note, that the _eRect corresponds to the bounding rectangle prior to applying the Margin. To see how to use _eRect, you can checkout the example eExplode effect and eDots.

glValues (optional)

.gre file:

<ShaderEffect name="Example Effect">
    <Properties>
        <Property name="exampleProperty" nameUI="example property"
                  type="float" min="0" max="100" ini="8" step="1"/>
    </Properties>
    <Script>
        <Definitions>
            function exampleFunction(x) {
                return 2*x;
            }
        </Definitions>
        <Calculate>
            var exampleLocalVariable = Math.PI * exampleProperty;
            extern exampleExternVariable = exampleFunction(exampleLocalVariable);
        </Calculate>
    </Script>
    <glValues>
        <glValue name="exampleValue" type="float" value="exampleExternVariable"/>
    </glValues>
</ShaderEffect>

.frag file:

#version 330 core
layout(location = 0) out vec4 fragColor;

in vec2 texCoord

uniform sampler2D texture;

uniform float exampleValue; // the same name as the glValue

void main(void) {
    fragColor = vec4(color.rgb, exampleValue); 
}

glValues have no representation in the user interface. Instead, they let you pass variables you defined as extern, in the Calculate portion of the Script, to the fragment shader.

Attributes

Margin

Some effects might need to expand the texture size, e.g., blur effects require additional space depending on the radius. Friction will expand the texture for you, all you have to do is define the Margin.

<ShaderEffect name="Example Blur">
    <Properties>
        <Property name="blurRadius" nameUI="blur radius"
                  type="float" min="0" max="100" ini="0" step="1"
                  glValue="true" resolutionScaled="true"/>
    </Properties>
    <Margin value="blurRadius"/>
</ShaderEffect>

Margin example

The Margin only has the value attribute. All variables defined as ‘extern’ in the Calculate portion of the Script are available to the Margin along with all the Property values. The Margin can be defined with four values [left, top, right, bottom], with two values [horizontal, vertical], which translates to [horizontal, vertical, horizontal, vertical], or with a single value margin, which translates to [margin, margin, margin, margin]. To see how to use Margin, you can checkout the example eExplode effect.

Fragment Shader (*.frag file)

multiplyRed.gre file:

<ShaderEffect name="Multiply Red">
    <Properties>
        <Property name="red" type="float" min="0" max="1"
                  ini="0" step="0.1" glValue="true"/>
    </Properties>
</ShaderEffect>

multiplyRed.frag file:

// Friction uses OpenGL 3.3
#version 330 core
// output color
layout(location = 0) out vec4 fragColor;

// processed texture coordinate, from the vertex shader
in vec2 texCoord;

// texture provided by Friction
uniform sampler2D texture;
// the value for the 'red' property
uniform float red;

void main(void) {
    // texture pixel color at the coordinate
    vec4 color = texture2D(texture, texCoord);
    // assign value to the output color,
    // multiply red by the 'red' property value
    fragColor = vec4(color.r * red, color.g, color.b, color.a); 
}

Result:

exampleRed

If you are familiar with fragment shaders, the example above should be easy to understand. Friction provides a texture uniform sampler2D texture;, values for all Properties with glValue="true", and all glValues. The type of the value passed to the fragment shader is the same, as the type of the Property/glValue: