What's New in Flame FX > Matchbox >
Creating Your Own Matchbox Effects

A great benefit of working with the Matchbox tool is being able to create your own effects, depending on your particular needs. Creating a Matchbox shader can be as simple as copying and pasting GLSL code snippets, or can be complex multipass effects with multiple inputs and dozens of UI elements. For example, here is the contents of a simple Add effect:

    uniform sampler2D input1, input2;
    uniform float adsk_result_w, adsk_result_h;

    void main()
    {
       vec2 coords = gl_FragCoord.xy / vec2( adsk_result_w, adsk_result_h );
       vec3 sourceColor1 = texture2D(input1, coords).rgb;
       vec3 sourceColor2 = texture2D(input2, coords).rgb;

       gl_FragColor = vec4( sourceColor1+sourceColor2, 1.0 );
    }

Here's a quick high-level workflow to follow when creating Matchbox shaders:

1. Write or copy/paste GLSL fragment shader code.
2. Use the provided command line tool to test the shader.
3. Edit the Shader Description output from the test tool.
4. Package the XML and GLSL code together for use in Flame.

Writing and Testing GLSL Fragment Shader Code

You can repurpose existing fragment shader code, or create an effect specific to your needs. In either case, you can use the test_shader utility to validate and debug your code, and optionally help you design user interface elements in a sidecar XML file. The test_shader utility also has an extensive Help file that lists the available uniforms (including a number of adsk_ custom uniforms) and XML structure.

The test_shader utility can be found in /usr/discreet/<product home>/bin. To access the Help file, from the bin directory, type test_shader --help.

To create and test a fragment shader:

1. Write or copy your fragment shader code in a text editor.
2. Save the file with the extension .glsl. For example, here is the contents of a scaling effect:

       1 uniform float size;
       2 uniform sampler2D myInputTex;
       3
       4 void main (void) {
       5         vec4 tex0 = texture2D(myInputTex, gl_TexCoord[0] * size);
       6         gl_FragColor = vec4 (tex0.rgb, 1.0);
       7 }

3. Run your code through the test utility. For example, test_shader scale.glsl produces this result:

       0(5) : warning C7011: implicit cast from "vec4" to "vec2"

        XML :
        <ShaderNodeDescription Description="" Name="Preset Name">
          <Shader Index="1">
             <Uniform RepeatMode="Off" InterpolationMode="Linear" Type="sampler2D" Tooltip="" Name="myInputTex">
             </Uniform>
             <Uniform DisplayName="size" Type="float" Name="size">
                <SubUniform Inc="0.01" Max="1000000.0" Min="-1000000.0" Default="0.0" Row="0" Col="0" Page="0" Tooltip="" Name="size">
                </SubUniform>
             </Uniform>
          </Shader>
          <Page Name="Page 1" Page="0">
             <Col Name="Column 1" Col="0" Page="0">
             </Col>
          </Page>
       </ShaderNodeDescription>

   In this case, the first line displays a compilation warning that you might want to fix. In some cases, you'll receive errors that need to be fixed for the shader to work properly in Flame.

4. Fix any errors, and rerun the code through the test_shader utility.
5. Optional: Use the XML information in the test_shader output to help you set up the UI of the effect. This can be especially useful if different users are going to be working with these effects.

   Simply copy the XML shader node description section of the test output into a new file and save it using the same name, but with an .xml extension. In our example, you can edit scale.xml to add default values, better names for inputs and other UI elements, and even tooltips to help the user (see the bold sections below):

       <ShaderNodePreset SupportsAdaptiveDegradation="0" Description="" Name="Next Generation Scaling">
          <Shader OutputBitDepth="Output" Index="1">
             <Uniform Index="0" NoInput="Error" Tooltip="" DisplayName="Front" Mipmaps="False" GL_TEXTURE_WRAP_T="GL_REPEAT" GL_TEXTURE_WRAP_S="GL_REPEAT" GL_TEXTURE_MAG_FILTER="GL_LINEAR" GL_TEXTURE_MIN_FILTER="GL_LINEAR" Type="sampler2D" Name="myInputTex">
             </Uniform>
             <Uniform ResDependent="None" Max="100.00" Min="-100.00" Default="0.0" Inc="0.01" Tooltip="Displays the percentage of scaling applied to the image." Row="0" Col="0" Page="0" DisplayName="size" Type="float" Name="Scale">
             </Uniform>
          </Shader>
          <Page Name="Page 1" Page="0">
             <Col Name="Effect Settings" Col="0" Page="0">
             </Col>
          </Page>
       </ShaderNodePreset>

6. Add your .glsl and optional sidecar .xml file to the same directory. The existing shader example files are located in /usr/discreet/<product home>/matchbox.
7. Try your effect in Smoke or Flame.

Creating Multipass Shaders

In order to build more efficient, complex, or sophisticated effects, you can split your effects into multiple passes. In order to do this, you can separate your effect into multiple .glsl files using advanced adsk_ uniforms. For example, the existing Median Filter preset consists of MedianFilter.1.glsl and MedianFilter.2.glsl. In this case, when selecting this effect from the Load Shaders browser in Flame, you need to select the root group MedianFilter.glsl file to incorporate all of the passes as one effect.

Optional: Creating Browser Proxy Files

Along with the .glsl and optional .xml files that comprise a fragment shader, you can also create a file that can display a proxy of your effect in the Load Shaders browser. You can use Flame to create a proxy of your effect, but if you don't have access to Flame, or want to create proxies programmatically, you can use the following header (byteswap). The standard width and height of the proxy is 126x92, and the file is RGB 8-bit. Save your proxy files as .p, and place them in the same folder as your .glsl and .xml files of the same name.

    typedef struct {
            unsigned short Magic;
            float  Version;
            short  Width;
            short  Height;
            short  Depth;
            float  Unused [ 6 ];
    } LibraryProxyHeaderStruct;

    #define PROXY_MAGIC 0xfaf0
    #define PROXY_VERSION 1.1f
    #define PROXY_DEPTH 130