OCIO and MaterialX¶

This notebook will cover one workflow of using OCIO to generate code for MaterialX. We will be using the API based on OCIO 2.2 and above (released in October 2022).

The aim of this notebook is to go over how OCIO can be used to generate "implementations". The longer term MaterialX aim is to generate functional node graphs. This book will cover the setup required for generation, but can only show how source code implementation generation can be performed at the curren time.

The workflow covered is the "green" parts in this overall workflow diagram: No description has been provided for this image

If / when graph generation is possible source code implementations can be swapped out for graph implementations.

The breakdown is as follows: library (cmlib)

  1. OCIO setup
  2. Setting up OCIO configurations and getting available color spaces.
  3. Setting up OCIO "processors" for generating color transforms
  4. Generating source code implementations
  5. Creating MaterialX implementations and definition wrappers for color3 and color4 variants.
  6. Add definitions and implementations to the "standard" transform

For further OCI there is a fair bit of documentation available with a useful starting place here

Setup¶

OpenColorIO is available as a pre-built Python package on PyPi here

pip can be used to install the package which is called PyOpenColorIO

User can also build OpenColorIO by cloning the GitHub repository.

For the purposes of generating color transform implementation, most of the build options can be disabled. For For building and installing the Python package, make sure that the appropriate build option is set (current OCIO_BUILD_PYTHON, OCIO_INSTALL_EXT_PACKAGES respectively).

An example set of options is given here:

-DOPENIMAGEIO_INCLUDE_DIR="" -DOPENIMAGEIO_LIBRARY="" -DOCIO_BUILD_DOCS=OFF -DBUILD_SHARED_LIBS=OFF -DOCIO_BUILD_TESTS=ON -DOCIO_BUILD_GPU_TESTS=OFF -DOCIO_BUILD_PYTHON=1 -DOCIO_BUILD_JAVA=0 -DOCIO_INSTALL_EXT_PACKAGES=ALL -DOCIO_BUILD_APPS=0 -DOCIO_BUILD_NUKE=0

A third alternative is to use a pre-built Python package which comes with another installation such as a DCC. A check should be made to not inadvertently use the incorrect version of the package.

For this book, we install from PyPi.

In [1]:
# Package install
#pip install OpenColorIO

Here we import PyOpenColorIO and MaterialX.

In [2]:
# Import OCIO package
import PyOpenColorIO as OCIO
import MaterialX as mx

print('OCIO version:', OCIO.GetVersion())
print('MaterialX version:', mx.getVersionString())
OCIO version: 2.4.1
MaterialX version: 1.39.2

Configurations¶

As of version 2.2, ACES Cg Config and ACES Studio Config are packaged with OCIO, meaning that they are available to use without having to download them separately. The getBuildInConfigs() API is explained here

In [3]:
# Get the OCIO built in configs
registry = OCIO.BuiltinConfigRegistry().getBuiltinConfigs()

This items return canned be scanned and the appropriate configuration instantiated using CreateFromBuiltInConfig() In the following example we built a dictionary of configs along with the available color spaces.

In [4]:
# Create a dictionary of configs
configs = {}
for item in registry:
    # The short_name is the URI-style name.
    # The ui_name is the name to use in a user interface.
    short_name, ui_name, isRecommended, isDefault = item

    # Don't present built-in configs to users if they are no longer recommended.
    if isRecommended:
        # Create a config using the Cg config
        config = OCIO.Config.CreateFromBuiltinConfig(short_name)
        colorSpaces = None
        if config:
            colorSpaces = config.getColorSpaces()

        if colorSpaces:
            configs[short_name] = [config, colorSpaces]

# Print the configs
for config in configs:
    print('Built-in config:', config)
    csnames = configs[config][0].getColorSpaceNames()
    print('- Number of color spaces: %d' % len(csnames))
    #for csname in csnames:
    #    print('  -', csname)
Built-in config: cg-config-v2.2.0_aces-v1.3_ocio-v2.4
- Number of color spaces: 23
Built-in config: studio-config-v2.2.0_aces-v1.3_ocio-v2.4
- Number of color spaces: 54

