A collection of tools for Foundry Mari that make it easy to produce CG textures. Here you are going to find:

If you want to know more, please consider vising the repository.

1. Adjustment Shaders

Layers that provide adjustment to other layers.

1.1. Normalize

This first example, shows a pretty simple adjustment layer that normalizes the colors of the stack below.

                
                  <!-- MariNormalize.xml -->
                  <Node>
                    <ID>customNormalizeAdjustment</ID>
                    <Tags>
                      <Tag>_adjustment</Tag>
                    </Tags>
                    <Inputs>
                      <Input Name="Input"></Input>
                    </Inputs>
                    <Attributes>
                      <Attribute></Attribute>
                    </Attributes>
                    <Contexts>
                      <Context Type="GLSL">
                        <Shader>
                          <Inputs>
                            <Input name="Input"><Default>vec4(1, 1, 1, 1)</Default></Input>
                          </Inputs>
                          <Body><![CDATA[
                            Output.rgb = normalize(#Input.rgb);
                            Output.a = #Input.a;
                          ]]></Body>
                        </Shader>
                      </Context>
                    </Contexts>
                  </Node>
                
              

To register this shader, just include the following piece of code in the start-up script called init.py.

                
                  import mari

                  mari.gl_render.registerCustomAdjustmentLayerFromXMLFile(
                    'Custom-Shaders/Normalize',
                    'path/to/adjustment/MariNormalize.xml'
                  )
                
              

1.2. Saturation

For this second example, we are going to declare custom functions to be used in the shader.

Firstly, we have to declare the header file with the extension .glslh.

                
                  // adjustmentUtils.glslh

                  // ! Utils
                  float avrValue(vec3 input);
                  float avrValue(vec4 input);
                  float maxValue(vec3 input);
                  float maxValue(vec4 input);
                  float minValue(vec3 input);
                  float minValue(vec4 input);

                  // ! Saturation functions
                  float ccir601Value(vec3 input);
                  float ccir601Value(vec4 input);
                  float rec709Value(vec3 input);
                  float rec709Value(vec4 input);
                  float rec2020Value(vec3 input);
                  float rec2020Value(vec4 input);
                
              

The next step is to declare the function code file with the extension .glslc.

                
                  // adjustmentUtils.glslc

                  #version 330

                  // ! include | adjUtils.glslh

                  // ! Utils

                  float avrValue(vec3 input)
                  {
                    return (input.r + input.g + input.b) / 3;
                  }

                  float avrValue(vec4 input)
                  {
                    return (input.r + input.g + input.b) / 3;
                  }

                  float maxValue(vec3 input)
                  {
                    return max(max(input.r, input.g), input.b);
                  }

                  float maxValue(vec4 input)
                  {
                    return max(max(input.r, input.g), input.b);
                  }

                  float minValue(vec3 input)
                  {
                    return min(min(input.r, input.g), input.b);
                  }

                  float minValue(vec4 input)
                  {
                    return min(min(input.r, input.g), input.b);
                  }

                  // ! Saturation functions

                  float ccir601Value(vec3 input)
                  {
                    float kb = 0.114;
                    float kr = 0.299;
                    float kg = 1 - kr - kb;
                    return kr * input.r + kg * input.g + kb * input.b;
                  }

                  float ccir601Value(vec4 input)
                  {
                    float kb = 0.114;
                    float kr = 0.299;
                    float kg = 1 - kr - kb;
                    return kr * input.r + kg * input.g + kb * input.b;
                  }

                  float rec709Value(vec3 input)
                  {
                    float kb = 0.0722;
                    float kr = 0.2126;
                    float kg = 1 - kr - kb;
                    return kr * input.r + kg * input.g + kb * input.b;
                  }

                  float rec709Value(vec4 input)
                  {
                    float kb = 0.0722;
                    float kr = 0.2126;
                    float kg = 1 - kr - kb;
                    return kr * input.r + kg * input.g + kb * input.b;
                  }

                  float rec2020Value(vec3 input)
                  {
                    float kb = 0.0593;
                    float kr = 0.2627;
                    float kg = 1 - kr - kb;
                    return kr * input.r + kg * input.g + kb * input.b;
                  }

                  float rec2020Value(vec4 input)
                  {
                    float kb = 0.0593;
                    float kr = 0.2627;
                    float kg = 1 - kr - kb;
                    return kr * input.r + kg * input.g + kb * input.b;
                  }
                
              

Now we can finally write the shader and use the custom functions we declared.

                
                  <!-- MariSaturation.xml -->
                  <Node>
                    <ID>customSaturationAdjustment</ID>
                    <Tags>
                      <Tag>_adjustment</Tag>
                    </Tags>
                    <Inputs>
                      <Input Name="Input"></Input>
                    </Inputs>
                    <Attributes>
                      <Attribute Name="type" PrettyName="luminance type" Type="stringlist">maximum,average,maximum,minimum,ccir601,rec709,rec2020</Attribute>
                      <Attribute Name="saturation" Type="double" Min="0" Max="4">1</Attribute>
                      <Attribute Name="absolute" PrettyName="absolute value" Type="bool">false</Attribute>
                    </Attributes>
                    <Contexts>
                      <Context Type="GLSL">
                        <Shader>
                          <Inputs>
                            <Input name="Input"><Default>vec4(1, 1, 1, 1)</Default></Input>
                          </Inputs>
                          <Body><![CDATA[
                            float value;
                            switch($type){
                              case 0:
                                value = avrValue(#Input);
                                break;
                              case 1:
                                value = maxValue(#Input);
                                break;
                              case 2:
                                value = minValue(#Input);
                                break;
                              case 3:
                                value = ccir601Value(#Input);
                                break;
                              case 4:
                                value = rec709Value(#Input);
                                break;
                              case 5:
                                value = rec2020Value(#Input);
                                break;
                              default:
                                Output.rgb = vec3(1);
                            }
                            Output.r = #Input.r*$saturation + value*(1 - $saturation);
                            Output.g = #Input.g*$saturation + value*(1 - $saturation);
                            Output.b = #Input.b*$saturation + value*(1 - $saturation);
                            Output.a = 1;
                            if($absolute){
                              Output = abs(Output);
                            }
                          ]]></Body>
                        </Shader>
                      </Context>
                    </Contexts>
                  </Node>
                
              

To register this shader, just include the following piece of code in the start-up script called init.py.

                
                  import mari

                  mari.gl_render.registerCustomHeaderFile(
                    'ADJUSTMENT_UTILS_GLSLH',
                    'path/to/adjustment/lib/adjustmentUtils.glslh'
                  )
                  mari.gl_render.registerCustomCodeFile(
                    'ADJUSTMENT_UTILS_GLSLC',
                    'path/to/adjustment/lib/adjustmentUtils.glslc'
                  )

                  mari.gl_render.registerCustomAdjustmentLayerFromXMLFile(
                    'Custom-Shaders/Saturation',
                    'path/to/adjustment/MariSaturation.xml'
                  )