A more direct way to get the desired config is to call CreateFomFile with the appropriate built in path. In this case we get the ACES Cg Config.`

In [5]:
acesCgConfigPath = 'ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1'
builtinCfgC = OCIO.Config.CreateFromFile(acesCgConfigPath)
print('Built-in config:', builtinCfgC.getName())
csnames = builtinCfgC.getColorSpaceNames()
print('- Number of color spaces: %d' % len(csnames))
Built-in config: cg-config-v1.0.0_aces-v1.3_ocio-v2.1
- Number of color spaces: 14

Color Spaces¶

To check what color space identifiers can be used we print out each color space name along with any aliases by calling getAliases() on each color space.

In [6]:
from IPython.display import display_markdown

title = '| Configuration | Color Space | Aliases |\n'
title = title + '| --- | --- | --- |\n'

rows = ''
for c in configs:
    config = configs[c][0]
    colorSpaces = configs[c][1]
    for colorSpace in colorSpaces:
        aliases = colorSpace.getAliases()
        rows = rows + '| ' + c + ' | ' + colorSpace.getName() + ' | ' + ', '.join(aliases) + ' |\n'

md = '<details><summary>Color Spaces</summary>\n\n' + title + rows + '</details>'
display_markdown(md, raw=True)
Color Spaces
Configuration Color Space Aliases
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 sRGB - Display srgb_display
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Display P3 - Display displayp3_display
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Rec.1886 Rec.709 - Display rec1886_rec709_display
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Rec.2100-PQ - Display rec2100_pq_display
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 ST2084-P3-D65 - Display st2084_p3d65_display
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 P3-D65 - Display p3d65_display
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 ACES2065-1 aces2065_1, aces, ACES - ACES2065-1, lin_ap0, lin_ap0_scene
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 ACEScc ACES - ACEScc, acescc_ap1
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 ACEScct ACES - ACEScct, acescct_ap1
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 ACEScg ACES - ACEScg, lin_ap1, lin_ap1_scene
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 sRGB Encoded Rec.709 (sRGB) srgb_encoded_rec709_srgb, Utility - sRGB - Texture, srgb_texture, srgb_rec709_scene, Input - Generic - sRGB - Texture, sRGB - Texture, srgb_tx
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 1.8 Encoded Rec.709 g18_encoded_rec709, Utility - Gamma 1.8 - Rec.709 - Texture, g18_rec709, Gamma 1.8 Rec.709 - Texture, g18_rec709_tx, g18_rec709_scene
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 2.2 Encoded Rec.709 g22_encoded_rec709, Utility - Gamma 2.2 - Rec.709 - Texture, g22_rec709, Gamma 2.2 Rec.709 - Texture, g22_rec709_tx, g22_rec709_scene
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 2.4 Encoded Rec.709 g24_encoded_rec709, g24_rec709, rec709_display, Utility - Rec.709 - Display, Gamma 2.4 Rec.709 - Texture, g24_rec709_tx
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 sRGB Encoded P3-D65 srgb_encoded_p3d65, srgb_p3d65, srgb_displayp3, srgb_p3d65_scene, sRGB Encoded P3-D65 - Texture, srgb_encoded_p3d65_tx
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 2.2 Encoded AdobeRGB g22_encoded_adobergb, adobergb, g22_adobergb_scene
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 sRGB Encoded AP1 srgb_encoded_ap1, srgb_ap1, srgb_ap1_scene, sRGB Encoded AP1 - Texture, srgb_encoded_ap1_tx
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 2.2 Encoded AP1 g22_encoded_ap1, g22_ap1, Gamma 2.2 AP1 - Texture, g22_ap1_tx, g22_ap1_scene
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear Rec.709 (sRGB) lin_rec709_srgb, Utility - Linear - Rec.709, lin_rec709, lin_rec709_scene, lin_srgb, Utility - Linear - sRGB
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear P3-D65 lin_p3d65, Utility - Linear - P3-D65, lin_displayp3, lin_p3d65_scene, Linear Display P3
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear AdobeRGB lin_adobergb, Utility - Linear - Adobe RGB, lin_adobergb_scene
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear Rec.2020 lin_rec2020, Utility - Linear - Rec.2020, lin_rec2020_scene
cg-config-v2.2.0_aces-v1.3_ocio-v2.4 Raw Utility - Raw, none
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 sRGB - Display srgb_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Display P3 - Display displayp3_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Rec.1886 Rec.709 - Display rec1886_rec709_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Rec.1886 Rec.2020 - Display rec1886_rec2020_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Rec.2100-HLG - Display rec2100_hlg_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Rec.2100-PQ - Display rec2100_pq_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ST2084-P3-D65 - Display st2084_p3d65_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 P3-D60 - Display p3d60_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 P3-D65 - Display p3d65_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 P3-DCI - Display p3_dci_display
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ACES2065-1 aces2065_1, aces, ACES - ACES2065-1, lin_ap0, lin_ap0_scene
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ACEScc ACES - ACEScc, acescc_ap1
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ACEScct ACES - ACEScct, acescct_ap1
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ACEScg ACES - ACEScg, lin_ap1, lin_ap1_scene
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ADX10 Input - ADX - ADX10
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ADX16 Input - ADX - ADX16
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Apple Log apple_log
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear ARRI Wide Gamut 3 lin_arri_wide_gamut_3, Input - ARRI - Linear - ALEXA Wide Gamut, lin_alexawide
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ARRI LogC3 (EI800) arri_logc3_ei800, Input - ARRI - V3 LogC (EI800) - Wide Gamut, logc3ei800_alexawide
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 ARRI LogC4 arri_logc4
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear ARRI Wide Gamut 4 lin_arri_wide_gamut_4, lin_awg4
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 BMDFilm WideGamut Gen5 bmdfilm_widegamut_gen5
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 DaVinci Intermediate WideGamut davinci_intermediate_widegamut
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 CanonLog2 CinemaGamut D55 canonlog2_cinemagamut_d55, Input - Canon - Canon-Log2 - Cinema Gamut Daylight, canonlog2_cgamutday
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 CanonLog3 CinemaGamut D55 canonlog3_cinemagamut_d55, Input - Canon - Canon-Log3 - Cinema Gamut Daylight, canonlog3_cgamutday
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear CinemaGamut D55 lin_cinemagamut_d55, Input - Canon - Linear - Canon Cinema Gamut Daylight, lin_canoncgamutday
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear V-Gamut lin_vgamut, Input - Panasonic - Linear - V-Gamut
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 V-Log V-Gamut vlog_vgamut, Input - Panasonic - V-Log - V-Gamut
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear REDWideGamutRGB lin_redwidegamutrgb, Input - RED - Linear - REDWideGamutRGB, lin_rwg
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Log3G10 REDWideGamutRGB log3g10_redwidegamutrgb, Input - RED - REDLog3G10 - REDWideGamutRGB, rl3g10_rwg
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear S-Gamut3 lin_sgamut3, Input - Sony - Linear - S-Gamut3
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear S-Gamut3.Cine lin_sgamut3cine, Input - Sony - Linear - S-Gamut3.Cine
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear Venice S-Gamut3 lin_venice_sgamut3, Input - Sony - Linear - Venice S-Gamut3
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear Venice S-Gamut3.Cine lin_venice_sgamut3cine, Input - Sony - Linear - Venice S-Gamut3.Cine
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 S-Log3 S-Gamut3 slog3_sgamut3, Input - Sony - S-Log3 - S-Gamut3
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 S-Log3 S-Gamut3.Cine slog3_sgamut3cine, Input - Sony - S-Log3 - S-Gamut3.Cine, slog3_sgamutcine
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 S-Log3 Venice S-Gamut3 slog3_venice_sgamut3, Input - Sony - S-Log3 - Venice S-Gamut3
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 S-Log3 Venice S-Gamut3.Cine slog3_venice_sgamut3cine, Input - Sony - S-Log3 - Venice S-Gamut3.Cine, slog3_venice_sgamutcine
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear BMD WideGamut Gen5 lin_bmd_widegamut_gen5
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear DaVinci WideGamut lin_davinci_widegamut
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 sRGB Encoded Rec.709 (sRGB) srgb_encoded_rec709_srgb, Utility - sRGB - Texture, srgb_texture, srgb_rec709_scene, Input - Generic - sRGB - Texture, sRGB - Texture, srgb_tx
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 1.8 Encoded Rec.709 g18_encoded_rec709, Utility - Gamma 1.8 - Rec.709 - Texture, g18_rec709, Gamma 1.8 Rec.709 - Texture, g18_rec709_tx, g18_rec709_scene
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 2.2 Encoded Rec.709 g22_encoded_rec709, Utility - Gamma 2.2 - Rec.709 - Texture, g22_rec709, Gamma 2.2 Rec.709 - Texture, g22_rec709_tx, g22_rec709_scene
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 2.4 Encoded Rec.709 g24_encoded_rec709, g24_rec709, rec709_display, Utility - Rec.709 - Display, Gamma 2.4 Rec.709 - Texture, g24_rec709_tx
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Camera Rec.709 camera_rec709, Utility - Rec.709 - Camera, rec709_camera
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 sRGB Encoded P3-D65 srgb_encoded_p3d65, srgb_p3d65, srgb_displayp3, srgb_p3d65_scene, sRGB Encoded P3-D65 - Texture, srgb_encoded_p3d65_tx
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 2.2 Encoded AdobeRGB g22_encoded_adobergb, adobergb, g22_adobergb_scene
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 sRGB Encoded AP1 srgb_encoded_ap1, srgb_ap1, srgb_ap1_scene, sRGB Encoded AP1 - Texture, srgb_encoded_ap1_tx
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Gamma 2.2 Encoded AP1 g22_encoded_ap1, g22_ap1, Gamma 2.2 AP1 - Texture, g22_ap1_tx, g22_ap1_scene
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear Rec.709 (sRGB) lin_rec709_srgb, Utility - Linear - Rec.709, lin_rec709, lin_rec709_scene, lin_srgb, Utility - Linear - sRGB
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear P3-D65 lin_p3d65, Utility - Linear - P3-D65, lin_displayp3, lin_p3d65_scene, Linear Display P3
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear AdobeRGB lin_adobergb, Utility - Linear - Adobe RGB, lin_adobergb_scene
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Linear Rec.2020 lin_rec2020, Utility - Linear - Rec.2020, lin_rec2020_scene
studio-config-v2.2.0_aces-v1.3_ocio-v2.4 Raw Utility - Raw, none

Supported Color Spaces in MaterialX¶

MaterialX currently uses color space names for :

  1. Color space (colorspace attribute) tagging for input images (filename attributes) and colors (color3 and color4 types).
  2. Node category identifiers for node definitions of the form <from color space>_<to color space name> to specify color space conversion nodes. (Node definitions are support as of MaterialX 1.38.7)

Note that any valid color space name can be used for input tagging.

At time of writing only specific color space conversions are supported via node definitions and hence can perform code injection during shader code generation. Any color space information can still be passed as meta-data to the code generated (e.g. as is possible with the OSL generator).

Further note that only certain aliases which are valid MaterialX identifiers are recognized in this context. For example g18_rec709 is used for color space Gamma 1.8 Rec.709 - Texture and lin_rec709 is used for color space Linear Rec.709 (sRGB).

OCIO Shader Code Generation¶

It is possible to generate code color space transforms for certain code generation targets.

This is done by:

  1. Calling getProcessor() on the config with desired "source" and "destination" color spaces for the transform.
  2. Creating a CPU or GPU processor
  3. Set the appropriate target language
  4. Getting the shader code using getShaderText()
In [7]:
def generateShaderCode(config, sourceColorSpace, destColorSpace, language):
    cshaderCodee = ''
    if not config:
        return shaderCode

    # Create a processor for a pair of colorspaces (namely to go to linear)
    processor = None
    try:
        processor = config.getProcessor(sourceColorSpace, destColorSpace)
    except:
        return shaderCode

    gpuProcessor = None
    if processor:
        processor = processor.getOptimizedProcessor(OCIO.OPTIMIZATION_ALL) 
        gpuProcessor = processor.getDefaultGPUProcessor()
    if gpuProcessor:
        shaderDesc = OCIO.GpuShaderDesc.CreateShaderDesc()
        if shaderDesc:
            shaderDesc.setLanguage(language)
            gpuProcessor.extractGpuShaderInfo(shaderDesc)
            shaderCode = shaderDesc.getShaderText()
    
    return shaderCode

# Use GLSL as the shader language to produce, and linear as the target color space
language = OCIO.GpuLanguage.GPU_LANGUAGE_GLSL_4_0
targetColorSpace = 'lin_rec709'

# Go through all the config and create code for each transform

title = '| Source | Target | Code |\n'
title = title + '| --- | --- | --- |\n'

rows = ''
testedSources = set()
for c in configs:
    config = OCIO.Config.CreateFromBuiltinConfig(c)
    colorSpaces = config.getColorSpaces()
    for colorSpace in colorSpaces:
        colorSpaceName = colorSpace.getName()
        # Skip if the colorspace is already tested
        if colorSpaceName in testedSources:
            continue
        testedSources.add(colorSpaceName)

        code = generateShaderCode(config, colorSpace.getName(), targetColorSpace, language)
        code = code.replace('\n', '<br>')
        code = '<code>' + code + '</code>'
        rows = rows + '| ' + colorSpace.getName() + ' | ' + targetColorSpace + ' | ' + code + '|\n'

md = '<details><summary>Transform Code for GLSL</summary>\n\n' + title + rows + '</details>'
display_markdown(md, raw=True)
Transform Code for GLSL
Source Target Code
sRGB - Display lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'monCurveFwd' processing

{
vec4 breakPnt = vec4(0.0392857157, 0.0392857157, 0.0392857157, 1.);
vec4 slope = vec4(0.077380158, 0.077380158, 0.077380158, 1.);
vec4 scale = vec4(0.947867274, 0.947867274, 0.947867274, 0.999998987);
vec4 offset = vec4(0.0521326996, 0.0521326996, 0.0521326996, 9.99998974e-07);
vec4 gamma = vec4(2.4000001, 2.4000001, 2.4000001, 1.00000095);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 linSeg = outColor * slope;
vec4 powSeg = pow( max( vec4(0., 0., 0., 0.), scale * outColor + offset), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * linSeg;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Display P3 - Display lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'monCurveMirrorFwd' processing

{
vec4 breakPnt = vec4(0.0392857157, 0.0392857157, 0.0392857157, 1.);
vec4 slope = vec4(0.077380158, 0.077380158, 0.077380158, 1.);
vec4 scale = vec4(0.947867274, 0.947867274, 0.947867274, 0.999998987);
vec4 offset = vec4(0.0521326996, 0.0521326996, 0.0521326996, 9.99998974e-07);
vec4 gamma = vec4(2.4000001, 2.4000001, 2.4000001, 1.00000095);
vec4 signcol = sign(outColor);;
outColor = abs( outColor );
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 linSeg = outColor * slope;
vec4 powSeg = pow( scale * outColor + offset, gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * linSeg;
res = signcol * res;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.2249401762805601, -0.042056954709688135, -0.019637554590334505, 0., -0.22494017628055812, 1.0420569547096905, -0.07863604555063225, 0., -0., 0., 1.0982736001409614, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Rec.1886 Rec.709 - Display lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicFwd' processing

{
vec4 gamma = vec4(2.3999999999999999, 2.3999999999999999, 2.3999999999999999, 1.);
vec4 res = pow( max( vec4(0., 0., 0., 0.), outColor ), gamma );
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Rec.2100-PQ - Display lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep;
float abs_f = abs(f);
if (abs_f > 6.10351562e-05)
{
vec3 fComp = vec3(15., 15., 15.);
float absarr = min( abs_f, 65504.);
fComp.x = floor( log2( absarr ) );
float lower = pow( 2.0, fComp.x );
fComp.y = ( absarr - lower ) / lower;
vec3 scale = vec3(1024., 1024., 1024.);
dep = dot( fComp, scale );
}
else
{
dep = abs_f * 16777216.;
}
dep += (f < 0.) ? 32768.0 : 0.0;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 17.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6604910021084345, -0.12455047452159071, -0.018150763354905296, 0., -0.58764113878854818, 1.132899897125963, -0.10057889800800782, 0., -0.072849863319885577, -0.0083494226043691194, 1.1187296613629079, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ST2084-P3-D65 - Display lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep;
float abs_f = abs(f);
if (abs_f > 6.10351562e-05)
{
vec3 fComp = vec3(15., 15., 15.);
float absarr = min( abs_f, 65504.);
fComp.x = floor( log2( absarr ) );
float lower = pow( 2.0, fComp.x );
fComp.y = ( absarr - lower ) / lower;
vec3 scale = vec3(1024., 1024., 1024.);
dep = dot( fComp, scale );
}
else
{
dep = abs_f * 16777216.;
}
dep += (f < 0.) ? 32768.0 : 0.0;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 17.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.2249401762805601, -0.042056954709688135, -0.019637554590334505, 0., -0.22494017628055812, 1.0420569547096905, -0.07863604555063225, 0., -0., 0., 1.0982736001409614, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
P3-D65 - Display lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicFwd' processing

{
vec4 gamma = vec4(2.6000000000000001, 2.6000000000000001, 2.6000000000000001, 1.);
vec4 res = pow( max( vec4(0., 0., 0., 0.), outColor ), gamma );
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.2249401762805601, -0.042056954709688135, -0.019637554590334505, 0., -0.22494017628055812, 1.0420569547096905, -0.07863604555063225, 0., -0., 0., 1.0982736001409614, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ACES2065-1 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(2.5216861867438798, -0.27647991422992202, -0.015378064966034201, 0., -1.1341309882397199, 1.37271908766826, -0.152975335867399, 0., -0.38755519850416398, -0.096239173438334005, 1.16835340083343, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ACEScc lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep = clamp(f, 0.0, 1.0) * 4095.;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 2.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Range processing

{
outColor.rgb = outColor.rgb * vec3(0.53763440860215062, 0.53763440860215062, 0.53763440860215062) + vec3(0.19354838709677422, 0.19354838709677422, 0.19354838709677422);
outColor.rgb = max(vec3(0., 0., 0.), outColor.rgb);
outColor.rgb = min(vec3(1., 1., 1.), outColor.rgb);
}

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(0.69545224135745187, 0.044794563372037716, -0.0055258825581135443, 0., 0.14067869647029416, 0.85967111845642163, 0.0040252103059786595, 0., 0.16386906217225405, 0.0955343181715404, 1.0015006722521349, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Range processing

{
outColor.rgb = max(vec3(0., 0., 0.), outColor.rgb);
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(2.5216861867438798, -0.27647991422992202, -0.015378064966034201, 0., -1.1341309882397199, 1.37271908766826, -0.152975335867399, 0., -0.38755519850416398, -0.096239173438334005, 1.16835340083343, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ACEScct lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.155251175, 0.155251175, 0.155251175);
vec3 linear_segment_offset = vec3(0.0729055703, 0.0729055703, 0.0729055703);
vec3 linear_segment_slopeinv = vec3(0.0948745236, 0.0948745236, 0.0948745236);
vec3 lin_slopeinv = vec3(1., 1., 1.);
vec3 lin_offset = vec3(0., 0., 0.);
vec3 log_slopeinv = vec3(17.5200005, 17.5200005, 17.5200005);
vec3 log_base = vec3(2., 2., 2.);
vec3 log_offset = vec3(0.5547945205479452, 0.5547945205479452, 0.5547945205479452);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.7050509926579815, -0.1302564175070435, -0.024003356804618042, 0., -0.62179212065700562, 1.1408047365754048, -0.1289689760649709, 0., -0.0832588720009797, -0.010548319068357653, 1.1529723328695858, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ACEScg lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.7050509926579815, -0.1302564175070435, -0.024003356804618042, 0., -0.62179212065700562, 1.1408047365754048, -0.1289689760649709, 0., -0.0832588720009797, -0.010548319068357653, 1.1529723328695858, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
sRGB Encoded Rec.709 (sRGB) lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'monCurveFwd' processing

{
vec4 breakPnt = vec4(0.0392857157, 0.0392857157, 0.0392857157, 1.);
vec4 slope = vec4(0.077380158, 0.077380158, 0.077380158, 1.);
vec4 scale = vec4(0.947867274, 0.947867274, 0.947867274, 0.999998987);
vec4 offset = vec4(0.0521326996, 0.0521326996, 0.0521326996, 9.99998974e-07);
vec4 gamma = vec4(2.4000001, 2.4000001, 2.4000001, 1.00000095);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 linSeg = outColor * slope;
vec4 powSeg = pow( max( vec4(0., 0., 0., 0.), scale * outColor + offset), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * linSeg;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Gamma 1.8 Encoded Rec.709 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicPassThruFwd' processing

{
vec4 gamma = vec4(1.8, 1.8, 1.8, 1.);
vec4 breakPnt = vec4(0., 0., 0., 0.);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 powSeg = pow(max( vec4(0., 0., 0., 0.), outColor ), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * outColor;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Gamma 2.2 Encoded Rec.709 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicPassThruFwd' processing

{
vec4 gamma = vec4(2.2000000000000002, 2.2000000000000002, 2.2000000000000002, 1.);
vec4 breakPnt = vec4(0., 0., 0., 0.);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 powSeg = pow(max( vec4(0., 0., 0., 0.), outColor ), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * outColor;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Gamma 2.4 Encoded Rec.709 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicPassThruFwd' processing

{
vec4 gamma = vec4(2.3999999999999999, 2.3999999999999999, 2.3999999999999999, 1.);
vec4 breakPnt = vec4(0., 0., 0., 0.);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 powSeg = pow(max( vec4(0., 0., 0., 0.), outColor ), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * outColor;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
sRGB Encoded P3-D65 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'monCurveFwd' processing

{
vec4 breakPnt = vec4(0.0392857157, 0.0392857157, 0.0392857157, 1.);
vec4 slope = vec4(0.077380158, 0.077380158, 0.077380158, 1.);
vec4 scale = vec4(0.947867274, 0.947867274, 0.947867274, 0.999998987);
vec4 offset = vec4(0.0521326996, 0.0521326996, 0.0521326996, 9.99998974e-07);
vec4 gamma = vec4(2.4000001, 2.4000001, 2.4000001, 1.00000095);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 linSeg = outColor * slope;
vec4 powSeg = pow( max( vec4(0., 0., 0., 0.), scale * outColor + offset), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * linSeg;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.224940176280555, -0.042056954709687663, -0.019637554590334446, 0., -0.22494017628056295, 1.0420569547096903, -0.078636045550631944, 0., -0., 0., 1.0982736001409683, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Gamma 2.2 Encoded AdobeRGB lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicPassThruFwd' processing

{
vec4 gamma = vec4(2.19921875, 2.19921875, 2.19921875, 1.);
vec4 breakPnt = vec4(0., 0., 0., 0.);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 powSeg = pow(max( vec4(0., 0., 0., 0.), outColor ), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * outColor;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.3983557439607741, -0., -0., 0., -0.39835574396077827, 1., -0.042928989294473863, 0., -0., -0., 1.0429289892944664, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
sRGB Encoded AP1 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'monCurveFwd' processing

{
vec4 breakPnt = vec4(0.0392857157, 0.0392857157, 0.0392857157, 1.);
vec4 slope = vec4(0.077380158, 0.077380158, 0.077380158, 1.);
vec4 scale = vec4(0.947867274, 0.947867274, 0.947867274, 0.999998987);
vec4 offset = vec4(0.0521326996, 0.0521326996, 0.0521326996, 9.99998974e-07);
vec4 gamma = vec4(2.4000001, 2.4000001, 2.4000001, 1.00000095);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 linSeg = outColor * slope;
vec4 powSeg = pow( max( vec4(0., 0., 0., 0.), scale * outColor + offset), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * linSeg;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.7050509926579756, -0.13025641750704287, -0.02400335680461799, 0., -0.62179212065700873, 1.1408047365754079, -0.12896897606497126, 0., -0.083258872000981698, -0.010548319068357195, 1.152972332869586, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Gamma 2.2 Encoded AP1 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicPassThruFwd' processing

{
vec4 gamma = vec4(2.2000000000000002, 2.2000000000000002, 2.2000000000000002, 1.);
vec4 breakPnt = vec4(0., 0., 0., 0.);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 powSeg = pow(max( vec4(0., 0., 0., 0.), outColor ), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * outColor;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.7050509926579756, -0.13025641750704287, -0.02400335680461799, 0., -0.62179212065700873, 1.1408047365754079, -0.12896897606497126, 0., -0.083258872000981698, -0.010548319068357195, 1.152972332869586, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear Rec.709 (sRGB) lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

return outColor;
}
Linear P3-D65 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.224940176280555, -0.042056954709687663, -0.019637554590334446, 0., -0.22494017628056295, 1.0420569547096903, -0.078636045550631944, 0., -0., 0., 1.0982736001409683, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear AdobeRGB lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.3983557439607741, -0., -0., 0., -0.39835574396077827, 1., -0.042928989294473863, 0., -0., -0., 1.0429289892944664, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear Rec.2020 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6604910021084354, -0.12455047452159097, -0.018150763354905279, 0., -0.58764113878854773, 1.1328998971259596, -0.10057889800800768, 0., -0.072849863319883967, -0.0083494226043700909, 1.118729661362905, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Raw lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

return outColor;
}
Rec.1886 Rec.2020 - Display lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicFwd' processing

{
vec4 gamma = vec4(2.3999999999999999, 2.3999999999999999, 2.3999999999999999, 1.);
vec4 res = pow( max( vec4(0., 0., 0., 0.), outColor ), gamma );
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6604910021084345, -0.12455047452159071, -0.018150763354905296, 0., -0.58764113878854818, 1.132899897125963, -0.10057889800800782, 0., -0.072849863319885577, -0.0083494226043691194, 1.1187296613629079, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Rec.2100-HLG - Display lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep;
float abs_f = abs(f);
if (abs_f > 6.10351562e-05)
{
vec3 fComp = vec3(15., 15., 15.);
float absarr = min( abs_f, 65504.);
fComp.x = floor( log2( absarr ) );
float lower = pow( 2.0, fComp.x );
fComp.y = ( absarr - lower ) / lower;
vec3 scale = vec3(1024., 1024., 1024.);
dep = dot( fComp, scale );
}
else
{
dep = abs_f * 16777216.;
}
dep += (f < 0.) ? 32768.0 : 0.0;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 17.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add FixedFunction 'REC2100_Surround (Inverse)' processing

{
float Y = 0.2627 * outColor.rgb.r + 0.6780 * outColor.rgb.g + 0.0593 * outColor.rgb.b;
Y = max( 0.000464158948, abs(Y) );
float Ypow_over_Y = pow( Y, 0.200000048);
outColor.rgb = outColor.rgb * Ypow_over_Y;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(4.4431504677377838, -0.33327280811813154, -0.048567907075523643, 0., -1.5724132183522657, 3.0314194424563343, -0.26912953889023716, 0., -0.19493204351808124, -0.022341428470757985, 2.9935026518331829, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
P3-D60 - Display lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicFwd' processing

{
vec4 gamma = vec4(2.6000000000000001, 2.6000000000000001, 2.6000000000000001, 1.);
vec4 res = pow( max( vec4(0., 0., 0., 0.), outColor ), gamma );
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.2506407302924027, -0.04233848109588953, -0.019766618255446962, 0., -0.24612878703824759, 1.0439783389254813, -0.077599171696057692, 0., -0.0045119432541608773, -0.0016398578295868521, 1.0973657899515015, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
P3-DCI - Display lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'basicFwd' processing

{
vec4 gamma = vec4(2.6000000000000001, 2.6000000000000001, 2.6000000000000001, 1.);
vec4 res = pow( max( vec4(0., 0., 0., 0.), outColor ), gamma );
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.1575164061997576, -0.041500071530685759, -0.018050038956254021, 0., -0.15496237807385949, 1.045567923079703, -0.078578272653029468, 0., -0.0025540281259017195, -0.0040678515490129574, 1.0966283116092799, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ADX10 lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep;
float abs_f = abs(f);
if (abs_f > 6.10351562e-05)
{
vec3 fComp = vec3(15., 15., 15.);
float absarr = min( abs_f, 65504.);
fComp.x = floor( log2( absarr ) );
float lower = pow( 2.0, fComp.x );
fComp.y = ( absarr - lower ) / lower;
vec3 scale = vec3(1024., 1024., 1024.);
dep = dot( fComp, scale );
}
else
{
dep = abs_f * 16777216.;
}
dep += (f < 0.) ? 32768.0 : 0.0;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 17.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.5462235799999999, 0.12073445999999999, 0.33010163999999997, 0., 0.45415061999999995, 1.9831468799999998, 0.15152675999999998, 0., 0.045625799999999994, -0.057881339999999996, 1.5643715999999999, 0., 0., 0., 0., 1.) * tmp;
res = vec4(-0.189999998, -0.189999998, -0.189999998, 0.) + res;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add Log 'Anti-Log' processing

{
outColor.rgb = pow( vec3(10., 10., 10.), outColor.rgb);
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6820732265392047, -0.037560306982519796, -0.012683034306924423, 0., -0.58002116166042406, 1.0061809359326013, -0.022886076957909493, 0., -0.10204818932679965, 0.031380333441656763, 1.0355574277308224, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ADX16 lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep;
float abs_f = abs(f);
if (abs_f > 6.10351562e-05)
{
vec3 fComp = vec3(15., 15., 15.);
float absarr = min( abs_f, 65504.);
fComp.x = floor( log2( absarr ) );
float lower = pow( 2.0, fComp.x );
fComp.y = ( absarr - lower ) / lower;
vec3 scale = vec3(1024., 1024., 1024.);
dep = dot( fComp, scale );
}
else
{
dep = abs_f * 16777216.;
}
dep += (f < 0.) ? 32768.0 : 0.0;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 17.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(6.19084569375, 0.48340254374999997, 1.3216771125, 0., 1.8183504937499999, 7.9402206, 0.60669026250000002, 0., 0.18267881249999998, -0.23174814374999997, 6.263507624999999, 0., 0., 0., 0., 1.) * tmp;
res = vec4(-0.189999998, -0.189999998, -0.189999998, 0.) + res;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add Log 'Anti-Log' processing

{
outColor.rgb = pow( vec3(10., 10., 10.), outColor.rgb);
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6820732265392047, -0.037560306982519796, -0.012683034306924423, 0., -0.58002116166042406, 1.0061809359326013, -0.022886076957909493, 0., -0.10204818932679965, 0.031380333441656763, 1.0355574277308224, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Apple Log lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep;
float abs_f = abs(f);
if (abs_f > 6.10351562e-05)
{
vec3 fComp = vec3(15., 15., 15.);
float absarr = min( abs_f, 65504.);
fComp.x = floor( log2( absarr ) );
float lower = pow( 2.0, fComp.x );
fComp.y = ( absarr - lower ) / lower;
vec3 scale = vec3(1024., 1024., 1024.);
dep = dot( fComp, scale );
}
else
{
dep = abs_f * 16777216.;
}
dep += (f < 0.) ? 32768.0 : 0.0;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 17.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6604910021084316, -0.12455047452159074, -0.01815076335490522, 0., -0.58764113878855107, 1.1328998971259641, -0.10057889800800789, 0., -0.072849863319885744, -0.0083494226043691611, 1.1187296613629099, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear ARRI Wide Gamut 3 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6175960353244454, -0.071010304591282061, -0.021123885575728883, 0., -0.53423642434848773, 1.3374356321770418, -0.23237438347978712, 0., -0.083359610975958676, -0.26642532758575721, 1.253498269055507, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ARRI LogC3 (EI800) lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.149658144, 0.149658144, 0.149658144);
vec3 linear_segment_offset = vec3(0.0928093642, 0.0928093642, 0.0928093642);
vec3 linear_segment_slopeinv = vec3(0.186301097, 0.186301097, 0.186301097);
vec3 lin_slopeinv = vec3(0.180000007, 0.180000007, 0.180000007);
vec3 lin_offset = vec3(0.052272275025168798, 0.052272275025168798, 0.052272275025168798);
vec3 log_slopeinv = vec3(4.04547691, 4.04547691, 4.04547691);
vec3 log_base = vec3(10., 10., 10.);
vec3 log_offset = vec3(0.38553699869244301, 0.38553699869244301, 0.38553699869244301);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6175960353244454, -0.071010304591282061, -0.021123885575728883, 0., -0.53423642434848773, 1.3374356321770418, -0.23237438347978712, 0., -0.083359610975958676, -0.26642532758575721, 1.253498269055507, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
ARRI LogC4 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0., 0., 0.);
vec3 linear_segment_offset = vec3(0.158956334, 0.158956334, 0.158956334);
vec3 linear_segment_slopeinv = vec3(0.113597214, 0.113597214, 0.113597214);
vec3 lin_slopeinv = vec3(0.000448063511, 0.000448063511, 0.000448063511);
vec3 lin_offset = vec3(64., 64., 64.);
vec3 log_slopeinv = vec3(15.4331894, 15.4331894, 15.4331894);
vec3 log_base = vec3(2., 2., 2.);
vec3 log_offset = vec3(-0.29590839268258601, -0.29590839268258601, -0.29590839268258601);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.8929404968219639, -0.20644836083723977, -0.012258112702638239, 0., -0.77800083137239329, 1.3430260992709093, -0.15732590776965169, 0., -0.11493966544957079, -0.13657773843366997, 1.1695840204722865, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear ARRI Wide Gamut 4 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.8929404968219639, -0.20644836083723977, -0.012258112702638239, 0., -0.77800083137239329, 1.3430260992709093, -0.15732590776965169, 0., -0.11493966544957079, -0.13657773843366997, 1.1695840204722865, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
BMDFilm WideGamut Gen5 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.133883744, 0.133883744, 0.133883744);
vec3 linear_segment_offset = vec3(0.0924657136, 0.0924657136, 0.0924657136);
vec3 linear_segment_slopeinv = vec3(0.120720379, 0.120720379, 0.120720379);
vec3 lin_slopeinv = vec3(1., 1., 1.);
vec3 lin_offset = vec3(0.0054940724322578103, 0.0054940724322578103, 0.0054940724322578103);
vec3 log_slopeinv = vec3(11.5036726, 11.5036726, 11.5036726);
vec3 log_base = vec3(2.71828182845905, 2.71828182845905, 2.71828182845905);
vec3 log_offset = vec3(0.53001333922919402, 0.53001333922919402, 0.53001333922919402);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.5685053307142094, -0.086765930966416174, -0.05212011917108085, 0., -0.51955620578769812, 1.3477854013561954, -0.25469373659499694, 0., -0.048949124926515208, -0.26101947038977646, 1.3068138557660767, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
DaVinci Intermediate WideGamut lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.0274066925, 0.0274066925, 0.0274066925);
vec3 linear_segment_offset = vec3(-7.4505806e-09, -7.4505806e-09, -7.4505806e-09);
vec3 linear_segment_slopeinv = vec3(0.0957462937, 0.0957462937, 0.0957462937);
vec3 lin_slopeinv = vec3(1., 1., 1.);
vec3 lin_offset = vec3(0.0074999999999999997, 0.0074999999999999997, 0.0074999999999999997);
vec3 log_slopeinv = vec3(13.6439648, 13.6439648, 13.6439648);
vec3 log_base = vec3(2., 2., 2.);
vec3 log_offset = vec3(0.51304735999999995, 0.51304735999999995, 0.51304735999999995);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.8987312079363696, -0.1694642609483365, -0.12161393715142485, 0., -0.78866341542508211, 1.4922628969176159, -0.32192612718818647, 0., -0.11006779251129151, -0.32279863596927649, 1.4435400643396084, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
CanonLog2 CinemaGamut D55 lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep = clamp(f, 0.0, 1.0) * 4095.;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 2.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.923707099704667, -0.20504593605401519, -0.023285583594355674, 0., -0.79501788145104413, 1.4993613143502984, -0.42677817014753039, 0., -0.12868921825362739, -0.29431537829627868, 1.4500637537418826, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
CanonLog3 CinemaGamut D55 lin_rec709
// Declaration of all variables

uniform sampler2D ocio_lut1d_0Sampler;

// Declaration of all helper methods

vec2 ocio_lut1d_0_computePos(float f)
{
float dep = clamp(f, 0.0, 1.0) * 4095.;
vec2 retVal;
retVal.y = floor(dep / 4095.);
retVal.x = dep - retVal.y * 4095.;
retVal.x = (retVal.x + 0.5) / 4096.;
retVal.y = (retVal.y + 0.5) / 2.;
return retVal;
}

// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add LUT 1D processing for ocio_lut1d_0

{
outColor.r = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.r)).r;
outColor.g = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.g)).r;
outColor.b = texture(ocio_lut1d_0Sampler, ocio_lut1d_0_computePos(outColor.b)).r;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.923707099704667, -0.20504593605401519, -0.023285583594355674, 0., -0.79501788145104413, 1.4993613143502984, -0.42677817014753039, 0., -0.12868921825362739, -0.29431537829627868, 1.4500637537418826, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear CinemaGamut D55 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.9237070997046672, -0.20504593605401522, -0.023285583594355678, 0., -0.7950178814510509, 1.4993613143503051, -0.42677817014753106, 0., -0.12868921825362856, -0.2943153782962793, 1.4500637537418875, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear V-Gamut lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.8065758837249319, -0.17009034310239998, -0.025205784016640309, 0., -0.69569727408369775, 1.3059552160953665, -0.154468329360574, 0., -0.11087860964123719, -0.13586487299296368, 1.1796741133772104, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
V-Log V-Gamut lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.180999666, 0.180999666, 0.180999666);
vec3 linear_segment_offset = vec3(0.124999568, 0.124999568, 0.124999568);
vec3 linear_segment_slopeinv = vec3(0.17857109, 0.17857109, 0.17857109);
vec3 lin_slopeinv = vec3(1., 1., 1.);
vec3 lin_offset = vec3(0.0087299999999999999, 0.0087299999999999999, 0.0087299999999999999);
vec3 log_slopeinv = vec3(4.1405468, 4.1405468, 4.1405468);
vec3 log_base = vec3(10., 10., 10.);
vec3 log_offset = vec3(0.59820600000000002, 0.59820600000000002, 0.59820600000000002);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.8065758837249319, -0.17009034310239998, -0.025205784016640309, 0., -0.69569727408369775, 1.3059552160953665, -0.154468329360574, 0., -0.11087860964123719, -0.13586487299296368, 1.1796741133772104, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear REDWideGamutRGB lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.9819760179564536, -0.17814318205504703, -0.10179596596933896, 0., -0.90043183664045945, 1.5004683579162101, -0.53526345921182183, 0., -0.081544181316000275, -0.32232517586115994, 1.6370594251811619, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Log3G10 REDWideGamutRGB lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0., 0., 0.);
vec3 linear_segment_offset = vec3(0.15192689, 0.15192689, 0.15192689);
vec3 linear_segment_slopeinv = vec3(0.0658211336, 0.0658211336, 0.0658211336);
vec3 lin_slopeinv = vec3(0.00641127024, 0.00641127024, 0.00641127024);
vec3 lin_offset = vec3(2.5597532699999999, 2.5597532699999999, 2.5597532699999999);
vec3 log_slopeinv = vec3(4.45867252, 4.45867252, 4.45867252);
vec3 log_base = vec3(10., 10., 10.);
vec3 log_offset = vec3(0., 0., 0.);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.9819760179564536, -0.17814318205504703, -0.10179596596933896, 0., -0.90043183664045945, 1.5004683579162101, -0.53526345921182183, 0., -0.081544181316000275, -0.32232517586115994, 1.6370594251811619, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear S-Gamut3 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.8778156775191697, -0.17747979963189922, -0.02590143482982572, 0., -0.79127608338063604, 1.353784194250401, -0.15358565720579506, 0., -0.08653959413854162, -0.17630439461849309, 1.1794870920356171, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear S-Gamut3.Cine lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6268564003175596, -0.17910943044878672, -0.04416647789499864, 0., -0.53698863655119955, 1.4208630414432488, -0.20151920061693746, 0., -0.089867763766365294, -0.24175361099445791, 1.2456856785119332, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear Venice S-Gamut3 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.9901688195570184, -0.19613579460920139, -0.036624086206908393, 0., -0.9515515415040825, 1.3917665273557032, -0.14443018284830009, 0., -0.038617278052943071, -0.19563073274649953, 1.1810542690552106, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear Venice S-Gamut3.Cine lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.725635767457687, -0.19552629878430919, -0.053585711071423188, 0., -0.6911374056917291, 1.4589135591606734, -0.19353475807298104, 0., -0.03449836176596871, -0.26338726037635629, 1.247120469144404, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
S-Log3 S-Gamut3 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.167360976, 0.167360976, 0.167360976);
vec3 linear_segment_offset = vec3(0.0928641111, 0.0928641111, 0.0928641111);
vec3 linear_segment_slopeinv = vec3(0.151013061, 0.151013061, 0.151013061);
vec3 lin_slopeinv = vec3(0.189999998, 0.189999998, 0.189999998);
vec3 lin_offset = vec3(0.052631578947368397, 0.052631578947368397, 0.052631578947368397);
vec3 log_slopeinv = vec3(3.91204596, 3.91204596, 3.91204596);
vec3 log_base = vec3(10., 10., 10.);
vec3 log_offset = vec3(0.410557184750733, 0.410557184750733, 0.410557184750733);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.8778156775191697, -0.17747979963189922, -0.02590143482982572, 0., -0.79127608338063604, 1.353784194250401, -0.15358565720579506, 0., -0.08653959413854162, -0.17630439461849309, 1.1794870920356171, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
S-Log3 S-Gamut3.Cine lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.167360976, 0.167360976, 0.167360976);
vec3 linear_segment_offset = vec3(0.0928641111, 0.0928641111, 0.0928641111);
vec3 linear_segment_slopeinv = vec3(0.151013061, 0.151013061, 0.151013061);
vec3 lin_slopeinv = vec3(0.189999998, 0.189999998, 0.189999998);
vec3 lin_offset = vec3(0.052631578947368397, 0.052631578947368397, 0.052631578947368397);
vec3 log_slopeinv = vec3(3.91204596, 3.91204596, 3.91204596);
vec3 log_base = vec3(10., 10., 10.);
vec3 log_offset = vec3(0.410557184750733, 0.410557184750733, 0.410557184750733);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.6268564003175596, -0.17910943044878672, -0.04416647789499864, 0., -0.53698863655119955, 1.4208630414432488, -0.20151920061693746, 0., -0.089867763766365294, -0.24175361099445791, 1.2456856785119332, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
S-Log3 Venice S-Gamut3 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.167360976, 0.167360976, 0.167360976);
vec3 linear_segment_offset = vec3(0.0928641111, 0.0928641111, 0.0928641111);
vec3 linear_segment_slopeinv = vec3(0.151013061, 0.151013061, 0.151013061);
vec3 lin_slopeinv = vec3(0.189999998, 0.189999998, 0.189999998);
vec3 lin_offset = vec3(0.052631578947368397, 0.052631578947368397, 0.052631578947368397);
vec3 log_slopeinv = vec3(3.91204596, 3.91204596, 3.91204596);
vec3 log_base = vec3(10., 10., 10.);
vec3 log_offset = vec3(0.410557184750733, 0.410557184750733, 0.410557184750733);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.9901688195570184, -0.19613579460920139, -0.036624086206908393, 0., -0.9515515415040825, 1.3917665273557032, -0.14443018284830009, 0., -0.038617278052943071, -0.19563073274649953, 1.1810542690552106, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
S-Log3 Venice S-Gamut3.Cine lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Log 'Camera Log to Lin' processing

{
vec3 log_break = vec3(0.167360976, 0.167360976, 0.167360976);
vec3 linear_segment_offset = vec3(0.0928641111, 0.0928641111, 0.0928641111);
vec3 linear_segment_slopeinv = vec3(0.151013061, 0.151013061, 0.151013061);
vec3 lin_slopeinv = vec3(0.189999998, 0.189999998, 0.189999998);
vec3 lin_offset = vec3(0.052631578947368397, 0.052631578947368397, 0.052631578947368397);
vec3 log_slopeinv = vec3(3.91204596, 3.91204596, 3.91204596);
vec3 log_base = vec3(10., 10., 10.);
vec3 log_offset = vec3(0.410557184750733, 0.410557184750733, 0.410557184750733);
vec3 isAboveBreak = vec3(greaterThan( outColor.rgb, log_break));
vec3 linSeg = ( outColor.rgb - linear_segment_offset ) * linear_segment_slopeinv;
vec3 logSeg = (outColor.rgb - log_offset) * log_slopeinv;
logSeg = pow(log_base, logSeg);
logSeg = lin_slopeinv * (logSeg - lin_offset);
outColor.rgb = isAboveBreak * logSeg + ( vec3(1., 1., 1.) - isAboveBreak ) * linSeg;
}

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.725635767457687, -0.19552629878430919, -0.053585711071423188, 0., -0.6911374056917291, 1.4589135591606734, -0.19353475807298104, 0., -0.03449836176596871, -0.26338726037635629, 1.247120469144404, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear BMD WideGamut Gen5 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.5685053307142094, -0.086765930966416174, -0.05212011917108085, 0., -0.51955620578769812, 1.3477854013561954, -0.25469373659499694, 0., -0.048949124926515208, -0.26101947038977646, 1.3068138557660767, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Linear DaVinci WideGamut lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Matrix processing

{
vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
vec4 tmp = res;
res = mat4(1.8987312079363696, -0.1694642609483365, -0.12161393715142485, 0., -0.78866341542508211, 1.4922628969176159, -0.32192612718818647, 0., -0.11006779251129151, -0.32279863596927649, 1.4435400643396084, 0., 0., 0., 0., 1.) * tmp;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}
Camera Rec.709 lin_rec709
// Declaration of the OCIO shader function

vec4 OCIOMain(vec4 inPixel)
{
vec4 outColor = inPixel;

// Add Gamma 'monCurveFwd' processing

{
vec4 breakPnt = vec4(0.0810000002, 0.0810000002, 0.0810000002, 1.);
vec4 slope = vec4(0.221543506, 0.221543506, 0.221543506, 1.);
vec4 scale = vec4(0.909918129, 0.909918129, 0.909918129, 0.999998987);
vec4 offset = vec4(0.0900818929, 0.0900818929, 0.0900818929, 9.99998974e-07);
vec4 gamma = vec4(2.22222233, 2.22222233, 2.22222233, 1.00000095);
vec4 isAboveBreak = vec4(greaterThan( outColor, breakPnt));
vec4 linSeg = outColor * slope;
vec4 powSeg = pow( max( vec4(0., 0., 0., 0.), scale * outColor + offset), gamma);
vec4 res = isAboveBreak * powSeg + ( vec4(1., 1., 1., 1.) - isAboveBreak ) * linSeg;
outColor.rgb = vec3(res.x, res.y, res.z);
outColor.a = res.w;
}

return outColor;
}

Integrating OCIO with MaterialX¶

We will pick an example transform to go over details on mapping from OCIO to MaterialX.

The first thing of note is OCIO function signatures

  • Currently all signatures transform 4 channel color inputs while MaterialX supports both 3 and 4 channel variants. This can be easily handled by adding pre and post conversion nodes, or by creating variant function signatures. The former is more robust and more in line with the proposed direction to have all OCIO transforms to be represented as graphs.

  • The signature name is not unique. This can be handled as OCIO provides mechanism to override the function names using setFunctionName and setResourcePrefix.

Following the current MaterialX convention we use the signature notation: mx_<sourceName>_to_<targetname>_<type> where type is either color3 or color4 for 3 or 4 channel variants.

We add in two new utilities:

  1. createTransformName which will generate the unique function name
  2. setShaderDescriptionParameters which overrides the function name but also adds a prefix to uniquely identify dependent resources.

These are then used in a new code generation variation called generateShaderCode2() which has additionally been modified to return the number of dependent texture resources, which can be queried from the shader descriptor via the GpuShaderDesc.getTextures() iterator.

In [8]:
def createTransformName(sourceSpace, targetSpace, typeName): 
    transformFunctionName = "mx_" + mx.createValidName(sourceSpace) + "_to_" + targetSpace + "_" + typeName 
    return transformFunctionName

def setShaderDescriptionParameters(shaderDesc, sourceSpace, targetSpace, typeName):
    transformFunctionName = createTransformName(sourceSpace, targetSpace, typeName)
    shaderDesc.setFunctionName(transformFunctionName)
    shaderDesc.setResourcePrefix(transformFunctionName)

def generateShaderCode2(config, sourceColorSpace, destColorSpace, language):
    shaderCode = ''
    textureCount = 0
    if not config:
        return shaderCode, textureCount

    # Create a processor for a pair of colorspaces (namely to go to linear)
    processor = None
    try:
        processor = config.getProcessor(sourceColorSpace, destColorSpace)
    except:
        print('Failed to generated code for transform: %s -> %s' % (sourceColorSpace, destColorSpace))
        return shaderCode, textureCount

    if processor:
        processor = processor.getOptimizedProcessor(OCIO.OPTIMIZATION_ALL)
        gpuProcessor = processor.getDefaultGPUProcessor()
        if gpuProcessor:
            shaderDesc = OCIO.GpuShaderDesc.CreateShaderDesc()
            if shaderDesc:
                try:
                    shaderDesc.setLanguage(language)
                    if shaderDesc.getLanguage() == language:
                        setShaderDescriptionParameters(shaderDesc, sourceColorSpace, destColorSpace, "color4")
                        gpuProcessor.extractGpuShaderInfo(shaderDesc)                                                                 
                        shaderCode = shaderDesc.getShaderText()
                        for t in shaderDesc.getTextures():
                            textureCount += 1
                except OCIO.Exception as err:
                    print(err)
    
    return shaderCode, textureCount

OCIO Resource Dependencies¶

Resource dependencies is a second major issue to examine.

In the example below we convert two different source color spaces.

One is "self-contained" in that there are no support functions being produced (ACES2065-1), while the second adds additional function and resources. Note that we maintain uniqueness of these additions by using setFunctionName and setResourcePrefix respectively.

Example 1: Self-contained¶

In [9]:
sourceColorSpace = 'ACES2065-1' # "acescg"
textureCount = 0
code = ''
code, textureCount = generateShaderCode2(builtinCfgC, sourceColorSpace, targetColorSpace, language)
if code:
    code = code.replace("// Declaration of the OCIO shader function\n", 
                        "// " + sourceColorSpace + " to " + targetColorSpace + " function. Texture count: %d\n" % textureCount)
    code = '```c++\n' + code + '\n```'
    display_markdown(code, raw=True)    
// ACES2065-1 to lin_rec709 function. Texture count: 0

vec4 mx_ACES2065_1_to_lin_rec709_color4(vec4 inPixel)
{
  vec4 outColor = inPixel;
  
  // Add Matrix processing
  
  {
    vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
    vec4 tmp = res;
    res = mat4(2.5216861867438798, -0.27647991422992202, -0.015378064966034201, 0., -1.1341309882397199, 1.37271908766826, -0.152975335867399, 0., -0.38755519850416398, -0.096239173438334005, 1.16835340083343, 0., 0., 0., 0., 1.) * tmp;
    outColor.rgb = vec3(res.x, res.y, res.z);
    outColor.a = res.w;
  }

  return outColor;
}

Example 2: Secondary Dependencies¶

In [10]:
sourceColorSpace = 'ACEScc' # "acescg"
code, textureCount = generateShaderCode2(builtinCfgC, sourceColorSpace, targetColorSpace, language)
if code:
    code = code.replace("// Declaration of the OCIO shader function\n", 
                        "// " + sourceColorSpace + " to " + targetColorSpace + " function. Texture count: %d\n" % textureCount)
    code = '```c++\n' + code + '\n```\n'

    md = '<details><summary>Secondary Dependency Sample Code</summary>\n\n' + code + '</details>'
    display_markdown(md, raw=True)
Secondary Dependency Sample Code
// Declaration of all variables

uniform sampler2D mx_ACEScc_to_lin_rec709_color4_lut1d_0Sampler;

// Declaration of all helper methods

vec2 mx_ACEScc_to_lin_rec709_color4_lut1d_0_computePos(float f)
{
  float dep = clamp(f, 0.0, 1.0) * 4095.;
  vec2 retVal;
  retVal.y = floor(dep / 4095.);
  retVal.x = dep - retVal.y * 4095.;
  retVal.x = (retVal.x + 0.5) / 4096.;
  retVal.y = (retVal.y + 0.5) / 2.;
  return retVal;
}

// ACEScc to lin_rec709 function. Texture count: 1

vec4 mx_ACEScc_to_lin_rec709_color4(vec4 inPixel)
{
  vec4 outColor = inPixel;
  
  // Add Range processing
  
  {
    outColor.rgb = outColor.rgb * vec3(0.53763440860215062, 0.53763440860215062, 0.53763440860215062) + vec3(0.19354838709677422, 0.19354838709677422, 0.19354838709677422);
    outColor.rgb = max(vec3(0., 0., 0.), outColor.rgb);
    outColor.rgb = min(vec3(1., 1., 1.), outColor.rgb);
  }
  
  // Add LUT 1D processing for mx_ACEScc_to_lin_rec709_color4_lut1d_0
  
  {
    outColor.r = texture(mx_ACEScc_to_lin_rec709_color4_lut1d_0Sampler, mx_ACEScc_to_lin_rec709_color4_lut1d_0_computePos(outColor.r)).r;
    outColor.g = texture(mx_ACEScc_to_lin_rec709_color4_lut1d_0Sampler, mx_ACEScc_to_lin_rec709_color4_lut1d_0_computePos(outColor.g)).r;
    outColor.b = texture(mx_ACEScc_to_lin_rec709_color4_lut1d_0Sampler, mx_ACEScc_to_lin_rec709_color4_lut1d_0_computePos(outColor.b)).r;
  }
  
  // Add Matrix processing
  
  {
    vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
    vec4 tmp = res;
    res = mat4(0.69545224135745187, 0.044794563372037716, -0.0055258825581135443, 0., 0.14067869647029416, 0.85967111845642163, 0.0040252103059786595, 0., 0.16386906217225405, 0.0955343181715404, 1.0015006722521349, 0., 0., 0., 0., 1.) * tmp;
    outColor.rgb = vec3(res.x, res.y, res.z);
    outColor.a = res.w;
  }
  
  // Add Range processing
  
  {
    outColor.rgb = max(vec3(0., 0., 0.), outColor.rgb);
  }
  
  // Add Matrix processing
  
  {
    vec4 res = vec4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
    vec4 tmp = res;
    res = mat4(2.5216861867438798, -0.27647991422992202, -0.015378064966034201, 0., -1.1341309882397199, 1.37271908766826, -0.152975335867399, 0., -0.38755519850416398, -0.096239173438334005, 1.16835340083343, 0., 0., 0., 0., 1.) * tmp;
    outColor.rgb = vec3(res.x, res.y, res.z);
    outColor.a = res.w;
  }

  return outColor;
}

Issues With Texture Resources¶

From an integration point of view any introduction of texture lookups requires resource declarations in the code. (such as the uniform sampler2D mx_ACEScc_to_lin_rec709_color4_ocio_lut1d_0Sampler; sampler declaration).

  1. The only way to handle these is to have additional logic added for code insertion of color transforms, such that the shader function declarations and resources can be inserted into the code independently. The current MaterialX code generation logic does not otherwise support this using the "default color system".

    Note : An experiment was attempted previously but does not align with the current proposal to have stand-alone node definitions. It was thus abandoned. ( For those interested the full code with code changes can be found here). Here 1D lookups (LUTS) were specified as input arrays and code generation created 1D textures dynamically based on the array inputs. 3D lookups were not handled.

  2. From the point of view of creating node graphs, any implementation resource dependencies means it cannot be cleanly wrapped up into a self-contained node definition and implementation.

For now these can be "skipped" until such time as they are require, or the implementation changes to avoid using these.

Finding Transforms Using Texture Resources¶

We can re-iterate through all of the transforms of interest, and find these transforms using the following code.

Note that the code generation is not necessary but is written this way to reuse the existing utility generateShaderCode2).

In [11]:
# Scan through all the color spaces on the configs to check for texture resource usage.
testedSources = set()
for c in configs:
    config = OCIO.Config.CreateFromBuiltinConfig(c)
    colorSpaces = config.getColorSpaces()
    for colorSpace in colorSpaces:
        colorSpaceName = colorSpace.getName()
        # Skip if the colorspace is already tested
        if colorSpaceName in testedSources:
            continue
        testedSources.add(colorSpaceName)

        # Test for texture resource usage
        code, textureCount = generateShaderCode2(config, colorSpace.getName(), targetColorSpace, language)
        if textureCount:
            print('- Transform "%s" to "%s" requires %d texture resources' % (colorSpace.getName(), targetColorSpace, textureCount))
- Transform "Rec.2100-PQ - Display" to "lin_rec709" requires 1 texture resources
- Transform "ST2084-P3-D65 - Display" to "lin_rec709" requires 1 texture resources
- Transform "ACEScc" to "lin_rec709" requires 1 texture resources
- Transform "Rec.2100-HLG - Display" to "lin_rec709" requires 1 texture resources
- Transform "ADX10" to "lin_rec709" requires 1 texture resources
- Transform "ADX16" to "lin_rec709" requires 1 texture resources
- Transform "Apple Log" to "lin_rec709" requires 1 texture resources
- Transform "CanonLog2 CinemaGamut D55" to "lin_rec709" requires 1 texture resources
- Transform "CanonLog3 CinemaGamut D55" to "lin_rec709" requires 1 texture resources

Target Language Support¶

At time of writing the target languages supported by OCIO and MaterialX differ. This includes non-core support such as MDL and current versions of OSL. Also as no logical operators are provided as with MaterialX, targets such as Vex which parses and maps MaterialX nodes as operators is not easy to do.

OCIO and MaterialX recently added in Metal language support. It is to be checked if there would be any issues with the additional struct wrappers required for this language as it is uncommon for MaterialX code generation to call into a struct function at the current time.

In [12]:
sourceColorSpace = "acescg"
language = OCIO.GpuLanguage.GPU_LANGUAGE_MSL_2_0
code, textureCount = generateShaderCode2(builtinCfgC, sourceColorSpace, targetColorSpace, language)
if code:
    code = code.replace("// Declaration of the OCIO shader function\n", "// " + sourceColorSpace + " to " + targetColorSpace + " function\n")
    code = '```c++\n' + code + '\n```\n'
    md = '<details><summary>MSL struct usage</summary>\n\n' + code + '</details>'
    display_markdown(md, raw=True)
MSL struct usage
// Declaration of class wrapper

struct mx_acescg_to_lin_rec709_color4mx_acescg_to_lin_rec709_color4
{
mx_acescg_to_lin_rec709_color4mx_acescg_to_lin_rec709_color4(
)
{
}


// acescg to lin_rec709 function

float4 mx_acescg_to_lin_rec709_color4(float4 inPixel)
{
  float4 outColor = inPixel;
  
  // Add Matrix processing
  
  {
    float4 res = float4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
    float4 tmp = res;
    res = float4x4(1.7050509926579815, -0.1302564175070435, -0.024003356804618042, 0., -0.62179212065700562, 1.1408047365754048, -0.1289689760649709, 0., -0.0832588720009797, -0.010548319068357653, 1.1529723328695858, 0., 0., 0., 0., 1.) * tmp;
    outColor.rgb = float3(res.x, res.y, res.z);
    outColor.a = res.w;
  }

  return outColor;
}

// Close class wrapper


};
float4 mx_acescg_to_lin_rec709_color4(
  float4 inPixel)
{
  return mx_acescg_to_lin_rec709_color4mx_acescg_to_lin_rec709_color4(
  ).mx_acescg_to_lin_rec709_color4(inPixel);
}

Using version 2.3 to access OSL there appears to be additional issues with the code generated as additional utility functions may be inserted which are not renamed to avoid collisions.

For example functions called max(), pow() etc are added which are outside the scope of the main shader declaration for which do not seem to be included in the logic for unique function name. As well as include additional include files which should be part of the OSL distribution. These need to be stripped out to embed this code as part of a larger OSL shader which already includes these functions to avoid name clashes. An issue has been logged for this.

As OSL integrations will generally perform color management outside of the shader, it is to be seen if this is important enough to address.

In [13]:
if OCIO.GpuLanguage.LANGUAGE_OSL_1:
    sourceColorSpace = "acescg"
    language = OCIO.GpuLanguage.LANGUAGE_OSL_1
    code, textureCount = generateShaderCode2(builtinCfgC, sourceColorSpace, targetColorSpace, language)
    if code:
        # Bit of ugly patching to make the main function name consistent.
        transformName = createTransformName(sourceColorSpace, targetColorSpace, 'color4')
        code = code.replace('OSL_' + transformName, '__temp_name__')
        code = code.replace(transformName, transformName + '_impl')
        code = code.replace('__temp_name__', transformName)
        code = code.replace("// Declaration of the OCIO shader function\n", "// " + sourceColorSpace + " to " + targetColorSpace + " function\n")
        code = '```c++\n' + code + '\n```\n'
        md = '<details><summary>OSL dependent function / includes code</summary>\n\n' + code + '</details>'
        display_markdown(md, raw=True)
OSL dependent function / includes code
/* All the includes */

#include "vector4.h"
#include "color4.h"

/* All the generic helper methods */

vector4 __operator__mul__(matrix m, vector4 v)
{
  return vector4(v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], 
                 v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3], 
                 v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3], 
                 v.x * m[3][0] + v.y * m[3][1] + v.z * m[3][2] + v.w * m[3][3]);
}

vector4 __operator__mul__(color4 c, vector4 v)
{
  return vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a) * v;
}

vector4 __operator__mul__(vector4 v, color4 c)
{
  return v * vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a);
}

vector4 __operator__sub__(color4 c, vector4 v)
{
  return vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a) - v;
}

vector4 __operator__add__(vector4 v, color4 c)
{
  return v + vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a);
}

vector4 __operator__add__(color4 c, vector4 v)
{
  return vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a) + v;
}

vector4 pow(color4 c, vector4 v)
{
  return pow(vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a), v);
}

vector4 max(vector4 v, color4 c)
{
  return max(v, vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a));
}

/* The shader implementation */

shader mx_acescg_to_lin_rec709_color4(color4 inColor = {color(0), 1}, output color4 outColor = {color(0), 1})
{

// acescg to lin_rec709 function

color4 mx_acescg_to_lin_rec709_color4_impl(color4 inPixel)
{
  color4 outColor = inPixel;
  
  // Add Matrix processing
  
  {
    vector4 res = vector4(outColor.rgb.r, outColor.rgb.g, outColor.rgb.b, outColor.a);
    vector4 tmp = res;
    res = matrix(1.7050509926579815, -0.62179212065700562, -0.0832588720009797, 0., -0.1302564175070435, 1.1408047365754048, -0.010548319068357653, 0., -0.024003356804618042, -0.1289689760649709, 1.1529723328695858, 0., 0., 0., 0., 1.) * tmp;
    outColor.rgb = vector(res.x, res.y, res.z);
    outColor.a = res.w;
  }

  return outColor;
}

outColor = mx_acescg_to_lin_rec709_color4_impl(inColor);
}

Creating MaterialX Node Definitions / Implementation¶

Given source code for now, it is still possible to create implementations and node definitions. If in the future the implementations can become MaterialX node graphs then the definition interface can still be used.

To create a new definition:

  1. The source and target color space is used to derive:
    • a transform name: using the previously described createTransformName() utility
    • a node name by replace the 'mx_' function name with the "standard" 'ND_' prefix used for definition
    • a node category
  2. Use addNodeDef() API to add a new definition
  3. Set node group to be colortransform which is the recommended group for new color transforms.
  4. Add a single input and output of the appropriate type (color3 or color4).
  5. Set a default value on the input. For this code we assume the defaul to be opaque black.

Thie logic is encapsulated in a new generateMaterialXDefinition() utility function.

In [14]:
def generateMaterialXDefinition(doc, sourceColorSpace, targetColorSpace, inputName, type):

    # Create a definition
    transformName = createTransformName(sourceColorSpace, targetColorSpace, type)
    nodeName = transformName.replace('mx_', 'ND_')

    comment = doc.addChildOfCategory('comment')
    comment.setDocString(' Color space %s to %s transform. Generated via OCIO. ' % (sourceColorSpace, targetColorSpace))

    definition = doc.addNodeDef(nodeName, 'color4')
    category = sourceColorSpace + '_to_' + targetColorSpace
    definition.setNodeString(category)
    definition.setNodeGroup('colortransform')

    defaultValueString = '0.0 0.0 0.0 1.0'
    defaultValue = mx.createValueFromStrings(defaultValueString, 'color4')
    input = definition.addInput(inputName, type)
    input.setValue(defaultValue)
    output = definition.getOutput('out')
    output.setAttribute('default', 'in')

    return definition

Another utility called writeShaderCode() is used to write the code to file following the "standard" MaterialX naming convention.

In [15]:
def writeShaderCode(code, transformName, extension, target):

    # Write source code file
    filename = mx.FilePath('./data') / mx.FilePath(transformName + '.' + extension)
    print('Write target[%s] source file %s' % (target,filename.asString()))
    f = open(filename.asString(), 'w')
    f.write(code)
    f.close()

The implementation creation logic is encapsulated in a createMaterialXImplementation() utility function which appends a new implementation to an existing Document.

The transform name is assumged to be precreated using createTransformName().

This is used to create a unique implementation Element name, and source code filename. We decied to use a file on disk as it is not possible to inline 1 or more function functions created by OCIO.

The implementation is associated with an existing node definition which is passed in and a target is explicit set to indicate which shading language (target) the implementation is for.

In [16]:
def createMaterialXImplementation(doc, definition, transformName, extension, target):
    '''
    Create a new implementation in a document for a given definition.
    '''
    implName = transformName + '_' + target
    filename = transformName + '.' + extension
    implName = implName.replace('mx_', 'IM_')

    # Check if implementation already exists
    impl = doc.getImplementation(implName)
    if impl:
        print('Implementation already exists: %s' % implName)
        return impl

    comment = doc.addChildOfCategory('comment')
    comment.setDocString(' Color space %s to %s transform. Generated via OCIO for target: %s' 
                         % (sourceColorSpace, targetColorSpace, target))
    impl = doc.addImplementation(implName)
    impl.setFile(filename)
    impl.setFunction(transformName)
    impl.setTarget(target)
    impl.setNodeDef(definition)

    return impl

Finally a small utility is added to write the document to disk.

In [17]:
def writeDocument(doc, filename):
    print('Write MaterialX file:', filename.asString())
    mx.writeToXmlFile(doc, filename)

Using these utilities we:

  • Create separate definition and implementation Documents.
  • Generate shader code for GLSL, MSL, and OSL`` for the same color transform. (OSL` is available in version 2.3).
  • Create a new definition for that transform
  • Create a new implementation for each shader code result
In [18]:
# Example to create:
# - source code for a given transform for 2 shader targets
# - A definition wrapper for the source
# - An implementations per source code. All implementations are associated with single definition
definitionDoc = mx.createDocument()
definition = None

implDoc = mx.createDocument()

sourceColorSpace = "acescg"
type = 'color4'
transformName = createTransformName(sourceColorSpace, targetColorSpace, type)

# All code has the same input name
# It is possible to use a different name than the name used in the generated function ('inPixel')
#IN_PIXEL_STRING = 'inPixel'
IN_PIXEL_STRING = 'in'

# Pick a source and target color space
sourceColorSpace = 'acescg'
targetColorSpace = 'lin_rec709'

# List of MaterialX target language, source code extensions, and OCIO GPU languages
generationList = [#['genmsl', 'metal', OCIO.GpuLanguage.GPU_LANGUAGE_MSL_2_0],
                  ['genglsl', 'glsl', OCIO.GpuLanguage.GPU_LANGUAGE_GLSL_4_0] ]

if OCIO.GpuLanguage.LANGUAGE_OSL_1:
    generationList.append(['genosl', 'osl', OCIO.GpuLanguage.LANGUAGE_OSL_1])

for gen in generationList:
    target = gen[0]
    extension = gen[1]
    language = gen[2]

    code, textureCount = generateShaderCode2(builtinCfgC, sourceColorSpace, targetColorSpace, language)
    if code:
        # Emit the source code file
        writeShaderCode(code, transformName, extension, target)

        # Create the definition once
        if not definition:
            definition = generateMaterialXDefinition(definitionDoc, sourceColorSpace, targetColorSpace, 
                                                    IN_PIXEL_STRING, type)
        
        # Create the implementation
        createMaterialXImplementation(implDoc, definition, transformName, extension, target)
Write target[genglsl] source file .\data\mx_acescg_to_lin_rec709_color4.glsl
Write target[genosl] source file .\data\mx_acescg_to_lin_rec709_color4.osl

The resulting MaterialX wrappers are then written to disk as follows:

In [ ]:
 

Variant Creation¶

Given a node definition for the color4 variant is is possible to create a functional graph and corresponding definition for a color3 variant. The graph simple convertes from color3 to color4 before connecting to the transform and then converts back to color3 for output.

In [19]:
color4Name = definition.getName()
color3Name = color4Name.replace('color4', 'color3')
color3Def = definitionDoc.addNodeDef(color3Name)
color3Def.copyContentFrom(definition)
c3input = color3Def.getInput(IN_PIXEL_STRING)
c3input.setType('color3')
c3input.setValue(mx.createValueFromStrings('0.0 0.0 0.0', 'color3'))
    
ngName = color3Def.getName().replace('ND_', 'NG_')
ng = definitionDoc.addNodeGraph(ngName)
c4instance = ng.addNodeInstance(definition)
c4instance.addInputsFromNodeDef()
c4instanceIn = c4instance.getInput(IN_PIXEL_STRING)
c3to4 = ng.addNode('convert', 'c3to4', 'color4')
c3to4Input = c3to4.addInput('in', 'color3')
c4to3 = ng.addNode('convert', 'c4to3', 'color3')
c4to3Input = c4to3.addInput('in', 'color4')
ngout = ng.addOutput('out', 'color3')
#ngin = ng.addInput('in', 'color3')
ng.setNodeDef(color3Def)

c4instanceIn.setNodeName(c3to4.getName())
c4to3Input.setNodeName(c4instance.getName())
ngout.setNodeName(c4to3.getName())
c3to4Input.setInterfaceName(IN_PIXEL_STRING)

result = mx.writeToXmlString(definitionDoc)
display_markdown('#### Generated Color3 Variant\n' + '```xml\n' + result + '```\n', raw=True)

valid, log = definitionDoc.validate()
if not valid:
    print('Document created is invalid:', log)

filename = mx.FilePath('./data') / mx.FilePath(definition.getName() + '_2.' + 'mtlx')
print('Write MaterialX definition variant file:', filename.asString())
mx.writeToXmlFile(definitionDoc, filename)

Generated Color3 Variant¶

<?xml version="1.0"?>
<materialx version="1.39">
  <!-- Color space acescg to lin_rec709 transform. Generated via OCIO. -->
  <nodedef name="ND_acescg_to_lin_rec709_color4" node="acescg_to_lin_rec709" nodegroup="colortransform">
    <output name="out" type="color4" default="in" />
    <input name="in" type="color4" value="0, 0, 0, 1" />
  </nodedef>
  <nodedef name="ND_acescg_to_lin_rec709_color3" node="acescg_to_lin_rec709" nodegroup="colortransform">
    <output name="out" type="color3" />
    <input name="in" type="color3" value="0, 0, 0" />
  </nodedef>
  <nodegraph name="NG_acescg_to_lin_rec709_color3" nodedef="ND_acescg_to_lin_rec709_color3">
    <acescg_to_lin_rec709 name="node1" type="color4" nodedef="ND_acescg_to_lin_rec709_color4">
      <input name="in" type="color4" value="0, 0, 0, 1" nodename="c3to4" />
    </acescg_to_lin_rec709>
    <convert name="c3to4" type="color4">
      <input name="in" type="color3" interfacename="in" />
    </convert>
    <convert name="c4to3" type="color3">
      <input name="in" type="color4" nodename="node1" />
    </convert>
    <output name="out" type="color3" nodename="c4to3" />
  </nodegraph>
</materialx>
Document created is invalid: Node input has too many bindings: <input name="in" type="color4" value="0, 0, 0, 1" nodename="c3to4">

Write MaterialX definition variant file: .\data\ND_acescg_to_lin_rec709_color4_2.mtlx

MaterialX Standard Library Inclusion¶

It is possible to add a new color space transform to the "standard" MaterialX library locations. This can be done for local testing for in some cases when additional search paths are not supported.

Introduced with version 1.38.7, the location of definitions and implementations can be found in the cmlib folder under the installation libraries location. Note that target specific source file directories were removed as all implementations are now target independent node graphs.

To include source file implementations the appropriate target folders can be added in. Under that folder an implementation file can be added for each target along with associated source files. The new definition can be added to `cmlib_defs.mtlx.

See the Creating Definitions book for more on how set up new definitions.

The standard library folder structure is partially shown below. The bolded items would be the ones of interest. The stdlib folder is also shown to show how each folder follows the same naming and hierarchy conventions.


  • cmlib // Color space transform library
    • cmlib_defs.mtlx // definitions file
    • cmlib_ng.mtlx // functional node graphs file
    • genglsl // GLSL implementation folder
      • cmlib_genglsl_impl.mtlx // Implementation declarations
      • GLSL files reside here
    • genmsl // MSL implementation folder
      • cmlib_genmsl_impl.mtlx // Implementation declarations
      • MSL files reside here
  • stdlib // "Standard" node library
    • genglsl
      • stdlib_genglsl_impl.mtlx
    • genmdl
    • genmsl
      • stdlib_genmsl_impl.mtlx
    • genosl
    • targets

Future Exploration¶

At time of writing (September 2024), the NanoColor initiative is underway. The current plan is to allow pre-processing of transforms to create MaterialX definitions with graph implementation. See the next section for some unofficial prototyping.

As there is the intent to provide Javascript bindings it will be interesting to see how this will interact with Web libraries and how it can work with the glTF Texture Procedurals extension.

NodeGraph Prototype¶

The following is some prototype code to extract out the list of transforms and attempt to create corresponding MaterialX nodes. It currently only handles matrix operations.

As a first step instead of extracting out code the list of transforms is extracted. A GPU processor or CPU processor can be used. (Not sure if there is any difference which processor is used). This logic is given in the generateTransformGraph utility

In [20]:
def generateTransformGraph(config, sourceColorSpace, destColorSpace):
    if not config:
        return None

    # Create a processor for a pair of colorspaces (namely to go to linear)
    processor = None
    groupTransform = None
    try:
        processor = config.getProcessor(sourceColorSpace, destColorSpace)
    except:
        print('Failed to get processor for: %s -> %s' % (sourceColorSpace, destColorSpace))
        return groupTransform

    if processor:
        processor = processor.getOptimizedProcessor(OCIO.OPTIMIZATION_ALL) 
        groupTransform = processor.createGroupTransform()
    
    return groupTransform

Next we use this to extract out the list of transforms and iterate over them to pull out information per transform.

The basic 'template' for creating a new MaterialX definition is a single new nodedef with one input and one output. In this case we use color3 as the input and output type.

For each transform a new corresponding MaterialX node is created. For now the logic only handles matrix tranforms. These are chained together incrementally. All computations work on vector3 data.

All nodes are encapsulated into a functional nodegraph implementation with the appropriate conversion to/from color3 to vector3 is performed.

In [21]:
groupTransform = generateTransformGraph(builtinCfgC, sourceColorSpace, targetColorSpace)
result = f'{groupTransform}'
display_markdown('#### Extracted Transform\n' + '```xml\n' + result + '```\n', raw=True)

# To add. Proper testing of unsupported transforms...
invalidTransforms = [ OCIO.TransformType.TRANSFORM_TYPE_LUT3D, OCIO.TransformType.TRANSFORM_TYPE_LUT1D, 
                     OCIO.TransformType.TRANSFORM_TYPE_RANGE, 
                     OCIO.TransformType.TRANSFORM_TYPE_GRADING_PRIMARY ]

# Create a document, a nodedef and a functional graph.
graphDoc = mx.createDocument()
outputType = 'color3'
xformName = sourceColorSpace + '_to_' + targetColorSpace + '_' + outputType
nd = graphDoc.addNodeDef('ND_' + xformName )
nd.setAttribute('node', xformName)
ndInput = nd.addInput('in', 'color3')
ndInput.setValue(mx.createValueFromStrings('0.0 0.0 0.0', 'color3'))
ng = graphDoc.addNodeGraph('NG_' + xformName)
ng.setAttribute('nodedef', nd.getName())
convertNode = ng.addNode('convert', 'asVec', 'vector3')
converInput = convertNode.addInput('in', 'color3')
converInput.setInterfaceName('in')

print(f'Transform from: {sourceColorSpace} to {targetColorSpace}')
print(f'Number of transforms: {groupTransform.__len__()}')
previousNode = None

# Iterate and create appropriate nodes and connections
for i in range(groupTransform.__len__()):
    transform = groupTransform.__getitem__(i)
    # Get type of transform
    transformType = transform.getTransformType()
    if transformType in invalidTransforms:
        print(f'- Transform[{i}]: {transformType} contains an unsupported transform type')
        continue

    #print(f'- Transform[{i}]: {transformType}')   
    if transformType == OCIO.TransformType.TRANSFORM_TYPE_MATRIX:
        matrixNode = ng.addNode('transform', ng.createValidChildName(f'matrixTransform'), 'vector3')

        # Route output from previous node as input of current node
        inInput = matrixNode.addInput('in', 'vector3')
        if previousNode:            
            inInput.setAttribute('nodename', previousNode)
        else:
            if i==0:
                inInput.setAttribute('nodename', 'asVec')
            else:
                inInput.setValue(mx.createValueFromStrings('0.0 0.0 0.0', 'vector3'))

        # Set matrix value
        matInput = matrixNode.addInput('mat', 'matrix33')
        matrixValue = transform.getMatrix()
        # Extract 3x3 matrix from 4x4 matrix
        matrixValue = matrixValue[0:3] + matrixValue[4:7] + matrixValue[8:11]
        matrixValue = ', '.join([str(x) for x in matrixValue])
        #print('  - Matrix:', matrixValue)
        matInput.setAttribute('value', matrixValue)        

        # Add offset value
        offsetValue = transform.getOffset()
        offsetValue = ', '.join([str(x) for x in offsetValue])
        #print('  - Offset:', offsetValue)
        # Add a add vector3 to graph

        previousNode = matrixNode.getName()
    #elif transformType == OCIO.TransformType.TRANSFORM_TYPE_LOG:
    #    print('  - Base:', transform.getBase())

# Create an output for the last node if any
convertNode2 = ng.addNode('convert', 'asColor', 'color3')
converInput2 = convertNode2.addInput('in', 'vector3')
converInput2.setAttribute('nodename', previousNode)
if previousNode:
    out = ng.addOutput(ng.createValidChildName('out'), 'color3')
    out.setAttribute('nodename', 'asColor')

# Write the graph document
print('---------------------------')
print('Write OCIO transform graph file:', xformName + '.' + 'mtlx')
filename = mx.FilePath('./data') / mx.FilePath(xformName + '.' + 'mtlx')
mx.writeToXmlFile(graphDoc, filename)

result = mx.writeToXmlString(graphDoc)
display_markdown('#### Generated Transform Graph\n' + '```xml\n' + result + '```\n', raw=True)

Extracted Transform¶

<GroupTransform direction=forward, transforms=
        <MatrixTransform direction=forward, fileindepth=unknown, fileoutdepth=unknown, matrix=1.705050992657982 -0.6217921206570056 -0.0832588720009797 0 -0.1302564175070435 1.140804736575405 -0.01054831906835765 0 -0.02400335680461804 -0.1289689760649709 1.152972332869586 0 0 0 0 1, offset=0 0 0 0>>```
Transform from: acescg to lin_rec709
Number of transforms: 1
---------------------------
Write OCIO transform graph file: acescg_to_lin_rec709_color3.mtlx

Generated Transform Graph¶

<?xml version="1.0"?>
<materialx version="1.39">
  <nodedef name="ND_acescg_to_lin_rec709_color3" node="acescg_to_lin_rec709_color3">
    <output name="out" type="color3" />
    <input name="in" type="color3" value="0, 0, 0" />
  </nodedef>
  <nodegraph name="NG_acescg_to_lin_rec709_color3" nodedef="ND_acescg_to_lin_rec709_color3">
    <convert name="asVec" type="vector3">
      <input name="in" type="color3" interfacename="in" />
    </convert>
    <transform name="matrixTransform" type="vector3">
      <input name="in" type="vector3" nodename="asVec" />
      <input name="mat" type="matrix33" value="1.7050509926579815, -0.6217921206570056, -0.0832588720009797, -0.1302564175070435, 1.1408047365754048, -0.010548319068357653, -0.024003356804618042, -0.1289689760649709, 1.1529723328695858" />
    </transform>
    <convert name="asColor" type="color3">
      <input name="in" type="vector3" nodename="matrixTransform" />
    </convert>
    <output name="out" type="color3" nodename="asColor" />
  </nodegraph>
</materialx>