├── .gitignore
├── CHANGELOG.md
├── README.md
├── docs
├── cryptomatte_logo.svg
├── encryptomatteProperties.png
├── fusion.md
├── fusionInstallDefaults.png
├── fusionInstallUser.png
├── fusionUsageComp.png
├── fusionUsageFuseAdvanced.png
├── fusionUsageFuseControls.png
├── github-zip.png
├── gizmoProperties.png
├── header.png
├── nuke.md
└── nukeScreenshot.jpg
├── fusion
├── Config
│ └── cryptomatte_shortcuts.fu
├── Fuses
│ └── Matte
│ │ └── cryptomatte.fuse
└── Modules
│ └── Lua
│ ├── cryptomatte_utilities.lua
│ └── test_cryptomatte_utilities.lua
├── license.txt
├── nuke
├── Cryptomatte.gizmo
├── Encryptomatte.gizmo
├── cryptomatte_logo.png
├── cryptomatte_utilities.py
├── cryptomatte_utilities_tests.py
├── init.py
├── menu.py
└── pymmh3.py
├── sample_images
├── bunny_CryptoAsset.exr
├── bunny_CryptoMaterial.exr
├── bunny_CryptoObject.exr
├── cornellBox_CryptoWildcard.0001.exr
├── cornellBox_CryptoWildcard.0002.exr
├── debug_images
│ ├── about.md
│ ├── multichannel.exr
│ ├── sidecar_manifest.crypto_asset.json
│ ├── sidecar_manifest.exr
│ └── special_chars.exr
├── sidecar_manifest
│ ├── bunny_CryptoObject.exr
│ └── bunny_CryptoObject_manifest.json
└── testGrid_CryptoObject.exr
└── specification
├── IDmattes_poster.pdf
└── cryptomatte_specification.pdf
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vscode/
3 | .DS_Store
4 | *.pyc
5 | Thumbs.db
6 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### 1.4.0:
2 |
3 | 1.4.0 is a major update for both the Fusion and Nuke side.
4 |
5 | The Fusion plugin has been overhauled by Cédric Duriau. Importantly this fixes a key memory issue causing glitches (#117). It uses less memory in general and is 10-30% faster both interactively and in render times. The user interface has been improved and fine tuned for Resolve. On the development side, it now features a test suite written in Lua.
6 |
7 | The Nuke plugin is also updated with a major new feature, Wildcard support. This is based largely on work done by Veronica Tello during her time at Method Studios. See [Nuke Documentation](/docs/nuke.md#Wildcards) for more information on wildcards.
8 |
9 | Also in Nuke news, Foundry's Nuke 13 now has a native Cryptomatte integration, which leads to obvious questions about the future of this Nuke integration and the purpose of this release. This release is likely the last major release for this Nuke plugin. While this is sad for me to write, it's also worth celebrating. "The goal of releasing Cryptomatte is to turn it into an ecosystem around an open standard", as we say on the front page of the repo, and there is now a robust ecosystem of Cryptomatte readers and writers. This repository still hosts the Cryptomatte standard as well, which is the central part, and not any one implementation.
10 |
11 | This release of the Nuke plug-in gets features released that have sat in beta for a long time, is tested in the newest versions of Nuke, and provides an off-ramp for Nuke users to make the transition. It also remains available for users who rely on the current functionality or need their existing Nuke scripts to continue working.
12 |
13 | Thank you to all our users for taking this journey with us, to Psyop for supporting this project, and everyone who contributed with everything from code contributions to bug fixes to encouragement.
14 |
15 | Nuke:
16 |
17 | * Official release of wildcards (Thanks @vtello, @maxnbk, and others!) See documentation.
18 | * Fixed unload manifest with special characters in names
19 |
20 | Fusion:
21 |
22 | * Fixed memory issue ([#46](https://github.com/Psyop/Cryptomatte/issues/46), [#117](https://github.com/Psyop/Cryptomatte/issues/117))
23 | * Fixed hex to float decoding bug for Cycles ([#120](https://github.com/Psyop/Cryptomatte/issues/120))
24 | * Improved performance ([cedricduriau#11](https://github.com/cedricduriau/Cryptomatte/pull/11))
25 | * Implemented multi-level logging ([cedricduriau#11](https://github.com/cedricduriau/Cryptomatte/pull/11))
26 | * Improved error management & logging ([#100](https://github.com/Psyop/Cryptomatte/issues/100), [#101](https://github.com/Psyop/Cryptomatte/issues/101), [#116](https://github.com/Psyop/Cryptomatte/issues/116))
27 | * Simplified GUI ([#136](https://github.com/Psyop/Cryptomatte/issues/136), [cedricduriau#29](https://github.com/cedricduriau/Cryptomatte/issues/29), [cedricduriau#33](https://github.com/cedricduriau/Cryptomatte/issues/33))
28 | * Added test suite ([cedricduriau#12](https://github.com/cedricduriau/Cryptomatte/issues/12))
29 | * Allow animatable controls ([cedricduriau#25](https://github.com/cedricduriau/Cryptomatte/issues/25), [cedricduriau#35](https://github.com/cedricduriau/Cryptomatte/issues/35))
30 |
31 | ### 1.3.0
32 |
33 | Nuke:
34 |
35 | * Updated to support both Python 3 and Python 2.7 with the same code (#134, thanks @PumpingPixels).
36 | * Python 2.6 is no longer supported. This means Nuke 6 and Nuke 7 are no longer supported.
37 | * Fixed #138- load metadata for this view only
38 |
39 | ### 1.2.8
40 |
41 | Nuke:
42 |
43 | Fixed a bug with copy and pasting with "Lock Layer Selection" on (#128)
44 |
45 | ### 1.2.7:
46 |
47 | Nuke:
48 |
49 | * Fixed issue where decryptomatte doesn't work inside groups (#127, contributed by Johannes Hezer)
50 |
51 | ### 1.2.6
52 |
53 | Nuke:
54 |
55 | * Fixed issue where a missing manifest would prevent keying (#124)
56 | * Fixed issue where nuke-unfriendly Cryptomatte names (crypto.material, 123_crypto) would cause issues and noise in tests
57 | * Fixed layer options not being available on Cryptomatte gizmos after scene open
58 |
59 | ### 1.2.5
60 |
61 | Nuke:
62 |
63 | * Added a version number display for users and scripts to test what version is used (#106)
64 | * Better support for Blender layer names (#114, thanks @aliasguru)
65 | * Scalable Cryptomatte logo (#119, thanks JF Panisset)
66 | * Fixed a callback error when tab-creating gizmos with an input selected (#109)
67 | * Fixed troubleshooting button when callbacks are not installed. (#112)
68 | * Tests pass in Nuke 12.0v3
69 |
70 | ### 1.2.4
71 |
72 | Nuke:
73 |
74 | * Performance improvement when keying by caching metadata. (#90)
75 | * Fixed for stereo renders by using nuke.thisView() (#103)
76 | * Fixed errors on open with more than 16 layers of Cryptomatte (#95)
77 | * Fixed gizmo for Blender channel names containing "." which get converted to underscores in Nuke, also fixed for Encryptomatte. (#104)
78 |
79 | ### 1.2.3:
80 |
81 | Nuke:
82 |
83 | * Fixed bug with hierarchical names (contributed by Jens Lindgren)
84 |
85 | ### 1.2.2:
86 |
87 | Fusion (by Cédric Duriau):
88 |
89 | * Support for EXR images with a data window smaller than display window (builtin DoD)
90 | * Fixed crash for Redshift frames with DoD [#80](https://github.com/Psyop/Cryptomatte/issues/80)
91 | * Fixed crash for Mantra frames with DoD [#64](https://github.com/Psyop/Cryptomatte/issues/64)
92 | * Updated README install documentation [#62](https://github.com/Psyop/Cryptomatte/issues/62)
93 | * Minimum Fusion version is now 9.0.2
94 | * Changed repo structure to match Fusion directory structure
95 | * Added Fuse registry information (help, company, version, ...)
96 | * Added dosctrings
97 | * Cleaned up code
98 |
99 | ### 1.2.1:
100 |
101 | A reorganization of this repo, and a minor update to the Nuke plugins.
102 |
103 | * Reorganized Fusion and Nuke documentation into separate files.
104 | * Added some tiny test images showing different cases of Cryptomatte usage.
105 |
106 | Nuke:
107 |
108 | * Added troubleshooting button to Cryptomatte gizmo
109 | * Fixed Encryptomatte issue where it couldn't start a new Cryptomatte with no inputs
110 | * Added test for Encryptomatte with no inputs
111 | * Do not allow keying IDs with zero coverage
112 | * Fixed some test issues in Nuke 11.3
113 | * Cleaner decryptomatte results, with maximum of 3 nodes in sequence, no dots, and better naming
114 |
115 |
116 | ### 1.2.0:
117 |
118 | This is a major update to both the Nuke plugins and Fusion plugins, and a minor update to the Cryptomatte specification.
119 |
120 | Specification:
121 |
122 | * Changed specification regarding sidecar manifests, such that they are always sidecars with relative paths.
123 | * Support for UTF-8 Characters in Nuke plugin and specification
124 | * Deprecated preview channels
125 |
126 | Nuke:
127 |
128 | * Encryptomatte
129 | * Added Encryptomatte - allows modifying or creating Cryptomattes in Nuke
130 | * Added support for sidecar manifests
131 | * Added layer selection pulldown
132 | * New Eyedropper "picker" knobs which use picker position and not sampled values
133 | * No longer use Color knob's built in picker
134 | * Fixed keying problems sometimes caused by GPU-enabled viewers
135 | * Can pick mattes while viewing downstream node (or looking at the RGB/beauty)
136 | * Enables new "Preview" (AKA: "Keyable Surface") options
137 | * "Preview" option provides 3 modes of visual feedback
138 | * "Colors" is an improved version of the old style random colors
139 | * "Edges" allows viewing input RGBA with borders around keyable regions
140 | * "None" allows viewing of input RGBA without borders, but with a visible highlight on selected areas
141 | * Colors now generated dynamically, removing need for preview channels
142 | * Enhancements for multi-channel inline workflow
143 | * "Matte Output" knob enables output to a custom channel
144 | * "Remove Channels" now defaults to false
145 | * "Matte only" now causes mattes to be written to R, G, B, A in addition to specified output
146 | * "Unpremultiply" option to unpremult output matte by input alpha
147 | * Support for special characters and UTF-8
148 | * Support for non-ascii unicode
149 | * Added support names containing spaces, commas, and angle brackets
150 | * Switched matte lists to be YAML-style (names with special characters are enclosed in quotes)
151 | * Added test suite
152 | * Added failfast with cleanup skipping to Nuke tests, to allow inspecting what went wrong
153 | * Bug fixes
154 | * Mixed selections of names and raw IDs now work correctly for all cases
155 | * Gizmo now works when read nodes have "do not attach prefix" enabled
156 | * Fixed rare issue where connections were lost on script load and copy and paste when used with channelmerge
157 | * Fixed (Beta only) bug Encryptomatte retains its layer selection properly
158 | * Fixed (Beta only) bug with PickerAdd and PickerRemove values stored in files
159 | * Fixed (Beta only) bug with errors on load with invalid Cryptomatte
160 |
161 | Fusion (by Cédric Duriau)
162 |
163 | * Minimum Fusion version is now 9.0.1.
164 | * Redesigned around new Fusion 9.0.1 features
165 | * Fuse now loads EXRs directly via the EXRIO module
166 | * For older versions, please use an older release (see GitHub releases)
167 | * Added support for sidecar manifests
168 | * Added layer selection slider with layer name display
169 | * Added "Preview" (AKA "Keyable Surface") options
170 | * Colors now generated dynamically, removing need for preview channels
171 | * Added shortcut configuration file ("cryptomatte_shortcut.fu")
172 | * Added "Toggle" button acting as a Add/Remove switch (Shift+T)
173 | * Added support special characters in selection lists
174 | * Known limitation: Commas in names are not yet supported
175 | * Performance Improvements
176 | * Optimized multi threaded functions
177 | * Added Support for mixed depth EXR images
178 | * Added Support for proxy mode
179 | * Using EXRIO module
180 | * Removed loader channel slots workaround
181 | * Removed "Update Loader" button
182 | * No longer limited to 8 cryptomatte ranks
183 | * Bug fixes
184 | * Improved "matte only" previewing
185 | * Keyable surface feature disabled when in matte only mode
186 | * Code improvements
187 | * Added version to file headers
188 | * Added "cryptomatte_utilities.lua" module
189 | * Added docstrings
190 | * Removed simplejson.lua module, using builtin dkjson module
191 | * Removed "struct.lua" dependency
192 |
193 | ### 1.1.4:
194 |
195 | * Fixes Fusion crash when rendering with FusionRenderConsole
196 |
197 | ### 1.1.3:
198 |
199 | * Adds beta version of Fusion support, also by Cédric Duriau and Kristof Indeherberge at Grid.
200 | * Major tool connection workflow improvement. No longer requires multiple loaders to work, instead populates single loader channel slots when viewed.
201 |
202 | ### 1.1.2:
203 |
204 | * Adds alpha version of Fusion support, created by Cédric Duriau and Kristof Indeherberge at Grid.
205 |
206 | ### 1.1.1:
207 |
208 | * Store channels on hidden knobs on Cryptomatte gizmo and decryptomatte expression nodes
209 | * Fixes expression node errors in batch mode
210 | * No longer prompts users on "decryptomatte selected"
211 | * Allow API users to use decryptomatte without prompt
212 | * Fixed error when loading gizmo in Nuke 7
213 |
214 | ### 1.1.0:
215 |
216 | * Changes to specification regarding storage of metadata
217 | * Enabled Nuke code to read this metadata
218 | * (1.1.0 Nuke plugin is compatible with older Cryptomattes)
219 | * No longer raises errors if no metadata is available (would happen in batch mode)
220 | * No longer raises errors if picker in is in single value mode rather than RGB
221 |
222 | ### 1.0.2:
223 |
224 | * Updated pymmh3 to output signed ints, in compliance with mmh3
225 |
226 | ### 1.0.1:
227 |
228 | * Added layer selection to gizmo and utilities (backwards compatible)
229 | * Added menu.py
230 | * Added `__version__` to cryptomatte_utilities.py
231 | * Bug fix - invalid manifest broke keying
232 |
233 | ### 1.0.0:
234 |
235 | * Initial release of Nuke plugins, specification, and sample images.
236 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Cryptomatte is a tool created at Psyop by Jonah Friedman and Andy Jones. It creates ID mattes automatically with support for motion blur, transparency, and depth of field, using organizational information already available at render time. This organizational information is usually names, object namespaces, and material names.
4 |
5 | * Demo video: [https://vimeo.com/136954966](https://vimeo.com/136954966)
6 | * Poster: [https://github.com/Psyop/Cryptomatte/raw/master/specification/IDmattes_poster.pdf](https://github.com/Psyop/Cryptomatte/raw/master/specification/IDmattes_poster.pdf)
7 |
8 | The goal of releasing Cryptomatte is to turn it into an ecosystem around an open standard. Any developers who wish to make plugins are welcome and encouraged to create tools that inter-operate with the components we are providing. We hope to see a diverse ecosystem of renderers that can create Cryptomatte images and plugins for compositing applications to decode them.
9 |
10 | Cryptomatte is licenced using the BSD 3-clause license. See [license.txt](license.txt).
11 |
12 | Version 1.4.0 See [changelog](CHANGELOG.md) for version history.
13 |
14 | ## Repo Contents
15 |
16 | The contents of this repository are:
17 |
18 | **Nuke:** This contains Python files, an image, and a gizmo. Together these are our implementation for Foundry's Nuke. In Nuke 13, there is also a [native implementation](https://learn.foundry.com/nuke/content/release_notes/nuke_13.0.html) which is similar to this one. This implementation is being kept active to allow for a smooth transition.
19 |
20 | **Fusion:** Fusion integration, including a Fuse file, a Lua module and a Fusion shortcut configuration file.
21 |
22 | **Sample Images:** These example Cryptomatte images can be used for testing your Nuke installation, or for testing other implimentations.
23 |
24 | **Specification:** This is a technical document describing the Cryptomatte standard. It specifies how Cryptomattes are structured, encoded, and decoded. It also contains our SIGGRAPH 2015 poster on the subject.
25 |
26 | ## Documentation
27 |
28 | * [Nuke Documentation](/docs/nuke.md) - Installation, usage instructions, troubleshooting
29 | * [Fusion Documentation](/docs/fusion.md) - Installation, usage instructions
30 |
31 | ## Implementations
32 |
33 | A list of released implementations and links:
34 |
35 | Encoders:
36 |
37 | * [Isotropix Clarisse 3.5 (By Isotropix)](http://www.isotropix.com/products/clarisse-3.5), [Demo](https://www.youtube.com/watch?v=V_ov8B24jq0)
38 | * [Chaos Group V-Ray 3.6 (By Chaos Group)](https://docs.chaosgroup.com/display/VRAY3MAX/Cryptomatte+%7C+VRayCryptomatte), [3DSMax demo](https://www.youtube.com/watch?v=tlahITki4xg), [Maya demo](https://www.youtube.com/watch?v=iVHcuke_aWk), [Nuke demo](https://www.youtube.com/watch?v=Vb4OX7UNIMw)
39 | * [3Delight for Katana and Maya 9.0](https://3delight.atlassian.net/wiki/spaces/3DFK/pages/220135565/Exporting+CryptoMatte+IDs)
40 | * [Houdini 16.5 Mantra (By Sidefx)](http://www.sidefx.com/docs/houdini/render/cryptomatte.html), [Demo](https://vimeo.com/241036613#t=2862s)
41 | * Blender 2.8.0 Cycles (By Tangent Animation and Blender Foundation): [Cryptomatte in Blender 2.8 Alpha 2! demo](https://www.youtube.com/watch?v=lTJJqAGnWFM), [Tutorial by Zacharias Reinhardt](https://zachariasreinhardt.com/blender-2-8-cryptomatte-tutorial), [Cycles for Animated Feature Film Production by Stefan Werner](https://www.youtube.com/watch?v=_2Ia4h8q3xs), [Docs](https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Cycles#Cryptomatte)
42 | * [Blender 2.92 Eevee (By Jeroen Bakker and Blender Foundation)](https://www.blender.org/download/releases/2-92/)
43 | * [Pixar RenderMan 21.7](https://rmanwiki.pixar.com/display/REN/RenderMan+21.7), [Docs](https://rmanwiki.pixar.com/display/REN/PxrCryptomatte)
44 | * LightWave 3D 2018 ([DB&W EXRTrader plugin](https://www.db-w.com/products/exrtrader))
45 | * [Redshift 2.6.11](https://www.redshift3d.com)
46 | * [Arnold 4 (AlShaders), by Jonah Friedman, Andy Jones, Anders Langlands.](http://www.anderslanglands.com/alshaders/index.html)
47 | * [Arnold 5 (CryptomatteArnold) by Jonah Friedman, Andy Jones, Anders Langlands.](https://github.com/anderslanglands/alShaders2)
48 | * Nuke 8+ "Encryptomatte", by Andy Jones. In this repo.
49 | * [Appleseed 2.1.0 by Sergo Pogosyan, Jon Dent](https://appleseedhq.net/2019/09/21/appleseed-2-1-0-beta-Released.html)
50 | * [Autodesk VRed](https://knowledge.autodesk.com/support/vred-products/learn-explore/caas/CloudHelp/cloudhelp/2020/ENU/VRED/files/Rendering/VRED-Rendering-How-to-Use-the-Cryptomatte-Options-html-html.html)
51 | * [Otoy OctaneRender for Cinema4D](http://www.aoktar.com/octane/OCTANE%20HELP%20MANUAL.html?Cryptomatte.html)
52 | * [Unreal Engine 4.26](https://docs.unrealengine.com/en-US/AnimatingObjects/Sequencer/Workflow/RenderAndExport/HighQualityMediaExport/RenderPasses/index.html)
53 | * [Unity Cryptomatte - Research Project](https://www.schmuckerdaniel.com/unitycryptomatte) By Daniel Schmuker at Filmakademie Baden-Wuerttemberg
54 | * [Foundry Modo 14.2 mPath Renderer](https://learn.foundry.com/modo/content/help/pages/rendering/render_outputs_cryptomatte.html)
55 |
56 | Decoders:
57 |
58 | * Nuke 8+, by Jonah Friedman, Andy Jones. In this repo.
59 | * [Foundry Nuke 13](https://learn.foundry.com/nuke/content/release_notes/nuke_13.0.html)
60 | * Fusion: by Cédric Duriau and Kristof Indeherberge at Grid. In this repo.
61 | * [Houdini 16.5 Compositor (By Sidefx)](http://www.sidefx.com/docs/houdini/render/cryptomatte.html), [Demo](https://vimeo.com/241036613#t=2862s)
62 | * Blender 2.8.0 Compositor (By Tangent Animation and Blender Foundation): [Cryptomatte in Blender 2.8 Alpha 2! demo](https://www.youtube.com/watch?v=lTJJqAGnWFM), [Tutorial by Zacharias Reinhardt](https://zachariasreinhardt.com/blender-2-8-cryptomatte-tutorial), [Cycles for Animated Feature Film Production by Stefan Werner](https://www.youtube.com/watch?v=_2Ia4h8q3xs), [Docs](https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Cycles#Cryptomatte)
63 | * [Autodesk Flame (Autodesk)](https://knowledge.autodesk.com/support/flame-products/learn-explore/caas/CloudHelp/cloudhelp/2020/ENU/Flame-EffectsandToolsReference/files/GUID-0402116E-B47C-4E32-9010-DB8C334853E0-htm.html)
64 | * [Adobe After Effects (Fnordware ProEXR plugin 2.0)](https://www.fnordware.com/ProEXR/)[Ships with After Effects 2020](https://theblog.adobe.com/adobe-after-effects-is-faster-than-ever/)
65 | * [Adobe Photoshop (EXR-IO 2)](https://www.exr-io.com/exr-io-2-00/)
66 | * [FilmLight Baselight v5](https://www.filmlight.ltd.uk/pdf/datasheets/FL-BL-DS-0847-Baselightv5.pdf)
67 | * [Natron](https://github.com/NatronGitHub/natron-plugins) by Fahad Hasan Pathik and Fabrice Fernandez
68 |
69 | ## Acknowledgements
70 |
71 | * Anders Langlands
72 | * Alon Gibli
73 | * Jean-Francois Panisset
74 | * Psyop
75 | * Solid Angle
76 | * All the members of the Cryptomatte Committee
77 | * Benoit Leveau
78 | * Cédric Duriau
79 | * Kristof Indeherberge
80 | * Vladimir Koylazov
81 | * Peter Loveday
82 | * Andrew Hazelden
83 | * Jens Lindgren
84 | * Rainer Trummer
85 | * Veronica Tello
86 | * Stephen Mackenzie
87 |
--------------------------------------------------------------------------------
/docs/cryptomatte_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
188 |
--------------------------------------------------------------------------------
/docs/encryptomatteProperties.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/encryptomatteProperties.png
--------------------------------------------------------------------------------
/docs/fusion.md:
--------------------------------------------------------------------------------
1 | ## Fusion Installation
2 |
3 | 1. Download the entire Cryptomatte GitHub repository using the green `Code` button. Select `Download ZIP` and then extract the contents.
4 |
5 | 2. Open Fusion and open the path mapping preferences.
6 |
7 | - `File` > `Preferences` > `Global and Default Settings` > `Path Map`
8 |
9 | 3. Add to the `User` section by clicking `New` to create a new path mapping entry. Fill in the settings as follows. Replace `{CRYPTOMATTE_DIRECTORY}` with the path to the downloaded and extracted Cryptomatte repository. (See screenshot `User` below.)
10 |
11 | - From: `Cryptomatte:`
12 | - To: `{CRYPTOMATTE_DIRECTORY}/fusion`
13 |
14 | 4. Add the newly created path map by selecting the `Defaults` section `UserPaths:` entry as following. (See screenshot `Defaults` below.)
15 |
16 | - From: `UserPaths:`
17 | - To: `UserData:;AllData:;Fusion:;Cryptomatte:;`
18 |
19 |
20 | User | Defaults
21 | :----: | :--------:
22 |  | 
23 |
24 | NOTE: If you copied files from previous releases into their respective Fusion supported directories, remove them to avoid conflicts with path mapping.
25 |
26 | ## Fusion Usage
27 |
28 | 
29 |
30 | The Cryptomatte Fuse works in Fusion (Free and Studio) v9.0.2+. The Fuse allows you to create matte selections using a Cryptomatte "Matte Locator" control that is positioned using the transform control in the Fusion Viewer window.
31 |
32 | To get started:
33 |
34 | 1. Add a Cryptomatte exr file to your composite, such as the sample images, using a Loader node.
35 | 2. Select the Loader node and use the Select Tool window (Shift + Spacebar) to add a new Cryptomatte node to your composite.
36 | 3. Select the Cryptomatte node in the Flow area and display the output in a Viewer window.
37 | 4. Position the Cryptomatte "Matte Locator" control in the Viewer window over an object in the frame.
38 | 5. Press the "Add" button in the Cryptomatte Tools view to add a new matte entry to the Matte List. Alternatively, you could press the "Shift + T" hotkey in the Fusion Viewer window to toggle the active Cryptomatte "Matte Locator" state between the "Add" and "Remove" selection modes.
39 |
40 | ### Cryptomatte Fuse
41 |
42 | Controls Tab | Advanced Tab
43 | :-----------------: | :-----------------:
44 |  | 
45 |
46 | Controls:
47 | - Matte Locator: Defines the position of the matte to interact with.
48 | - Add: Adds the name of the matte at the current position of the locator to the matte list.
49 | - Removes: Removes the name of the matte at the current position of the locator from matte list.
50 | - Toggle: Adds/Removes the name of the matte at the current position of the locator to/from matte list.
51 | - View Mode: Image to pick mattes on.
52 | - Colors: Unique colors per matte.
53 | - Edges: Input image with a colored border around mattes.
54 | - Beauty: Input image.
55 | - Matte: Monochannel matte image.
56 | - Matte List: A list of names to extract mattes from. This list may be modified in text form or using the controls.
57 | - Clear: Clears the matte list.
58 | - Layer Index: Index of the Cryptomatte EXR layer to use. Automatically set, can be changed manually.
59 | - Layer Name: Name of the Cryptomatte EXR layer for current index.
60 |
61 | Advanced:
62 | - Name Checker Locator: Defines the position of the matte to interact with.
63 | - Show: Shows the name checker locator.
64 | - Hide: Hides the name checker locator.
65 | - Matte Name: Name of the matte at the current name checker locator position.
66 |
67 | ## Logging
68 |
69 | Cryptomatte has a multi-level logging system which notifies the user in case of errors, warnings and process information. There are three log levels supported: `ERROR`, `WARNING` and `INFO`.
70 |
71 | To control the log level, determining what is printed in the console, you can set the `CRYPTOMATTE_LOG_LEVEL` environment variable as following. When no log level is set, `WARNING` is used as default.
72 |
73 | Log Level | Value
74 | --------- | -----
75 | ERROR | 0
76 | WARNING | 1
77 | INFO | 2
78 |
79 | ```lua
80 | -- example error
81 | [Cryptomatte][Cryptomatte1][ERROR] unknown view mode: 'nil'
82 | ...Cryptomatte/fusion/Modules/Lua/cryptomatte_utilities.lua:614: ERROR
83 | stack traceback:
84 | [C]: in function 'error'
85 | ...Cryptomatte/fusion/Modules/Lua/cryptomatte_utilities.lua:614: in function 'log_error'
86 | ...iau/repo/Cryptomatte/fusion/Fuses/Matte/cryptomatte.fuse:403: in function <...iau/repo/Cryptomatte/fusion/Fuses/Matte/cryptomatte.fuse:249>
87 | Cryptomatte1 failed at time 0
88 | ```
89 | ```lua
90 | -- example warning
91 | [Cryptomatte][Cryptomatte1][WARNING] matte not present in manifest: foo
92 | ```
93 | ```lua
94 | -- example info
95 | [Cryptomatte][Cryptomatte1][INFO] -- process started
96 | [Cryptomatte][Cryptomatte1][INFO] reading metadata ...
97 | [Cryptomatte][Cryptomatte1][INFO] setting layer name: 'uCryptoAsset'
98 | [Cryptomatte][Cryptomatte1][INFO] decoding manifest ...
99 | [Cryptomatte][Cryptomatte1][INFO] creating layer images ...
100 | [Cryptomatte][Cryptomatte1][INFO] reading matte names ...
101 | [Cryptomatte][Cryptomatte1][INFO] creating matte image ...
102 | [Cryptomatte][Cryptomatte1][INFO] creating 'Colors' preview image ...
103 | [Cryptomatte][Cryptomatte1][INFO] elapsed time: 2.202
104 | [Cryptomatte][Cryptomatte1][INFO] -- process ended
105 | ```
106 |
107 | ## Testing
108 | Cryptomatte for Fusion ships with two lua modules.
109 |
110 | 1. `cryptomatte_utilities.lua`
111 | 2. `test_cryptomatte_utilities.lua`
112 |
113 | The first being the utility module for the Fuse, the second is its test suite. This test suite was written to test and ensure functionalities are working and behave in an expected manner.
114 |
115 | The test suite is only used for development and **completely optional** for a functional Cryptomatte Fuse. If you wish to run the test suite yourself, you can do so by running the following snippet in the Fusion Lua script console.
116 |
117 | ```lua
118 | -- replace {PATH_TO_TEST_FILE} with the absolute path to the test file
119 | dofile("{PATH_TO_TEST_FILE}")
120 | ```
121 | ```lua
122 | -- example run
123 | dofile("/home/cduriau/repo/Cryptomatte/fusion/Modules/Lua/test_cryptomatte_utilities.lua")
124 | collectings test(s) ...
125 | detected 18 test(s) ...
126 | running tests ...
127 | [ 6%] cryptomatte_test__format_log ... [OK]
128 | [ 11%] cryptomatte_test__get_absolute_path ... [OK]
129 | [ 17%] cryptomatte_test__get_absolute_position ... [OK]
130 | [ 22%] cryptomatte_test__get_channel_hierarchy ... [OK]
131 | [ 28%] cryptomatte_test__get_log_level ... [OK]
132 | [ 33%] cryptomatte_test__hex_to_float ... [OK]
133 | [ 39%] cryptomatte_test__is_position_in_rect ... [OK]
134 | [ 44%] cryptomatte_test__solve_channel_name ... [OK]
135 | [ 50%] cryptomatte_test__string_ends_with ... [OK]
136 | [ 56%] cryptomatte_test__string_split ... [OK]
137 | [ 61%] cryptomatte_test__string_starts_with ... [OK]
138 | [ 67%] cryptomatte_test_decode_manifest ... [OK]
139 | [ 72%] cryptomatte_test_get_cryptomatte_metadata ... [OK]
140 | [ 78%] cryptomatte_test_get_matte_names ... [OK]
141 | [ 83%] cryptomatte_test_log_error ... [OK]
142 | [ 89%] cryptomatte_test_log_info ... [OK]
143 | [ 94%] cryptomatte_test_log_warning ... [OK]
144 | [100%] cryptomatte_test_read_manifest_file ... [OK]
145 | ```
146 |
--------------------------------------------------------------------------------
/docs/fusionInstallDefaults.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/fusionInstallDefaults.png
--------------------------------------------------------------------------------
/docs/fusionInstallUser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/fusionInstallUser.png
--------------------------------------------------------------------------------
/docs/fusionUsageComp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/fusionUsageComp.png
--------------------------------------------------------------------------------
/docs/fusionUsageFuseAdvanced.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/fusionUsageFuseAdvanced.png
--------------------------------------------------------------------------------
/docs/fusionUsageFuseControls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/fusionUsageFuseControls.png
--------------------------------------------------------------------------------
/docs/github-zip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/github-zip.png
--------------------------------------------------------------------------------
/docs/gizmoProperties.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/gizmoProperties.png
--------------------------------------------------------------------------------
/docs/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/header.png
--------------------------------------------------------------------------------
/docs/nuke.md:
--------------------------------------------------------------------------------
1 | ## Nuke Installation
2 |
3 | 1. Download the entire Cryptomatte GitHub repository using the green "Clone or download" button. Select "Download Zip" and then extract the contents.
4 | 2. Copy the contents of the "nuke" folder from Cryptomatte into a folder in your Nuke plugin path, such as your home directory's ".nuke" folder.
5 | 3. If the destination folder already contains an "init.py" and/or "menu.py" file, open those files in a text editor, and append the contents of the Cryptomatte "init.py" and "menu.py" to those files.
6 | 4. After launching Nuke, if you've installed the plugin correctly you should be able to tab-create a Cryptomatte gizmo.
7 |
8 | For more information on installing Nuke plugins, see:
9 |
10 | [https://www.thefoundry.co.uk/products/nuke/developers/105/pythondevguide/installing_plugins.html](https://www.thefoundry.co.uk/products/nuke/developers/105/pythondevguide/installing_plugins.html)
11 |
12 | To test the functionality, you can try loading one of the sample images supplied. Load the sample images into Nuke, select one of them, and tab-create the gizmo. Viewing the output of the gizmo should show you a preview of the available mattes. Use the color knob, "Picker Add" to eye-dropper colors on the image to create your mattes.
13 |
14 | ## Nuke Usage
15 |
16 | 
17 |
18 | To get started:
19 |
20 | 1. Load a Cryptomatte exr file, such as the sample images, using a Read node.
21 | 2. Select it, and tab create a Cryptomatte gizmo.
22 | 3. View the output of the gizmo. You should see a preview image (pictured).
23 | 4. Use the eyedropper with the 'Picker Add' knob to select objects. They should light up in RGB, and output the matte in Alpha. With the eyedropper, make sure you use control-click and not alt-control click.
24 |
25 | ### Cryptomatte Gizmo
26 |
27 | 
28 |
29 | Psyop Cryptomatte Tab:
30 |
31 | * Picker Add: This adds "keyed" objects to the matte selection, meant to be used with Nuke's eyedropper.
32 | * Picker Remove: This removes "keyed" objects from the matte selection, meant to be used with Nuke's eyedropper.
33 | * Preview: Controls whether or not previews of the matte boundaries are drawn. A pulldown controls how they are drawn.
34 | * "Edges" allows viewing input RGBA with borders around keyable regions
35 | * "Colors" is random colors per matte
36 | * "None" allows viewing of input RGBA without borders, but with a visible highlight on selected areas
37 | * Matte Only: Also write the matte to RGBA channels
38 | * Single Selection: Changes the gizmo behavior so that only one object may be selected at a time.
39 | * Expand Wildcards: Expands wildcards in names typed in the matte list.
40 | * Remove Channels: Removes the Cryptomatte channels so that downstream of the gizmo, the additional channels are not present.
41 | * Matte Output: Which channel the extracted matte is written to.
42 | * Unpremultiply: Unpremults the extracted matte against by the alpha.
43 | * Matte List: A list of names to extract mattes from. This list may be modified in text form or using the Picker color knobs.
44 | * Clear: Clears the matte list.
45 | * Force Update: The python scripts keep Cryptomatte gizmos updated when inputs or relevant knobs are changed. If there's a case that it does not update, this button will manually update it.
46 | * Stop Auto Update: Stops the automatic updating described above.
47 | * Layer Selection: If there are multiple Cryptomattes, this is how you select the layer. This is filled in automatically, but may be changed manually.
48 | * Lock Layer Selection: Stops the automatic updating of layer selection, which occurs if the specified selection is not available.
49 | * Expression: Internally the gizmo generates an expression to extract the matte. The expression is saved here.
50 |
51 | Advanced Tab:
52 |
53 | * Decryptomatte: Replaces gizmo with equivalent nodes
54 | * Unload Manifest: Generates a keyer for every name in the manifest.
55 | * Force Update All Gizmos in Script: Same as "Force Update", but runs the force update functionality on all Gizmos in the script.
56 |
57 | #### [Wildcards](#Wildcards)
58 |
59 | When `Use Wildcards` is enabled, typing a wildcard expression such as `flower*` into the Matte list will expand it to all names that it matches, such as `flower1`, `flower2`, etc.
60 |
61 | Simple cases:
62 |
63 | - To use a wildcard expression, enable `Use Wildcards` and add an expression to the matte list. This uses *fnmatch* style matching, which has the following features.
64 | - Wildcards (`*`)
65 | - `flower*` matches `flower1`, `flower3_petal`, `flower_stem`, but not `red_flower`.
66 | - `flower*petal` matches `flower3_petal` and `flower_rose_petal`, but not `flower_stem`.
67 | - Numeric wildcards (`?`)
68 | - `flower?` matches `flower25` but not `flower25_petal2`.
69 | - `flower?_petal?` matches `flower25_petal2`
70 |
71 | Finer points (advanced):
72 |
73 | - If `Use Wildcards` is not enabled, the name `*sterisk` is used as the literal string. This is however somewhat like having an unexploded bomb in your matte list - as soon as you enable wildcards it'll expand. Keying an object with an `*` in the name will add escape characters to the front, to ensure this doesn't happen.
74 | - For example, an object is literally named `*sterisk`, where some smartass put an asterisk into the name itself.
75 | - `\\*sterisk` means the literal name `*sterisk`. The escape characters (`\\`) preceding the `*` mean it is not an fnmatch expression, and will not change when enabling wild cards.
76 | - Keying an object named `*sterisk` will add `\\*sterisk` to your matte list, so that when wildcards are enabled it will not change.
77 | - It's possible to mixing wildcards and literal characters, like so:
78 | - `\\*sterisk*` will match `*sterisk1`, `*sterisk2`, `*sterisk3` and so on at the same time.
79 | - What if my name contains square brackets? (`Brack[et]`)
80 | - This is an even specialer case, as square brackets have meaning in both fnmatch and muke. Nuke will match the square brackets themselves. For a literal square bracket, these require three escape characters. In the matte list this will appear as `Brack\\\[et\\\]`.
81 | - Brackets are also used by fnmatch. In fnmatch, `[*]sterisk` is a way of writing a literal asterisk and will match only `*sterisk`.
82 | - Using this mechanism is too complicated due to multiple levels of escaping and is not recommended. Instead, use `\\*sterisk` in the matte list to signify a literal asterisk.
83 | - `\\*sterisk*` will match `*sterisk1`, `*sterisk2`, but not `asterisk1`.
84 |
85 |
86 | ### Encryptomatte Gizmo
87 |
88 | 
89 |
90 | Encryptomatte is a gizmo that can modify existing Cryptomattes, or start new ones. One Encryptomatte node adds one matte to a Cryptomatte.
91 |
92 | To get started:
93 |
94 | 1. Load a Cryptomatte with a read node.
95 | 2. Select it, and tab-create an Encryptomatte.
96 | 3. Feed in a matte that you would like to add to that Cryptomatte. You can put it over or under all other mattes.
97 | 4. Write it out as a 32 bit EXR with all metadata, or attach a Cryptomatte node to it to test the mattes.
98 |
99 | Encryptomatte tab:
100 |
101 | * Matte Name: The name your new matte will have in the Cryptomatte
102 | * Merge Operation: Where in the stack of mattes your matte will be added, over or under the rest
103 | * Layer selection: Same as Cryptomatte, see above.
104 | * Force Update: Same as Cryptomatte, see above.
105 | * Layers: If starting a fresh Cryptomatte, sets how many Cryptomatte layers are to be created. If starting from scratch, fill in Layer Selection manually.
106 | * Setup Layers: If on, starts a fresh Cryptomatte. Otherwise, modifies one from the input.
107 |
108 | ### Menu options
109 |
110 | * Cryptomatte: Creates a Cryptomatte gizmo
111 | * Decryptomatte All: Replaces all Cryptomatte gizmos with other nodes which are functionally equivalent. This is useful for sending nuke scripts to other users who do not have the Cryptomatte plugins installed.
112 | * Decryptomatte Selected: Same as "decryptomatte all", except only applies to selected nodes.
113 | * Encryptomatte: Creates an Encryptomatte gizmo
114 |
115 | ### Troubleshooting
116 |
117 | A couple of really simple things to watch out for:
118 |
119 | * Make sure you are viewing the same Cryptomatte gizmo you're keying with. (this is a very easy mistake to make).
120 | * To use the eyedropper, use the control key. Do not use alt-control, which eyedroppers values from upstream of the node. Many users are in the habit of using alt-control eye droppering.
121 |
122 | ### Troubleshooting button
123 |
124 | The advanced tab of the gizmo has a "Troubleshoot" button that will test for common installation and setup problems.
125 |
126 | ### Common issues
127 |
128 | #### Keyed mattes have incorrect pixelated edges.
129 |
130 | Make sure there are no "Reformat" or "LensDistortion" or similar nodes applied to your Cryptomattes before trying to key them. Cryptomatte relies on exact values in channels, and operations that mix values with neighboring values will damage this information, resulting in only being able to extract mattes on pixels containing only one object. These operations should be applied to the extracted mattes instead.
131 |
132 | Likewise, using proxy mode gives bad results for similar reasons.
133 |
134 | #### Things key properly, but not as their names, instead they key as numbers like `<0.1234>`
135 |
136 | The object keyed is not in the manifest provided with this EXR file, or no manifest is provided. This is a problem on the 3D side. However, objects keyed this way will be stable and will work.
137 |
138 | #### I can't tab-create the Cryptomatte gizmo.
139 |
140 | The scripts are not installed correctly. See installation instructions.
141 |
142 | #### I don't get a keyable surface when I connect my gizmo to a read node.
143 |
144 | Try running, "Force Update". If an error dialogue box pops up, the scripts are not installed correctly. See installation instructions.
145 |
146 | Also, test if it works on one of the sample images.
147 |
148 | #### Objects under the Arnold watermark aren't keyable.
149 |
150 | They sure aren't!
151 |
152 | #### I can't key the background (black pixels).
153 |
154 | You can key the background by manually entering the value, `<0.0>` into the matte list of the gizmo.
155 |
156 | ### Testing (developers)
157 |
158 | Nuke Cryptomatte has a suite of unit and integration tests. These cover hashing, CSV resolution, operations of the Cryptomatte and Encryptomatte gizmos, and Decryptomatte. Use of these is strongly encouraged if working with the Cryptomatte code.
159 |
160 | ```
161 | # To run tests in an ad-hoc style in a Nuke session, in the script editor:
162 | import cryptomatte_utilities as cu
163 | cu.tests.run_nuke_tests()
164 | ```
165 |
166 | Tests require the provided `sample_images` directory. If it is not located in the default location relative to the Python files, its location may be specified using an env variable, `$CRYPTOMATTE_TESTING_SAMPLES`. This can also be done ad-hoc in Nuke prior to running tests:
167 |
168 | ```
169 | import os
170 | os.environ["CRYPTOMATTE_TESTING_SAMPLES"] = "" # < specify sample_images dir here
171 | ```
172 |
--------------------------------------------------------------------------------
/docs/nukeScreenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/docs/nukeScreenshot.jpg
--------------------------------------------------------------------------------
/fusion/Config/cryptomatte_shortcuts.fu:
--------------------------------------------------------------------------------
1 | --[[
2 | Version : 1.4.0
3 | Requires : Fusion 9.0.2 - 17.1.1+
4 | Requires : Resolve 15.1 - 17.1.1+
5 | Optional : cjson
6 | Created by : Cédric Duriau [duriau.cedric@live.be]
7 | Kristof Indeherberge [xmnr0x23@gmail.com]
8 | Andrew Hazelden [andrew@andrewhazelden.com]
9 | --]]
10 |
11 | {
12 | Action {
13 | ID = "CryptomatteAdd",
14 | Category = "Cryptomatte",
15 | Name = "Cryptomatte Add",
16 | Targets = {
17 | Composition = {
18 | Execute = _Lua [=[
19 | fuse = obj:Comp().ActiveTool
20 | if fuse then
21 | if fuse:GetID() == 'Fuse.Cryptomatte' then
22 | fuse.Add = 1
23 | end
24 | end
25 | ]=]
26 | }
27 | }
28 | },
29 | Action {
30 | ID = "CryptomatteRemove",
31 | Category = "Cryptomatte",
32 | Name = "Cryptomatte Remove",
33 | Targets = {
34 | Composition = {
35 | Execute = _Lua [=[
36 | fuse = obj:Comp().ActiveTool
37 | if fuse then
38 | if fuse:GetID() == 'Fuse.Cryptomatte' then
39 | fuse.Remove = 1
40 | end
41 | end
42 | ]=]
43 | }
44 | }
45 | },
46 | Action {
47 | ID = "CryptomatteToggle",
48 | Category = "Cryptomatte",
49 | Name = "Cryptomatte Toggle",
50 | Targets = {
51 | Composition = {
52 | Execute = _Lua [=[
53 | fuse = obj:Comp().ActiveTool
54 | if fuse then
55 | if fuse:GetID() == 'Fuse.Cryptomatte' then
56 | fuse.Toggle = 1
57 | end
58 | end
59 | ]=]
60 | }
61 | }
62 | },
63 | Action {
64 | ID = "CryptomatteViewMode",
65 | Category = "Cryptomatte",
66 | Name = "Cryptomatte View Mode",
67 | Targets = {
68 | Composition = {
69 | Execute = _Lua [=[
70 | fuse = obj:Comp().ActiveTool
71 | if fuse then
72 | if fuse:GetID() == 'Fuse.Cryptomatte' then
73 | view_mode = fuse.ViewMode[fu.TIME_UNDEFINED]
74 | if view_mode ~= 3 then
75 | view_mode = view_mode + 1
76 | else
77 | view_mode = 0
78 | end
79 | fuse.ViewMode = view_mode
80 | end
81 | end
82 | ]=]
83 | }
84 | }
85 | },
86 | Action {
87 | ID = "CryptomatteClear",
88 | Category = "Cryptomatte",
89 | Name = "Cryptomatte Clear",
90 | Targets = {
91 | Composition = {
92 | Execute = _Lua [=[
93 | fuse = obj:Comp().ActiveTool
94 | if fuse then
95 | if fuse:GetID() == 'Fuse.Cryptomatte' then
96 | fuse.Clear = 1
97 | end
98 | end
99 | ]=]
100 | }
101 | }
102 | },
103 | Action {
104 | ID = "CryptomatteLayerMinus",
105 | Category = "Cryptomatte",
106 | Name = "Cryptomatte Layer Minus",
107 | Targets = {
108 | Composition = {
109 | Execute = _Lua [=[
110 | fuse = obj:Comp().ActiveTool
111 | if fuse then
112 | if fuse:GetID() == 'Fuse.Cryptomatte' then
113 | layer_index = fuse.LayerIndex[fu.TIME_UNDEFINED]
114 | if layer_index ~= 1 then
115 | fuse.LayerIndex = layer_index - 1
116 | end
117 | end
118 | end
119 | ]=]
120 | }
121 | }
122 | },
123 | Action {
124 | ID = "CryptomatteLayerPlus",
125 | Category = "Cryptomatte",
126 | Name = "Cryptomatte Layer Plus",
127 | Targets = {
128 | Composition = {
129 | Execute = _Lua [=[
130 | fuse = obj:Comp().ActiveTool
131 | if fuse then
132 | if fuse:GetID() == 'Fuse.Cryptomatte' then
133 | layer_index = fuse.LayerIndex[fu.TIME_UNDEFINED]
134 | if layer_index ~= fuse.LayerIndex:GetAttrs("INPN_MaxScale") then
135 | fuse.LayerIndex = layer_index + 1
136 | end
137 | end
138 | end
139 | ]=]
140 | }
141 | }
142 | },
143 | Hotkeys {
144 | Target = "GLView",
145 | SHIFT_A = "CryptomatteAdd{}",
146 | SHIFT_C = "CryptomatteClear{}",
147 | SHIFT_KEYPAD_MINUS = "CryptomatteLayerMinus{}",
148 | SHIFT_MINUS = "CryptomatteLayerMinus{}",
149 | SHIFT_KEYPAD_PLUS = "CryptomatteLayerPlus{}",
150 | SHIFT_PLUS = "CryptomatteLayerPlus{}",
151 | SHIFT_R = "CryptomatteRemove{}",
152 | SHIFT_T = "CryptomatteToggle{}",
153 | SHIFT_V = "CryptomatteViewMode{}",
154 | SHIFT_CONTROL_K = "CryptomatteViewMode{}",
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/fusion/Fuses/Matte/cryptomatte.fuse:
--------------------------------------------------------------------------------
1 | --[[
2 | Version : 1.4.0
3 | Requires : Fusion 9.0.2 - 17.1.1+
4 | Requires : Resolve 15.1 - 17.1.1+
5 | Optional : cjson
6 | Created by : Cédric Duriau [duriau.cedric@live.be]
7 | Kristof Indeherberge [xmnr0x23@gmail.com]
8 | Andrew Hazelden [andrew@andrewhazelden.com]
9 | --]]
10 |
11 | -- ============================================================================
12 | -- modules
13 | -- ============================================================================
14 | local cryptoutils = self and require("cryptomatte_utilities") or nil
15 |
16 | -- ============================================================================
17 | -- constants
18 | -- ============================================================================
19 | FUSE_NAME = "Cryptomatte"
20 | FUSE_CATEGORY = "Matte"
21 | FUSE_COMPANY = "Psyop"
22 | FUSE_HELP = "https://www.steakunderwater.com/wesuckless/viewtopic.php?f=6&t=1027"
23 | FUSE_URL = "https://github.com/Psyop/Cryptomatte"
24 | FUSE_VERSION = 140
25 |
26 | SEPARATOR_INDEX = 0
27 | VIEW_MODE_EDGES = "Edges"
28 | VIEW_MODE_COLORS = "Colors"
29 | VIEW_MODE_BEAUTY = "Beauty"
30 | VIEW_MODE_MATTE = "Matte"
31 | VIEW_MODES = {VIEW_MODE_COLORS, VIEW_MODE_EDGES, VIEW_MODE_BEAUTY, VIEW_MODE_MATTE}
32 | SHOW_CALLBACKS = false
33 |
34 |
35 | -- ============================================================================
36 | -- utils
37 | -- ============================================================================
38 | function create_separator()
39 | --[[
40 | Creates a separator input control.
41 |
42 | :rtype: Input
43 | ]]
44 | SEPARATOR_INDEX = SEPARATOR_INDEX + 1
45 | local name = string.format("Separator%s", SEPARATOR_INDEX)
46 | return self:AddInput(name, name, {
47 | INPID_InputControl = "SeparatorControl",
48 | IC_Visible = true,
49 | INP_External = false,
50 | INP_Passive = true
51 | })
52 | end
53 |
54 |
55 | -- ============================================================================
56 | -- fuse
57 | -- ============================================================================
58 | FuRegisterClass(FUSE_NAME, CT_Tool, {
59 | REGS_Name = FUSE_NAME,
60 | REGS_Category = FUSE_CATEGORY,
61 | REGS_Company = FUSE_COMPANY,
62 | REGS_OpIconString = FUSE_NAME,
63 | REGS_OpDescription = FUSE_NAME,
64 | REGS_URL = FUSE_URL,
65 | REGS_HelpTopic = FUSE_HELP,
66 | REG_NoMotionBlurCtrls = true,
67 | REG_NoBlendCtrls = true,
68 | REG_OpNoMask = true,
69 | REG_Version = FUSE_VERSION,
70 | REG_SupportsDoD = true
71 | })
72 |
73 | function Create()
74 | --[[ Creates the user interface. ]]
75 | -- input
76 | InImage = self:AddInput("Input", "Input", {
77 | LINKID_DataType = "Image",
78 | LINK_Main = 1
79 | })
80 |
81 | -- output
82 | OutImage = self:AddOutput("Output", "Output", {
83 | LINKID_DataType = "Image",
84 | LINK_Main = 1
85 | })
86 |
87 | -- locator
88 | LocatorMatte = self:AddInput("Matte Locator", "Locator", {
89 | LINKID_DataType = "Point",
90 | INPID_InputControl = "OffsetControl",
91 | INPID_PreviewControl = "CrosshairControl",
92 | INP_External = false,
93 | INP_Passive = true
94 | })
95 |
96 | ButtonAdd = self:AddInput("Add", "Add", {
97 | LINKID_DataType = "Number",
98 | INPID_InputControl = "ButtonControl",
99 | INP_External = false,
100 | INP_DoNotifyChanged = true,
101 | ICD_Width = 1 / 3
102 | })
103 |
104 | ButtonRemove = self:AddInput("Remove", "Remove", {
105 | LINKID_DataType = "Number",
106 | INPID_InputControl = "ButtonControl",
107 | INP_External = false,
108 | INP_DoNotifyChanged = true,
109 | ICD_Width = 1 / 3
110 | })
111 |
112 | ButtonToggle = self:AddInput("Toggle", "Toggle", {
113 | LINKID_DataType = "Number",
114 | INPID_InputControl = "ButtonControl",
115 | INP_External = false,
116 | INP_DoNotifyChanged = true,
117 | ICD_Width = 1 / 3
118 | })
119 |
120 | create_separator()
121 |
122 | -- preview
123 | ComboViewMode = self:AddInput("View Mode", "ViewMode", {
124 | LINKID_DataType = "Number",
125 | INPID_InputControl = "ComboControl",
126 | INP_Default = 0.0,
127 | INP_Integer = true,
128 | { CCS_AddString = VIEW_MODES[1] },
129 | { CCS_AddString = VIEW_MODES[2] },
130 | { CCS_AddString = VIEW_MODES[3] },
131 | { CCS_AddString = VIEW_MODES[4] },
132 | INP_External = true
133 | })
134 |
135 | create_separator()
136 |
137 | -- matte list
138 | TextMatteList = self:AddInput("Matte List", "MatteList", {
139 | LINKS_Name = "Matte List",
140 | LINKID_DataType = "Text",
141 | INPID_InputControl = "TextEditControl",
142 | TEC_Lines = 1,
143 | TEC_Wrap = false,
144 | TEC_DeferSetInputs = true,
145 | INP_External = true
146 | })
147 |
148 | ButtonClear = self:AddInput("Clear", "Clear", {
149 | LINKS_Name = "Clear",
150 | LINKID_DataType = "Number",
151 | INPID_InputControl = "ButtonControl",
152 | INP_Integer = true,
153 | INP_DoNotifyChanged = true,
154 | INP_External = false
155 | })
156 |
157 | create_separator()
158 |
159 | -- layer selection
160 | SliderCryptoLayer = self:AddInput("Layer Index", "LayerIndex", {
161 | LINKID_DataType = "Number",
162 | INPID_InputControl = "SliderControl",
163 | IC_Steps = 1,
164 | INP_Integer = true,
165 | INP_MinAllowed = 1,
166 | INP_MaxAllowed = 100,
167 | INP_External = true
168 | })
169 |
170 | TextCryptoLayer = self:AddInput("Layer Name", "LayerName", {
171 | LINKID_DataType = "Text",
172 | INPID_InputControl = "TextEditControl",
173 | TEC_Lines = 1,
174 | TEC_ReadOnly = true,
175 | INP_External = false
176 | })
177 |
178 | -- advanced
179 | SeparatorCallbacks = create_separator()
180 | SeparatorCallbacks:SetAttrs({ICS_ControlPage = "Advanced"})
181 |
182 | -- name checker
183 | LocatorName = self:AddInput("Locator Name Checker", "LocatorName", {
184 | LINKID_DataType = "Point",
185 | INPID_InputControl = "OffsetControl",
186 | INPID_PreviewControl = "CrosshairControl",
187 | ICS_Name = "Name Checker Locator",
188 | ICS_ControlPage = "Advanced",
189 | PC_Visible = false,
190 | INP_External = false
191 | })
192 |
193 | ButtonShow = self:AddInput("Show", "Show", {
194 | LINKID_DataType = "Number",
195 | INPID_InputControl = "ButtonControl",
196 | INP_External = false,
197 | INP_DoNotifyChanged = true,
198 | ICD_Width = 0.5
199 | })
200 |
201 | ButtonHide = self:AddInput("Hide", "Hide", {
202 | LINKID_DataType = "Number",
203 | INPID_InputControl = "ButtonControl",
204 | INP_External = false,
205 | INP_DoNotifyChanged = true,
206 | ICD_Width = 0.5
207 | })
208 |
209 | TextMatteName = self:AddInput("Matte Name", "MatteName", {
210 | LINKS_Name = "Matte Name",
211 | LINKID_DataType = "Text",
212 | INPID_InputControl = "TextEditControl",
213 | TEC_Lines = 1,
214 | TEC_Wrap = false,
215 | TEC_ReadOnly = true,
216 | INP_External = false
217 | })
218 |
219 | separator = create_separator()
220 |
221 | -- callbacks
222 | separator:SetAttrs({IC_Visible = SHOW_CALLBACKS})
223 | CheckboxAdd = self:AddInput("Add Callback", "AddCallback", {
224 | LINKID_DataType = "Number",
225 | INPID_InputControl = "CheckboxControl",
226 | INP_Integer = true,
227 | INP_Default = 0.0,
228 | IC_Visible = SHOW_CALLBACKS,
229 | INP_External = false
230 | })
231 |
232 | CheckboxRemove = self:AddInput("Remove Callback", "RemoveCallback", {
233 | LINKID_DataType = "Number",
234 | INPID_InputControl = "CheckboxControl",
235 | INP_Integer = true,
236 | INP_Default = 0.0,
237 | IC_Visible = SHOW_CALLBACKS,
238 | INP_External = false
239 | })
240 |
241 | CheckboxToggle = self:AddInput("Toggle Callback", "ToggleCallback", {
242 | LINKID_DataType = "Number",
243 | INPID_InputControl = "CheckboxControl",
244 | INP_Integer = true,
245 | INP_Default = 0.0,
246 | IC_Visible = SHOW_CALLBACKS,
247 | INP_External = false
248 | })
249 | end
250 |
251 | function Process(req)
252 | --[[
253 | Processes all events for one render cycle.
254 |
255 | :param req: render request object
256 | :type req: Request
257 | ]]
258 | local t_start = os.clock()
259 | cryptoutils.log_info("-- process started")
260 |
261 | -- read current settings
262 | local current_layer_count = SliderCryptoLayer:GetAttr("INP_MaxAllowed")
263 | local current_layer_index = SliderCryptoLayer:GetSource(req.Time).Value
264 | local current_layer_name = TextCryptoLayer:GetSource(req.Time).Value
265 | local current_matte_names_str = TextMatteList:GetSource(req.Time).Value
266 |
267 | -- get input image
268 | local input_image = InImage:GetValue(req)
269 |
270 | -- validate input image depth
271 | module.validate_image_depth(input_image)
272 |
273 | -- read metadata
274 | cryptoutils.log_info("reading metadata ...")
275 | local metadata = cryptoutils.get_cryptomatte_metadata(input_image.Metadata)
276 | local layer_count = metadata["layer_count"]
277 |
278 | -- read/check layer data from current index
279 | local layer_index = current_layer_index
280 | local layer_id = metadata["index_to_id"][tostring(current_layer_index)]
281 | if layer_id == nil then
282 | cryptoutils.log_error(string.format("layer '%s' (index %s) not present in metadata", current_layer_name, current_layer_index))
283 | end
284 | local layer_name = metadata["id_to_name"][layer_id]
285 |
286 | -- apply GUI updates
287 | if layer_count ~= current_layer_count then
288 | SliderCryptoLayer:SetAttrs({INP_MinAllowed = 1,
289 | INP_MaxAllowed = layer_count,
290 | INP_MinScale = 1,
291 | INP_MaxScale = layer_count})
292 | end
293 |
294 | if layer_name ~= current_layer_name then
295 | cryptoutils.log_info(string.format("setting layer name: '%s'", layer_name))
296 | TextCryptoLayer:SetSource(Text(layer_name), req.Time, 0)
297 | end
298 |
299 | -- read raw manifest from file
300 | local manifest_file = metadata["layers"][layer_id]["manif_file"]
301 | local raw_manifest = metadata["layers"][layer_id]["manifest"]
302 | if manifest_file ~= nil then
303 | cryptoutils.log_info(string.format("reading manifest file: '%s'", manifest_file))
304 | raw_manifest = cryptoutils.read_manifest_file(metadata["path"], manifest_file)
305 | end
306 |
307 | -- decode manifest string to table
308 | cryptoutils.log_info("decoding manifest ...")
309 | local manifest = cryptoutils.decode_manifest(raw_manifest)
310 |
311 | -- create layer images
312 | cryptoutils.log_info("creating layer images ...")
313 | local layer_images = cryptoutils.get_layer_images(input_image, metadata["path"], layer_name, 1)
314 |
315 | -- get matte names
316 | cryptoutils.log_info("reading matte names ...")
317 | local matte_names = cryptoutils.get_matte_names(current_matte_names_str)
318 | local matte_name_str = current_matte_names_str
319 |
320 | -- apply callbacks
321 | local callback_add = CheckboxAdd:GetSource(req.Time).Value
322 | local callback_remove = CheckboxRemove:GetSource(req.Time).Value
323 | local callback_toggle = CheckboxToggle:GetSource(req.Time).Value
324 |
325 | if callback_add == 1 or callback_remove == 1 or callback_toggle == 1 then
326 | cryptoutils.log_info("processing callbacks ...")
327 | local screen_pos = LocatorMatte:GetSource(req.Time)
328 | local matte_name = module.get_screen_matte_name(input_image, layer_images, screen_pos, manifest)
329 | local update = false
330 |
331 | if callback_add == 1 then
332 | if matte_name ~= nil then
333 | if matte_names[matte_name] == nil then
334 | cryptoutils.log_info(string.format("adding matte: '%s'", matte_name))
335 | matte_names[matte_name] = true
336 | update = true
337 | end
338 | end
339 | CheckboxAdd:SetSource(Number(0), req.Time, 0)
340 | end
341 | if callback_remove == 1 then
342 | if matte_name ~= nil then
343 | if matte_names[matte_name] then
344 | cryptoutils.log_info(string.format("removing matte: '%s'", matte_name))
345 | matte_names[matte_name] = nil
346 | update = true
347 | end
348 | end
349 | CheckboxRemove:SetSource(Number(0), req.Time, 0)
350 | end
351 | if callback_toggle == 1 then
352 | if matte_name ~= nil then
353 | if matte_names[matte_name] then
354 | cryptoutils.log_info(string.format("removing matte: '%s'", matte_name))
355 | matte_names[matte_name] = nil
356 | update = true
357 | else
358 | cryptoutils.log_info(string.format("adding matte: '%s'", matte_name))
359 | matte_names[matte_name] = true
360 | update = true
361 | end
362 | end
363 | CheckboxToggle:SetSource(Number(0), req.Time, 0)
364 | end
365 |
366 | if update then
367 | name_array = {}
368 | for name, presence in pairs(matte_names) do
369 | if presence then
370 | table.insert(name_array, "\"" .. name .. "\"")
371 | end
372 | end
373 | matte_name_str = table.concat(name_array, ", ")
374 | TextMatteList:SetSource(Text(matte_name_str), req.Time, 0)
375 | end
376 | end
377 |
378 | -- set name checker
379 | local checker_locator_visible = LocatorName:GetAttr("PC_Visible")
380 | if checker_locator_visible then
381 | cryptoutils.log_info("updating name checker ...")
382 | local checker_screen_pos = LocatorName:GetSource(req.Time)
383 | local checker_matte_name = module.get_screen_matte_name(input_image, layer_images, checker_screen_pos, manifest)
384 | local current_matte_name = TextMatteName:GetSource(req.Time).Value
385 |
386 | if checker_matte_name == nil then
387 | checker_matte_name = ""
388 | else
389 | checker_matte_name = "\"" .. checker_matte_name .. "\""
390 | end
391 |
392 | if checker_matte_name ~= current_matte_name then
393 | TextMatteName:SetSource(Text(checker_matte_name), req.Time, 0)
394 | end
395 | end
396 |
397 | -- create matte image
398 | cryptoutils.log_info("creating matte image ...")
399 | local matte_image = cryptoutils.create_matte_image(input_image, layer_images, manifest, matte_names)
400 |
401 | -- get view mode
402 | local view_mode_index = ComboViewMode:GetSource(req.Time).Value
403 | local view_mode = VIEW_MODES[view_mode_index + 1]
404 | if view_mode == nil then
405 | cryptoutils.log_error(string.format("unknown view mode: '%s'", view_mode))
406 | end
407 |
408 | -- create preview image
409 | cryptoutils.log_info(string.format("creating '%s' preview image ...", view_mode))
410 | local output_image
411 |
412 | if view_mode == VIEW_MODE_MATTE then
413 | output_image = matte_image
414 | else
415 | if view_mode == VIEW_MODE_EDGES then
416 | output_image = cryptoutils.create_preview_image_edges(input_image, layer_images)
417 | elseif view_mode == VIEW_MODE_COLORS then
418 | output_image = cryptoutils.create_preview_image_colors(input_image, layer_images)
419 | elseif view_mode == VIEW_MODE_BEAUTY then
420 | output_image = input_image:CopyOf()
421 | end
422 |
423 | -- apply matte image
424 | output_image = output_image:ChannelOpOf("Add", matte_image, { R = "fg.A", G = "fg.A"})
425 | output_image = output_image:ChannelOpOf("Copy", matte_image, { A = "fg.A"})
426 | end
427 |
428 | OutImage:Set(req, output_image)
429 |
430 | local t_end = os.clock() - t_start
431 | cryptoutils.log_info(string.format("elapsed time: %.3f", t_end))
432 | cryptoutils.log_info("-- process ended")
433 | end
434 |
435 | function NotifyChanged(inp, param, time)
436 | --[[
437 | Handles all input control events.
438 |
439 | :param inp: Input that triggered a signal.
440 | :type inp: Input
441 |
442 | :param param: Parameter object holding the (new) value.
443 | :type param: Parameter
444 |
445 | :param time: Current frame number.
446 | :type time: number
447 | ]]
448 | -- trigger callbacks
449 | if param and param.Value == 1 then
450 | if inp == ButtonAdd then
451 | CheckboxAdd:SetSource(Number(1), time, 0)
452 | elseif inp == ButtonRemove then
453 | CheckboxRemove:SetSource(Number(1), time, 0)
454 | elseif inp == ButtonToggle then
455 | CheckboxToggle:SetSource(Number(1), time, 0)
456 | elseif inp == ButtonClear then
457 | TextMatteList:SetSource(Text(""), time, 0)
458 | elseif inp == ButtonShow then
459 | LocatorName:SetAttrs({PC_Visible = true})
460 | elseif inp == ButtonHide then
461 | TextMatteName:SetSource(Text(""), time, 0)
462 | LocatorName:SetAttrs({PC_Visible = false})
463 | end
464 | end
465 | end
466 |
--------------------------------------------------------------------------------
/fusion/Modules/Lua/cryptomatte_utilities.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | Version : 1.4.0
3 | Requires : Fusion 9.0.2 - 17.1.1+
4 | Requires : Resolve 15.1 - 17.1.1+
5 | Optional : cjson
6 | Created by : Cédric Duriau [duriau.cedric@live.be]
7 | Kristof Indeherberge [xmnr0x23@gmail.com]
8 | Andrew Hazelden [andrew@andrewhazelden.com]
9 | --]]
10 |
11 | -- ============================================================================
12 | -- third party modules
13 | -- ============================================================================
14 | function prefered_load(first, second)
15 | --[[
16 | Loads first module, if that fails, loads second module.
17 |
18 | :param first: Name of preferred module to load first, if loading this module
19 | fails, the second one will be loaded.
20 | :type first: string
21 |
22 | :param second: Name of second module to load if the first module could not
23 | be loaded. If this fails, the default error when loading a
24 | non-existing module will be raised.
25 | :type second: string
26 |
27 | :rtype: table
28 | -- ]]
29 | local status, module = pcall(require, first)
30 | if not status then
31 | module = require(second)
32 | end
33 | return module
34 | end
35 |
36 | -- load cjson module if present, if not, load Fusion stdlib dkjson module
37 | local json = prefered_load("cjson", "dkjson")
38 | local bit = require("bit")
39 |
40 | -- ============================================================================
41 | -- constants
42 | -- ============================================================================
43 | ENV_VAR_LOG_LEVEL = "CRYPTOMATTE_LOG_LEVEL"
44 | METADATA_PREFIX = "cryptomatte/"
45 | REGEX_METADATA = "%a+/([a-z0-9]+)/(.+)"
46 | METADATA_KEY_NAME = "name"
47 | METADATA_KEY_FILENAME = "Filename"
48 | REGEX_MATTE_LIST = "([^,]+),?%s*"
49 | REGEX_LAYER_CHANNEL = "(.+)([0-9]+)[.](.+)"
50 | CHANNEL_NAME_MAP = {r="r", red="r",
51 | g="g", green="g",
52 | b="b", blue="b",
53 | a="a", alpha="a"}
54 | BACKGROUND_MATTE_NAME = "Background (value RGBA=0000)"
55 |
56 | -- ============================================================================
57 | -- ffi C utils
58 | -- ============================================================================
59 | -- int / float representation of hash
60 | ffi.cdef [[ union int_flt { uint32_t i; float f; }; ]]
61 | local int_flt = ffi.new("union int_flt")
62 |
63 | -- ============================================================================
64 | -- fusion centric functions (EXRIO/scanline)
65 | -- ============================================================================
66 | function get_scale_factor(image)
67 | --[[
68 | Returns the scale factor to apply.
69 |
70 | Two scale factors are possible, Proxy Scale and Auto Proxy Scale.
71 | Auto proxy scale has precedence over proxy scale.
72 |
73 | :param image: Source image holding proxy scale value. (1 = off, >1 = on)
74 | :type image: Image
75 |
76 | :rtype: number
77 | ]]
78 | -- proxy
79 | local proxy_scale = image.ProxyScale
80 | local proxy_enabled
81 | if proxy_scale == 1 then
82 | proxy_enabled = false
83 | else
84 | proxy_enabled = true
85 | end
86 |
87 | -- auto proxy
88 | local prefs = self.Comp:GetPrefs()
89 | local proxy_prefs = prefs["Comp"]["Interactive"]["Proxy"]
90 | local auto_proxy_enabled = proxy_prefs["Auto"]
91 | local auto_proxy_scale = proxy_prefs["AutoScale"]
92 |
93 | -- determine scale
94 | local scale = 1
95 | if auto_proxy_enabled then
96 | scale = auto_proxy_scale
97 | elseif proxy_enabled then
98 | scale = proxy_scale
99 | end
100 | return scale
101 | end
102 |
103 | function get_layer_images(input_image, layer_name, channel_hierarchy, exr, partnum)
104 | --[[
105 | Returns the images for all indices of layer.
106 |
107 | :param input_image: Source Cryptomatte image.
108 | :type input_image: Image
109 |
110 | :param layer_name: Name of the layer to get all index images for.
111 | :type layer_name: string
112 |
113 | :param channel_hierarchy: Channel datastructure by layer and index.
114 | :type channel_hierarchy: table
115 |
116 | :param exr: EXRIO module instance loaded with the input EXR image.
117 | :type exr: EXRIO
118 |
119 | :param partnum: EXR multipart index.
120 | :type partnum: number
121 |
122 | :rtype: table[string, Image]
123 | ]]
124 | -- calculate datawindow to keep/scan
125 | local dispw = exr:DisplayWindow(partnum)
126 | local ox = dispw.left
127 | local oy = dispw.bottom
128 | local w = dispw.right - dispw.left
129 | local h = dispw.top - dispw.bottom
130 | local dataw = exr:DataWindow(partnum)
131 | local imgw = ImgRectI(dataw)
132 | imgw:Offset(-ox, -oy)
133 |
134 | -- get pixel aspect ratio
135 | local pixel_aspect_ratio = exr:PixelAspectRatio(partnum)
136 |
137 | -- get scale factor to apply
138 | local scale = get_scale_factor(input_image)
139 |
140 | -- select EXR part to load
141 | exr:Part(partnum)
142 |
143 | local images = {}
144 | for index, channels in pairs(channel_hierarchy[layer_name]) do
145 | -- create image from scratch
146 | local image = Image({IMG_Width = w,
147 | IMG_Height = h,
148 | IMG_Depth = IMDP_128bitFloat,
149 | IMG_DataWindow = imgw,
150 | IMG_YScale = 1.0 / pixel_aspect_ratio})
151 |
152 | -- write out loaded EXR part image channels to layer image
153 | exr:Channel(channels["r"], ANY_TYPE, 1, CHAN_RED)
154 | exr:Channel(channels["g"], ANY_TYPE, 1, CHAN_GREEN)
155 | exr:Channel(channels["b"], ANY_TYPE, 1, CHAN_BLUE)
156 | exr:Channel(channels["a"], ANY_TYPE, 1, CHAN_ALPHA)
157 | exr:ReadPart(partnum, {image})
158 |
159 | -- handle proxy scaling
160 | local result = image
161 | if scale ~= 1 then
162 | local resized_image = Image({IMG_Like = image,
163 | IMG_Width = input_image.Width,
164 | IMG_Height = input_image.Height})
165 | image:Resize(resized_image, {RSZ_Filter = "Nearest",
166 | RSZ_Width = input_image.Width,
167 | RSZ_Height = input_image.Height})
168 | result = resized_image
169 | end
170 | images[tonumber(index)] = result
171 | end
172 |
173 | return images
174 | end
175 |
176 | function create_preview_image_colors_init()
177 | --[[
178 | Scanline initializer function for the "colors" preview image.
179 |
180 | This function initializes pixel objects and pointers to re-use in scanline
181 | function. This avoids the creation of these objects at every X or Y pass,
182 | improving the overall performance.
183 |
184 | ! FOLLOWING PARAMTERS ARE PASSED INDIRECTLY, SEE `DoMultiProcess` USAGE !
185 |
186 | :param output_image: Preview image to write pixel information to.
187 | :type output_image: Image
188 |
189 | :param layer_0_image: Image for the layer 0.
190 | :type layer_0_image: Image
191 |
192 | :param layer_1_image: Image for the layer 1.
193 | :type layer_1_image: Image
194 | -- ]]
195 | global_p_00 = Pixel()
196 | global_p_01 = Pixel()
197 | local_p = Pixel()
198 |
199 | pixptr_00 = PixPtr(layer_0_image, global_p_00)
200 | pixptr_01 = PixPtr(layer_1_image, global_p_01)
201 | pixptr_out = PixPtr(output_image, local_p)
202 | end
203 |
204 | function create_preview_image_colors_scanline(n)
205 | --[[
206 | Scanline function that creates the "colors" preview image.
207 |
208 | This function builds the keyable surface preview image. The algorithm used
209 | to calculate the pixel information was provided by Jonah Friedman in a Nuke
210 | sample which I translated to Lua.
211 |
212 | :param n: Absolute Y coordinate to execute scanline (left to right) pass.
213 | :type n: number
214 |
215 | ! FOLLOWING PARAMTERS ARE PASSED INDIRECTLY, SEE `DoMultiProcess` USAGE !
216 |
217 | :param output_image: Preview image to write pixel information to.
218 | :type output_image: Image
219 |
220 | :param layer_0_image: Image for the layer 0.
221 | :type layer_0_image: Image
222 |
223 | :param layer_1_image: Image for the layer 1.
224 | :type layer_1_image: Image
225 | -- ]]
226 | -- calculate real scanline y position
227 | local y = n + output_image.DataWindow.bottom
228 |
229 | -- set start X position for scanline pass
230 | pixptr_00:GotoXY(output_image.DataWindow.left, y)
231 | pixptr_01:GotoXY(output_image.DataWindow.left, y)
232 | pixptr_out:GotoXY(output_image.DataWindow.left, y)
233 |
234 | for _ = output_image.DataWindow.left, output_image.DataWindow.right - 1 do
235 | -- go to correct X position
236 | pixptr_00:GetNextPixel(global_p_00)
237 | pixptr_01:GetNextPixel(global_p_01)
238 |
239 | -- get mantissa of R and B channels of both layer 0 and 1
240 | m00_rg, _ = math.frexp(math.abs(global_p_00.R))
241 | m00_ba, _ = math.frexp(math.abs(global_p_00.B))
242 | m01_rg, _ = math.frexp(math.abs(global_p_01.R))
243 | m01_ba, _ = math.frexp(math.abs(global_p_01.B))
244 |
245 | -- calculate RGB channel values for final id colored image
246 | -- red
247 | r_00_rg = (m00_rg * 1 % 0.25) * global_p_00.G
248 | r_00_ba = (m00_ba * 1 % 0.25) * global_p_00.A
249 | r_01_rg = (m01_rg * 1 % 0.25) * global_p_01.G
250 | r_01_ba = (m01_ba * 1 % 0.25) * global_p_01.A
251 |
252 | -- green
253 | g_00_rg = (m00_rg * 4 % 0.25) * global_p_00.G
254 | g_00_ba = (m00_ba * 4 % 0.25) * global_p_00.A
255 | g_01_rg = (m01_rg * 4 % 0.25) * global_p_01.G
256 | g_01_ba = (m01_ba * 4 % 0.25) * global_p_01.A
257 |
258 | -- blue
259 | b_00_rg = (m00_rg * 16 % 0.25) * global_p_00.G
260 | b_00_ba = (m00_ba * 16 % 0.25) * global_p_00.A
261 | b_01_rg = (m01_rg * 16 % 0.25) * global_p_01.G
262 | b_01_ba = (m01_ba * 16 % 0.25) * global_p_01.A
263 |
264 | -- store calculated R,G and B values
265 | local_p.R = (r_00_rg + r_00_ba + r_01_rg + r_01_ba)
266 | local_p.G = (g_00_rg + g_00_ba + g_01_rg + g_01_ba)
267 | local_p.B = (b_00_rg + b_00_ba + b_01_rg + b_01_ba)
268 |
269 | -- set output pixel pointer
270 | pixptr_out:SetNextPixel(local_p)
271 | end
272 | end
273 |
274 | function create_matte_image_init()
275 | --[[
276 | Scanline initializer function that creates the matte image.
277 |
278 | ! FOLLOWING PARAMTERS ARE PASSED INDIRECTLY, SEE `DoMultiProcess` USAGE !
279 |
280 | :param layer_image: Image of an isolated Cryptomatte layer.
281 | :type layer_image: Image
282 |
283 | :param matte_values: Matte ID float values to match.
284 | :type matte_values: table[number, boolean]
285 |
286 | :param dod: Datawindow to process pixels for.
287 | :type dod: FuRect
288 |
289 | :param output_image: Image to store mattes in.
290 | :type output_image: Image
291 | ]]
292 | input_p = Pixel()
293 | output_p = Pixel()
294 | pixptr_in = PixPtr(layer_image, input_p)
295 | pixptr_out = PixPtr(output_image, output_p)
296 | end
297 |
298 | function create_matte_image_scanline(n)
299 | --[[
300 | Scanline function that creates the matte image.
301 |
302 | :param n: Absolute Y coordinate to execute scanline (left to right) pass.
303 | :type n: number
304 |
305 | ! FOLLOWING PARAMTERS ARE PASSED INDIRECTLY, SEE `DoMultiProcess` USAGE !
306 |
307 | :param layer_image: Image of an isolated Cryptomatte layer.
308 | :type layer_image: Image
309 |
310 | :param matte_values: Known matte float ID values from manifest.
311 | :type matte_values: table[number, boolean]
312 |
313 | :param dod: Datawindow to process pixels for.
314 | :type dod: FuRect
315 |
316 | Algorithm:
317 | - matte_pixel.A += pixel.G if pixel.R in matte_float_id_values else 0
318 | - matte_pixel.A += pixel.A if pixel.B in matte_float_id_values else 0
319 |
320 | :param output_image: Image to store mattes in.
321 | :type output_image: Image
322 | ]]
323 | local y = n + dod.bottom
324 |
325 | -- set start X position for scanline pass
326 | pixptr_in:GotoXY(dod.left, y)
327 | pixptr_out:GotoXY(dod.left, y)
328 |
329 | local update
330 | for _ = dod.left, dod.right - 1 do
331 | -- go to correct X position
332 | pixptr_in:GetNextPixel(input_p)
333 | pixptr_out:GetPixel(output_p)
334 |
335 | -- reset flag
336 | update = false
337 |
338 | -- detect rank 1 match (red match = add green)
339 | if matte_values[input_p.R] then
340 | output_p.A = output_p.A + input_p.G
341 | update = true
342 | end
343 |
344 | -- detect rank 2 match (blue match = add alpha)
345 | if matte_values[input_p.B] then
346 | output_p.A = output_p.A + input_p.A
347 | update = true
348 | end
349 |
350 | if update then
351 | pixptr_out:SetNextPixel(output_p)
352 | else
353 | pixptr_out:NextPixel()
354 | end
355 | end
356 | end
357 |
358 | function get_screen_pixel(image, x, y)
359 | --[[
360 | Gets the pixel object from given image at given coordinates.
361 |
362 | :param x: Absolute x position in pixel units.
363 | :type x: number
364 |
365 | :param y: Absolute y position in pixel units.
366 | :type y: number
367 |
368 | :rtype: Pixel
369 | -- ]]
370 | local pixel = Pixel()
371 | image:GetPixel(x, y, pixel)
372 | return pixel
373 | end
374 |
375 | -- ============================================================================
376 | -- module
377 | -- ============================================================================
378 | module = {}
379 |
380 | -- private
381 | function module._format_log(level, message)
382 | --[[
383 | Returns a formatted message to log.
384 |
385 | :param level: Name of the log level.
386 | :type level: string
387 |
388 | :param message: Message to log.
389 | :type message: string
390 |
391 | :rtype: string
392 | ]]
393 | return string.format("[Cryptomatte][%s][%s] %s", self.Name, level, message)
394 | end
395 |
396 | function module._get_log_level()
397 | --[[
398 | Returns the log level.
399 |
400 | Log levels:
401 | - 0: error (default)
402 | - 1: warning
403 | - 2: info
404 |
405 | Setting the log level to a high number than specified log levels will
406 | result in applying all lower log levels.
407 |
408 | :rtype: number
409 | ]]
410 | local log_level = os.getenv(ENV_VAR_LOG_LEVEL)
411 | if log_level == nil then
412 | return 1
413 | end
414 | return tonumber(log_level)
415 | end
416 |
417 | function module._string_starts_with(str, substr)
418 | --[[
419 | Returns whether the given string starts with the given substring.
420 |
421 | :param str: Text to match with substring.
422 | :type str: string
423 |
424 | :param substr: Substring to match text with.
425 | :type substr: string
426 |
427 | :rtype: boolean
428 | ]]
429 | return string.sub(str, 1, string.len(substr)) == substr
430 | end
431 |
432 | function module._string_ends_with(str, substr)
433 | --[[
434 | Returns whether the given string ends with the given substring.
435 |
436 | :param str: Text to match with substring.
437 | :type str: string
438 |
439 | :param substr: Substring to match text with.
440 | :type substr: string
441 |
442 | :rtype: boolean
443 | ]]
444 | return string.sub(str, -string.len(substr), -1) == substr
445 | end
446 |
447 | function module._string_split(str, pattern)
448 | --[[
449 | Splits the given string to an array of strings using given pattern.
450 |
451 | :param str: String to split/convert to an array.
452 | :type str: string
453 |
454 | :param pattern: Pattern to split string with.
455 | :type pattern: string
456 |
457 | :rtype: table[string]
458 | -- ]]
459 | local parts = {}
460 | for part in string.gmatch(str, pattern) do
461 | table.insert(parts, part)
462 | end
463 | return parts
464 | end
465 |
466 | function module._get_absolute_path(path)
467 | --[[
468 | Returns the absolute representation of a relative path.
469 |
470 | :param path: Relative path.
471 | :type path: string
472 |
473 | :rtype: string
474 | ]]
475 | local abs_path = self.Comp:MapPath(path)
476 | return abs_path:gsub("([\\])", "/")
477 | end
478 |
479 | function module._solve_channel_name(name)
480 | --[[
481 | Returns the internal representation of a channel.
482 |
483 | :param name: Channel name to get internal representation of
484 | :type name: string
485 |
486 | :rtype: string
487 | ]]
488 | return CHANNEL_NAME_MAP[string.lower(name)]
489 | end
490 |
491 | function module._get_channel_hierarchy(layer_name, channels)
492 | --[[
493 | Returns the channels of all indices of a layer.
494 |
495 | :param layer_name: Name of the layer to get channels of.
496 | :type layer_name: string
497 |
498 | :param channels: All channel objects of an EXR file.
499 | :type channels: table[table]
500 |
501 | :rtype: table
502 | ]]
503 | local hierarchy = {}
504 | for _, channel in ipairs(channels) do
505 | full_channel_name = channel["Name"]
506 | if module._string_starts_with(full_channel_name, layer_name) then
507 | -- get layer name & index info from channel name
508 | local _, layer_index, channel_name = string.match(full_channel_name, REGEX_LAYER_CHANNEL)
509 |
510 | -- get internal channel name representation
511 | local internal_channel_name = nil
512 | if layer_index and channel_name then
513 | internal_channel_name = module._solve_channel_name(channel_name)
514 |
515 | -- skip error for matching layer without index (beauty layer)
516 | if layer_index and not internal_channel_name then
517 | module.log_error(string.format("failed to get internal name for channel: '%s'", full_channel_name))
518 | end
519 | end
520 |
521 | if internal_channel_name ~= nil then
522 | if hierarchy[layer_name] == nil then
523 | hierarchy[layer_name] = {}
524 | end
525 |
526 | if hierarchy[layer_name][layer_index] == nil then
527 | hierarchy[layer_name][layer_index] = {}
528 | end
529 |
530 | if hierarchy[layer_name][layer_index][internal_channel_name] == nil then
531 | hierarchy[layer_name][layer_index][internal_channel_name] = full_channel_name
532 | end
533 | end
534 | end
535 | end
536 | return hierarchy
537 | end
538 |
539 | function module._get_absolute_position(width, height, rel_x, rel_y)
540 | --[[
541 | Gets the absolute values for given relative coordinates.
542 |
543 | :param width: Reference width.
544 | :type width: number
545 |
546 | :param width: Reference height.
547 | :type width: number
548 |
549 | :param rel_x: Relative x coordinate.
550 | :type rel_x: number
551 |
552 | :param rel_y: Relative y coordinate.
553 | :type rel_y: number
554 |
555 | :rtype: number, number
556 | --]]
557 | return math.floor(width / (1 / rel_x)), math.floor(height / (1 / rel_y))
558 | end
559 |
560 | function module._is_position_in_rect(rect, x, y)
561 | --[[
562 | Validates if the given x and y coordinates are in the given rect bounds.
563 |
564 | :param rect: Integer rectangle position to validate x and y position with.
565 | :type rect: FuRectInt
566 |
567 | :param x: Y position to validate.
568 | :type x: number
569 |
570 | :param y: Y position to validate.
571 | :type y: number
572 |
573 | :rtype: bool
574 | --]]
575 | if x < rect.left or x > rect.right then
576 | return false
577 | end
578 | if y > rect.top or y < rect.bottom then
579 | return false
580 | end
581 | return true
582 | end
583 |
584 | function module._hex_to_float(hex)
585 | --[[
586 | Returns the float representation of a hexademical string.
587 |
588 | :param hex: Hexadecimal string.
589 | :type hex: string
590 |
591 | :rtype: number
592 | ]]
593 | int_flt.i = tonumber(hex, 16)
594 | --fix exponent if required
595 | local exp = bit.rshift(int_flt.i, 23)
596 | exp = bit.band(exp, 255)
597 | if exp == 0 or exp == 255 then
598 | int_flt.i = bit.bxor(int_flt.i, bit.lshift(1, 23))
599 | end
600 | return int_flt.f
601 | end
602 |
603 | -- public
604 | function module.log_error(message)
605 | --[[
606 | Logs an error message.
607 |
608 | :param message: Message to log.
609 | :type message: string
610 | ]]
611 | local log_level = module._get_log_level()
612 | if log_level >= 0 then
613 | print(module._format_log("ERROR", message))
614 | end
615 | error("ERROR")
616 | end
617 |
618 | function module.log_warning(message)
619 | --[[
620 | Logs an warning message.
621 |
622 | :param message: Message to log.
623 | :type message: string
624 | ]]
625 | local log_level = module._get_log_level()
626 | if log_level >= 1 then
627 | print(module._format_log("WARNING", message))
628 | end
629 | end
630 |
631 | function module.log_info(message)
632 | --[[
633 | Logs an information message.
634 |
635 | :param message: Message to log.
636 | :type message: string
637 | ]]
638 | local log_level = module._get_log_level()
639 | if log_level >= 2 then
640 | print(module._format_log("INFO", message))
641 | end
642 | end
643 |
644 | function module.get_cryptomatte_metadata(metadata)
645 | --[[
646 | Reads the Cryptomatte metadata of an EXR file.
647 |
648 | :param metadata: Source Cryptomatte EXR metadata.
649 | :type metadata: table
650 |
651 | :rtype: table
652 | ]]
653 | -- exr path metadata
654 | local exr_path = nil
655 | local filename = metadata[METADATA_KEY_FILENAME]
656 | if filename ~= nil then
657 | exr_path = module._get_absolute_path(filename)
658 | else
659 | module.log_error("metadata key 'Filename' empty/not set")
660 | end
661 |
662 | -- cryptomatte metadata
663 | local layer_data_by_id = {}
664 | local layer_names = {}
665 | local id_to_name = {}
666 | local name_to_id = {}
667 | local id_to_index = {}
668 | local index_to_id = {}
669 |
670 | for k, v in pairs(metadata) do
671 | if module._string_starts_with(k, METADATA_PREFIX) then
672 | -- get layer ID and cryptomatte metadata key
673 | local layer_id, partial_key = string.match(k, REGEX_METADATA)
674 |
675 | local layer_data = layer_data_by_id[layer_id]
676 | if layer_data == nil then
677 | layer_data = {}
678 | layer_data_by_id[layer_id] = layer_data
679 | end
680 |
681 | -- store cryptomatte layer metadata
682 | layer_data[partial_key] = v
683 |
684 | -- store layer name/id mapping for fast lookup
685 | if partial_key == METADATA_KEY_NAME then
686 | table.insert(layer_names, v)
687 | name_to_id[v] = layer_id
688 | id_to_name[layer_id] = v
689 | end
690 | end
691 | end
692 |
693 | -- validate layers were found
694 | if #layer_names == 0 then
695 | module.log_error("no cryptomatte metadata found")
696 | end
697 |
698 | -- store layer index/id mapping for fast lookup
699 | table.sort(layer_names)
700 | for i, layer_name in ipairs(layer_names) do
701 | local layer_id = name_to_id[layer_name]
702 | local layer_index = tostring(i)
703 | index_to_id[layer_index] = layer_id
704 | id_to_index[layer_id] = layer_index
705 | end
706 |
707 | local crypto_metadata = {}
708 | crypto_metadata["path"] = exr_path
709 | crypto_metadata["layer_count"] = #layer_names
710 | crypto_metadata["id_to_name"] = id_to_name
711 | crypto_metadata["name_to_id"] = name_to_id
712 | crypto_metadata["index_to_id"] = index_to_id
713 | crypto_metadata["id_to_index"] = id_to_index
714 | crypto_metadata["layers"] = layer_data_by_id
715 | return crypto_metadata
716 | end
717 |
718 | function module.read_manifest_file(exr_path, sidecar_file_path)
719 | --[[
720 | Reads the manifest of an EXR sidecar file.
721 |
722 | :param exr_path: Absolute path of an EXR file.
723 | :type exr_path: string
724 |
725 | :param sidecar_file_path: Path of a sidecar file relative to the EXR file.
726 | :type sidecar_file_path: string
727 |
728 | :rtype: string
729 | ]]
730 | -- build absolute sidecar file path
731 | local path = exr_path:match("(.*/)") .. sidecar_file_path
732 | local fp = io.open(path, "r")
733 | if fp == nil then
734 | module.log_error(string.format("unable to open manifest file: %s", path))
735 | return ""
736 | else
737 | local manifest_str = fp:read("*all")
738 | fp:close()
739 | return manifest_str
740 | end
741 | end
742 |
743 | function module.decode_manifest(raw_manifest)
744 | --[[
745 | Deserializes a manifest from JSON string to table.
746 |
747 | :param raw_manifest: Serialized manifest.
748 | :type raw_manifest: string
749 |
750 | :rtype: table[string, string]
751 | ]]
752 | if raw_manifest == nil or raw_manifest == "" then
753 | module.log_error("no manifest to decode")
754 | return {}
755 | end
756 | return json.decode(raw_manifest)
757 | end
758 |
759 | function module.get_matte_names(matte_str)
760 | --[[
761 | Returns the matte names from an input string.
762 |
763 | :param matte_str: Matte input string. Example: '"bunny", "flower"'
764 | :type matte_str: Matte input string.
765 |
766 | :rtype: table[string, bool]
767 | ]]
768 | -- get matte entries
769 | local name_array = module._string_split(matte_str, REGEX_MATTE_LIST)
770 |
771 | local name_set = {}
772 | for _, matte in ipairs(name_array) do
773 | -- detect double quote leading & trailing character
774 | if module._string_starts_with(matte, "\"") and module._string_ends_with(matte, "\"") then
775 | name = string.sub(matte, 2, matte:len() - 1)
776 | name_set[name] = true
777 | else
778 | module.log_warning(string.format("invalid syntax for matte: '%s'", matte))
779 | end
780 | end
781 | return name_set
782 | end
783 |
784 | function module.get_layer_images(input_image, exr_path, layer_name, partnum)
785 | --[[
786 | Returns the images for all indices of layer.
787 |
788 | :param input_image: Source Cryptomatte image.
789 | :type input_image: Image
790 |
791 | :param exr_path: Absolite path to the EXR file.
792 | :type exr_path: string
793 |
794 | :param layer_name: Name of the layer to get all index images for.
795 | :type layer_name: string
796 |
797 | :param partnum: EXR multipart index.
798 | :type partnum: number
799 |
800 | :rtype: table[string, Image]
801 | ]]
802 | -- load EXR file for current time
803 | local exr = EXRIO()
804 | exr:ReadOpen(exr_path, -1)
805 |
806 | if exr.NumParts > 0 then
807 | exr:Close()
808 | module.log_error("multipart EXR not supported")
809 | end
810 |
811 | local layer_images = {}
812 | if exr:ReadHeader() then
813 | local channels = exr:GetChannels(partnum)
814 | local channel_hierarchy = module._get_channel_hierarchy(layer_name, channels)
815 | if channel_hierarchy == {} or channel_hierarchy[layer_name] == nil then
816 | exr:Close()
817 | module.log_error(string.format("failed to read layer/index/channel information for layer: '%s'", layer_name))
818 | end
819 | layer_images = get_layer_images(input_image, layer_name, channel_hierarchy, exr, partnum)
820 | end
821 |
822 | -- close EXR file pointer
823 | exr:Close()
824 |
825 | -- log EXRIO internal errors
826 | local exrio_error = exr:GetLastError()
827 | if exrio_error ~= "" then
828 | module.log_error(exrio_error)
829 | end
830 |
831 | return layer_images
832 | end
833 |
834 | function module.create_preview_image_colors(input_image, layer_images)
835 | --[[
836 | Creates the preview image of view mode "edges".
837 |
838 | :param input_image: Source Cryptomatte image.
839 | :type input_image: Image
840 |
841 | :param layer_images: Cryptomatte layer images.
842 | :type layer_images: table[number, Image]
843 |
844 | Algorithm:
845 | - see `create_preview_image_colors_scanline` function documentation
846 |
847 | :rtype: Image
848 | ]]
849 | local output_image = input_image:CopyOf()
850 | output_image:Clear()
851 | self:DoMultiProcess(create_preview_image_colors_init,
852 | {output_image = output_image,
853 | layer_0_image = layer_images[0],
854 | layer_1_image = layer_images[1]},
855 | output_image.DataWindow.top - output_image.DataWindow.bottom,
856 | create_preview_image_colors_scanline)
857 | return output_image
858 | end
859 |
860 | function module.create_preview_image_edges(input_image, layer_images)
861 | --[[
862 | Creates the preview image of view mode "edges".
863 |
864 | :param input_image: Source Cryptomatte image.
865 | :type input_image: Image
866 |
867 | :param layer_images: Cryptomatte layer images.
868 | :type layer_images: table[number, Image]
869 |
870 | Algorithm:
871 | - output.r = input.r
872 | - output.g = input.g + (layer[0].a * 2)
873 | - output.b = input.b + (layer[0].a * 2)
874 | - output.a = input.a
875 |
876 | :rtype: Image
877 | ]]
878 | local coverage = layer_images[0]:CopyOf()
879 | coverage:Gain(1.0, 1.0, 1.0, 2.0)
880 | return input_image:ChannelOpOf("Add", coverage, {G="fg.A", B="fg.A"})
881 | end
882 |
883 | function module.create_matte_image(input_image, layer_images, manifest, matte_names)
884 | --[[
885 | Creates the monochannel matte images for selected names.
886 |
887 | :param input_image: Source Cryptomatte image
888 | :type input_image: Image
889 |
890 | :param layer_images: Cryptomatte layer images.
891 | :type layer_images: table[number, Image]
892 |
893 | :param manifest: Manifest storing matte id by name.
894 | :type manifest: table[string, string]
895 |
896 | :param matte_names: Selected mattes to isolate.
897 | :type matte_names: table[string, bool]
898 |
899 | Algorithm:
900 | - see `create_matte_image_scanline` function documentation
901 |
902 | :rtype: Image
903 | ]]
904 | local matte_values = {}
905 | for matte_name, _ in pairs(matte_names) do
906 | -- support background matte picking
907 | if matte_name == BACKGROUND_MATTE_NAME then
908 | matte_values[0.0] = true
909 | else
910 | local matte_id = manifest[matte_name]
911 | if matte_id == nil then
912 | module.log_warning(string.format("matte not present in manifest: %s", matte_name))
913 | else
914 | local matte_value = module._hex_to_float(matte_id)
915 | matte_values[matte_value] = true
916 | end
917 | end
918 | end
919 |
920 | -- build monochannel matte image
921 | local output_image = Image({IMG_Like = input_image,
922 | IMG_CopyChannels = false,
923 | {IMG_Channel = "Alpha"}})
924 | output_image:Clear()
925 | local dod = input_image.DataWindow
926 |
927 | if matte_values then
928 | for _, layer_image in pairs(layer_images) do
929 | self:DoMultiProcess(create_matte_image_init,
930 | {layer_image = layer_image,
931 | matte_values = matte_values,
932 | dod = dod,
933 | output_image = output_image},
934 | dod.top - dod.bottom,
935 | create_matte_image_scanline)
936 | end
937 | end
938 |
939 | return output_image
940 | end
941 |
942 | function module.get_screen_matte_name(input_image, layer_images, screen_pos, manifest)
943 | --[[
944 | Gets the name of a matte at given screen position.
945 |
946 | :param input_image: Source Cryptomatte image.
947 | :type input_image: Image
948 |
949 | :param layer_images: Cryptomatte layer images.
950 | :type layer_images: table[number, Image]
951 |
952 | :param screen_pos: Relative mouse position on canvas.
953 | :type screen_pos: Point
954 |
955 | :param manifest: Manifest storing matte id by name.
956 | :type manifest: table[string, string]
957 |
958 | :rtype: string or nil
959 | ]]
960 | -- get absolute screen position
961 | local x, y = module._get_absolute_position(input_image.Width, input_image.Height, screen_pos.X, screen_pos.Y)
962 |
963 | local dod = input_image.DataWindow
964 | if not module._is_position_in_rect(dod, x, y) then
965 | module.log_info(string.format("pixel (%s,%s) not present in data window (%s)", x, y, dod))
966 | return nil
967 | end
968 |
969 | -- get matte values from manifest to detect pixel matches from
970 | local matte_values = {}
971 | local matte_names_by_value = {}
972 | for matte_name, matte_id in pairs(manifest) do
973 | local matte_value = module._hex_to_float(matte_id)
974 | matte_values[matte_value] = true
975 | matte_names_by_value[matte_value] = matte_name
976 | end
977 |
978 | -- add background matte name/value
979 | matte_values[0.0] = true
980 | matte_names_by_value[0.0] = BACKGROUND_MATTE_NAME
981 |
982 | local matte_value = nil
983 | for _, layer_image in pairs(layer_images) do
984 | -- get pixel at screen coordinates for current layer image
985 | local pixel = get_screen_pixel(layer_image, x, y)
986 |
987 | if pixel.R == 0.0 and pixel.G == 0.0 and pixel.B == 0.0 and pixel.A == 0.0 then
988 | -- background is being picked
989 | matte_value = 0.0
990 | else
991 | -- detect if any RGBA channel value matches a known matte float ID
992 | for _, value in ipairs({pixel.R, pixel.G, pixel.B, pixel.A}) do
993 | if value ~= 0.0 and matte_values[value] then
994 | matte_value = value
995 | break
996 | end
997 | end
998 | end
999 |
1000 | if matte_value ~= nil then
1001 | break
1002 | end
1003 | end
1004 |
1005 | if matte_value ~= nil then
1006 | return matte_names_by_value[matte_value]
1007 | end
1008 |
1009 | return nil
1010 | end
1011 |
1012 | function module.validate_image_depth(image)
1013 | --[[
1014 | Validates the depth of provided image.
1015 |
1016 | Log a warning if the given image is not 32bit RGBA EXR.
1017 |
1018 | :param image: Image to validate.
1019 | :type image: Image
1020 | ]]
1021 | if image.Depth ~= 8 then
1022 | module.log_warning("input image is not 32bit RGBA EXR")
1023 | end
1024 | end
1025 |
1026 | return module
1027 |
--------------------------------------------------------------------------------
/fusion/Modules/Lua/test_cryptomatte_utilities.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | Version : 1.4.0
3 | Requires : Fusion 9.0.2 - 17.1.1+
4 | Requires : Resolve 15.1 - 17.1.1+
5 | Optional : cjson
6 | Created by : Cédric Duriau [duriau.cedric@live.be]
7 | Kristof Indeherberge [xmnr0x23@gmail.com]
8 | Andrew Hazelden [andrew@andrewhazelden.com]
9 | --]]
10 |
11 | local cryptoutils = require("cryptomatte_utilities")
12 | local json = require("dkjson")
13 |
14 | -- utils
15 | function collect_tests()
16 | --[[
17 | Returns function names detected as test.
18 |
19 | Functions with names starting with "test_" will be picked up.
20 |
21 | :rtype: table[string]
22 | ]]
23 | local tests = {}
24 | local substr = "cryptomatte_test_"
25 | for name, _ in pairs(_G) do
26 | if string.sub(name, 1, string.len(substr)) == substr then
27 | table.insert(tests, name)
28 | end
29 | end
30 | table.sort(tests)
31 | return tests
32 | end
33 |
34 | function run_tests()
35 | --[[
36 | Detects and runs all test functions of a module.
37 |
38 | :param module: Module to run all tests for.
39 | :type module: table[string, function]
40 | ]]
41 | -- collect all tests from module
42 | print("collectings test(s) ...")
43 | local tests = collect_tests()
44 | local ntests = #tests
45 | print(string.format("detected %s test(s) ...", ntests))
46 |
47 | print("running tests ...")
48 | local count = 0
49 | for _, name in ipairs(tests) do
50 | count = count + 1
51 |
52 | -- build progess percentage
53 | local percentage = (count / ntests) * 100
54 | local percentage_str = string.format("%.0f%%", percentage)
55 | local padding = string.rep(" ", 4 - string.len(percentage_str))
56 | percentage_str = string.format("%s%s", padding, percentage_str)
57 |
58 | -- build test report
59 | local report = string.format("[%s] %s ... ", percentage_str, name)
60 |
61 | -- add leading spaces to allign results
62 | while report:len() < 60 do
63 | report = report.." "
64 | end
65 |
66 | -- safe call test function
67 | local status, err = pcall(_G[name])
68 |
69 | -- error handling & final report update
70 | if status then
71 | report = string.format("%s [%s]", report, "OK")
72 | else
73 | report = string.format("%s [%s]\n%s", report, "FAILED", err)
74 | end
75 | print(report)
76 | end
77 | end
78 |
79 | function assert_equal(x, y)
80 | --[[
81 | Tests the equality of two variables.
82 |
83 | :rtype: boolean
84 | ]]
85 | local _x, _y = x, y
86 |
87 | -- transform values for equality
88 | if type(x) == "table" and type(y) == "table" then
89 | _x = json.encode(_x)
90 | _y = json.encode(_y)
91 | end
92 |
93 | if _x == _y then
94 | return true
95 | else
96 | error(string.format("%s\nassertion failed: %s != %s", debug.traceback(), _x, _y))
97 | end
98 | end
99 |
100 | -- mock funtions
101 | storage = {}
102 |
103 | function mock_error(message)
104 | storage["error_return"] = message
105 | end
106 |
107 | function mock_print(message)
108 | storage["print_return"] = message
109 | end
110 |
111 | function mock_log_level_unset()
112 | return nil
113 | end
114 |
115 | function mock_log_level_error()
116 | return "0"
117 | end
118 |
119 | function mock_log_level_warning()
120 | return "1"
121 | end
122 |
123 | function mock_log_level_info()
124 | return "2"
125 | end
126 |
127 | mock_self_node = {Name="NODE1", Comp=fusion}
128 |
129 | -- tests
130 | function cryptomatte_test__format_log()
131 | local old_self = _G["self"]
132 | _G["self"] = mock_self_node
133 | assert_equal(cryptoutils._format_log("LEVEL", "MESSAGE"), "[Cryptomatte][NODE1][LEVEL] MESSAGE")
134 | _G["self"] = old_self
135 | end
136 |
137 | function cryptomatte_test__get_log_level()
138 | -- store original function pre mock
139 | local old_get_env = _G["os"]["getenv"]
140 |
141 | -- mock log level not set in environment
142 | _G["os"]["getenv"] = mock_log_level_unset
143 | local r1 = cryptoutils._get_log_level()
144 | _G["os"]["getenv"] = old_get_env
145 | assert_equal(r1, 1)
146 |
147 | -- mock log level info set in environment (string -> number cast)
148 | _G["os"]["getenv"] = mock_log_level_info
149 | local r2 = cryptoutils._get_log_level()
150 | _G["os"]["getenv"] = old_get_env
151 | assert_equal(r2, 2)
152 | end
153 |
154 | function cryptomatte_test__string_starts_with()
155 | assert_equal(cryptoutils._string_starts_with("foo_bar", "foo_"), true)
156 | assert_equal(cryptoutils._string_starts_with("foo_bar", "bar"), false)
157 | end
158 |
159 | function cryptomatte_test__string_ends_with()
160 | assert_equal(cryptoutils._string_ends_with("foo_bar", "_bar"), true)
161 | assert_equal(cryptoutils._string_ends_with("foo_bar", "foo"), false)
162 | end
163 |
164 | function cryptomatte_test__string_split()
165 | local result = cryptoutils._string_split("foo, bar,bunny", "([^,]+),?%s*")
166 | assert_equal(#result, 3)
167 | local expected = {"foo", "bar", "bunny"}
168 | for i, v in ipairs(result) do
169 | assert_equal(v, expected[i])
170 | end
171 | end
172 |
173 | function cryptomatte_test__get_absolute_path()
174 | -- store original pre mock
175 | local old_self = _G["self"]
176 |
177 | -- mock
178 | _G["self"] = mock_self_node
179 |
180 | -- linux absolute path with forward path sep
181 | local r1 = cryptoutils._get_absolute_path("/tmp/test.exr")
182 |
183 | -- windows absolute path with double backward path sep
184 | local r2 = cryptoutils._get_absolute_path("C:\\Temp\\test.exr")
185 |
186 | -- path relative to path map system keyword
187 | local r3 = cryptoutils._get_absolute_path("Temp:/test.exr")
188 |
189 | -- reset mock
190 | _G["self"] = old_self
191 |
192 | assert_equal(r1, "/tmp/test.exr")
193 | assert_equal(r2, "C:/Temp/test.exr")
194 | local pathsep = package.config:sub(1,1)
195 | if pathsep == "/" then
196 | assert_equal(r3, "/tmp/test.exr")
197 | else
198 | assert_equal(r3, "C:\\Temp\\test.exr")
199 | end
200 | end
201 |
202 | function cryptomatte_test__solve_channel_name()
203 | -- r
204 | assert_equal(cryptoutils._solve_channel_name("r"), "r")
205 | assert_equal(cryptoutils._solve_channel_name("R"), "r")
206 | assert_equal(cryptoutils._solve_channel_name("red"), "r")
207 | assert_equal(cryptoutils._solve_channel_name("RED"), "r")
208 |
209 | -- g
210 | assert_equal(cryptoutils._solve_channel_name("g"), "g")
211 | assert_equal(cryptoutils._solve_channel_name("G"), "g")
212 | assert_equal(cryptoutils._solve_channel_name("green"), "g")
213 | assert_equal(cryptoutils._solve_channel_name("GREEN"), "g")
214 |
215 | -- b
216 | assert_equal(cryptoutils._solve_channel_name("b"), "b")
217 | assert_equal(cryptoutils._solve_channel_name("B"), "b")
218 | assert_equal(cryptoutils._solve_channel_name("blue"), "b")
219 | assert_equal(cryptoutils._solve_channel_name("BLUE"), "b")
220 |
221 | -- a
222 | assert_equal(cryptoutils._solve_channel_name("a"), "a")
223 | assert_equal(cryptoutils._solve_channel_name("A"), "a")
224 | assert_equal(cryptoutils._solve_channel_name("alpha"), "a")
225 | assert_equal(cryptoutils._solve_channel_name("ALPHA"), "a")
226 | end
227 |
228 | function cryptomatte_test__get_channel_hierarchy()
229 | local channels = {
230 | {Name="Layer.R"}, -- will be skipped
231 | {Name="Layer.G"}, -- will be skipped
232 | {Name="Layer.B"}, -- will be skipped
233 | {Name="Layer.A"}, -- will be skipped
234 | {Name="Layer00.R"},
235 | {Name="Layer00.G"},
236 | {Name="Layer00.B"},
237 | {Name="Layer00.A"},
238 | {Name="Layer01.R"},
239 | {Name="Layer01.G"},
240 | {Name="Layer01.B"},
241 | {Name="Layer01.A"}
242 | }
243 | local result = cryptoutils._get_channel_hierarchy("Layer", channels)
244 | local expected = {}
245 | expected["Layer"] = {}
246 | expected["Layer"]["0"] = {r="Layer00.R",g="Layer00.G",b="Layer00.B",a="Layer00.A"}
247 | expected["Layer"]["1"] = {r="Layer01.R",g="Layer01.G",b="Layer01.B",a="Layer01.A"}
248 | assert_equal(result, expected)
249 | end
250 |
251 | function cryptomatte_test__get_absolute_position()
252 | local x, y = cryptoutils._get_absolute_position(10, 10, 0.5, 0.5)
253 | assert_equal(x, 5)
254 | assert_equal(y, 5)
255 | end
256 |
257 | function cryptomatte_test__is_position_in_rect()
258 | -- NOTE: fusion rectangles follow mathematical convention, (origin=left,bottom)
259 | local rect = {left=0, top=10, right=10, bottom=0}
260 | assert_equal(cryptoutils._is_position_in_rect(rect, 5, 5), true)
261 | assert_equal(cryptoutils._is_position_in_rect(rect, 12, 5), false)
262 | assert_equal(cryptoutils._is_position_in_rect(rect, 5, 12), false)
263 | end
264 |
265 | function cryptomatte_test__hex_to_float()
266 | assert_equal(cryptoutils._hex_to_float("3f800000"), 1.0)
267 | assert_equal(cryptoutils._hex_to_float("bf800000"), -1.0)
268 | end
269 |
270 | function cryptomatte_test_log_error()
271 | -- store original pre mock
272 | local old_get_env = _G["os"]["getenv"]
273 | local old_self = _G["self"]
274 | local old_print = _G["print"]
275 | local old_error = _G["error"]
276 |
277 | -- mock
278 | _G["os"]['getenv'] = mock_log_level_error
279 | _G["self"] = mock_self_node
280 | _G["print"] = mock_print
281 | _G["error"] = mock_error
282 |
283 | cryptoutils.log_error("HELP")
284 |
285 | -- reset mock
286 | _G["os"]["getenv"] = old_get_env
287 | _G["self"] = old_self
288 | _G["print"] = old_print
289 | _G["error"] = old_error
290 |
291 | assert_equal(storage["print_return"], "[Cryptomatte][NODE1][ERROR] HELP")
292 | assert_equal(storage["error_return"], "ERROR")
293 | end
294 |
295 | function cryptomatte_test_log_warning()
296 | -- store original pre mock
297 | local old_get_env = _G["os"]["getenv"]
298 | local old_self = _G["self"]
299 | local old_print = _G["print"]
300 |
301 | -- mock with matching log level
302 | _G["os"]['getenv'] = mock_log_level_warning
303 | _G["self"] = mock_self_node
304 | _G["print"] = mock_print
305 |
306 | cryptoutils.log_warning("HELP")
307 | local pr1 = storage["print_return"]
308 | storage["print_return"] = nil -- clear print result for next run
309 |
310 | -- mock with non matching log level
311 | _G["os"]['getenv'] = mock_log_level_error
312 |
313 | cryptoutils.log_warning("HELP")
314 | local pr2 = storage["print_return"]
315 |
316 | -- reset mock
317 | _G["os"]["getenv"] = old_get_env
318 | _G["self"] = old_self
319 | _G["print"] = old_print
320 |
321 | assert_equal(pr1, "[Cryptomatte][NODE1][WARNING] HELP")
322 | assert_equal(pr2, nil) -- never got called
323 | end
324 |
325 | function cryptomatte_test_log_info()
326 | -- store original pre mock
327 | local old_get_env = _G["os"]["getenv"]
328 | local old_self = _G["self"]
329 | local old_print = _G["print"]
330 |
331 | -- mock
332 | _G["os"]['getenv'] = mock_log_level_info
333 | _G["self"] = mock_self_node
334 | _G["print"] = mock_print
335 |
336 | cryptoutils.log_info("HELP")
337 | local pr1 = storage["print_return"]
338 | storage["print_return"] = nil -- clear print result for next run
339 |
340 | -- mock with non matching log level
341 | _G["os"]['getenv'] = mock_log_level_unset
342 |
343 | cryptoutils.log_info("HELP")
344 | local pr2 = storage["print_return"]
345 |
346 | -- reset mock
347 | _G["os"]["getenv"] = old_get_env
348 | _G["self"] = old_self
349 | _G["print"] = old_print
350 |
351 | assert_equal(pr1, "[Cryptomatte][NODE1][INFO] HELP")
352 | assert_equal(pr2, nil) -- never got called
353 | end
354 |
355 | function cryptomatte_test_get_cryptomatte_metadata()
356 | local metadata = {}
357 | metadata["cryptomatte/123456/conversion"] = "uint32_to_float32"
358 | metadata["cryptomatte/123456/hash"] = "MurmurHash3_32"
359 | metadata["cryptomatte/123456/manifest"] = "{\"bunny\": \"3f800000\"}"
360 | metadata["cryptomatte/123456/name"] = "Layer"
361 | metadata["Filename"] = "/tmp/foo"
362 |
363 | -- store original pre mock
364 | local old_self = _G["self"]
365 |
366 | -- mock
367 | _G["self"] = mock_self_node
368 |
369 | local result = cryptoutils.get_cryptomatte_metadata(metadata)
370 |
371 | -- reset mock
372 | _G["self"] = old_self
373 |
374 | local expected = {}
375 | expected["path"] = "/tmp/foo"
376 | expected["layer_count"] = 1
377 | expected["id_to_name"] = {}
378 | expected["id_to_name"]["123456"]="Layer"
379 | expected["name_to_id"] = {}
380 | expected["name_to_id"]["Layer"] = "123456"
381 | expected["index_to_id"] = {}
382 | expected["index_to_id"]["1"] = "123456"
383 | expected["id_to_index"] = {}
384 | expected["id_to_index"]["123456"] = "1"
385 | expected["layers"] = {}
386 | expected["layers"]["123456"] = {}
387 | expected["layers"]["123456"]["conversion"] = "uint32_to_float32"
388 | expected["layers"]["123456"]["hash"] = "MurmurHash3_32"
389 | expected["layers"]["123456"]["manifest"] = "{\"bunny\": \"3f800000\"}"
390 | expected["layers"]["123456"]["name"] = "Layer"
391 | assert_equal(result, expected)
392 | end
393 |
394 | function cryptomatte_test_read_manifest_file()
395 | -- valid manifest file
396 | local tmp_file = os.tmpname()
397 | local fp = io.open(tmp_file, "w")
398 | fp:write("{\"bunny\": \"3f800000\"}")
399 | fp:close()
400 |
401 | local dir, file = string.match(tmp_file, "(.-)([^\\/]-%.?[^%.\\/]*)$")
402 | local result = cryptoutils.read_manifest_file(dir, file)
403 | os.remove(tmp_file)
404 | assert_equal(result, "{\"bunny\": \"3f800000\"}")
405 |
406 | -- invalid manifest file, file does not exist
407 | -- store original pre mock
408 | local old_print = _G["print"]
409 | local old_self = _G["self"]
410 | local old_error = _G["error"]
411 |
412 | -- mock
413 | _G["print"] = mock_print
414 | _G["self"] = mock_self_node
415 | _G["error"] = mock_error
416 |
417 | local result = cryptoutils.read_manifest_file(dir, file)
418 |
419 | -- reset mock
420 | _G["print"] = old_print
421 | _G["self"] = old_self
422 | _G["error"] = old_error
423 |
424 | assert_equal(result, "")
425 | end
426 |
427 | function cryptomatte_test_decode_manifest()
428 | local result = cryptoutils.decode_manifest("{\"bunny\": \"3f800000\"}")
429 | assert_equal(result, {bunny="3f800000"})
430 | end
431 |
432 | function cryptomatte_test_get_matte_names()
433 | -- valid single name string
434 | assert_equal(cryptoutils.get_matte_names("\"bunny\""), {bunny=true})
435 |
436 | -- valid multiple names string
437 | assert_equal(cryptoutils.get_matte_names("\"bunny\", \"flower\""), {bunny=true, flower=true})
438 |
439 | -- valid name string with numbers
440 | assert_equal(cryptoutils.get_matte_names("\"bunny123\""), {bunny123=true})
441 |
442 | -- valid name string with escaped quotes (single & double)
443 | local result = cryptoutils.get_matte_names("\"bunny'\"\"")
444 | local expected = {}
445 | expected["bunny'\""] = true
446 | assert_equal(result, expected)
447 |
448 | -- valid name string with spaces
449 | result = cryptoutils.get_matte_names("\"b u n n y\"")
450 | expected = {}
451 | expected["b u n n y"] = true
452 | assert_equal(result, expected)
453 |
454 | -- valid name string with special characters
455 | result = cryptoutils.get_matte_names("\"bunny?!\"")
456 | expected = {}
457 | expected["bunny?!"] = true
458 | assert_equal(result, expected)
459 |
460 | -- valid name string with latin encoding characters
461 | result = cryptoutils.get_matte_names("\"itsabunnyé\"")
462 | expected = {}
463 | expected["itsabunnyé"] = true
464 | assert_equal(result, expected)
465 |
466 | -- valid name string in Russian cyrillic
467 | result = cryptoutils.get_matte_names("\"кролик\"")
468 | expected = {}
469 | expected["кролик"] = true
470 | assert_equal(result, expected)
471 |
472 | -- invalid name strings
473 | -- store original pre mock
474 | local old_self = _G["self"]
475 | local old_print = _G["print"]
476 |
477 | -- mock
478 | _G["self"] = mock_self_node
479 | _G["print"] = mock_print
480 |
481 | local no_quotes = cryptoutils.get_matte_names("bunny")
482 | local comma = cryptoutils.get_matte_names("bu,nny")
483 |
484 | -- reset mock
485 | _G["self"] = old_self
486 | _G["print"] = old_print
487 |
488 | assert_equal(no_quotes, {})
489 | assert_equal(comma, {})
490 | end
491 |
492 | run_tests()
493 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, 2015, 2016 Psyop Media Company, LLC
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the name of the nor the
12 | names of its contributors may be used to endorse or promote products
13 | derived from this software without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
26 |
--------------------------------------------------------------------------------
/nuke/Cryptomatte.gizmo:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2014, 2015, 2016, 2017 Psyop Media Company, LLC
3 | # See license.txt
4 | #
5 |
6 | version 7.0 v1
7 | #! C:/Temp/psyop_cache/apps/nuke/win64/10.0v6/nuke-10.0.6.dll -nx
8 | Gizmo {
9 | addUserKnob {20 cryptomatte l "Psyop Cryptomatte"}
10 |
11 | addUserKnob {36 pickerAdd l "Picker Add" t "Key objects to add to the Matte List here. " +STARTLINE +DO_NOT_WRITE}
12 | pickerAdd {0 0 0 0 0 0 0 0}
13 | addUserKnob {26 pickerAddLabel l "Picker Add" -STARTLINE T " "}
14 |
15 | addUserKnob {36 pickerRemove l "Picker Remove" t "Key objects to remove from the Matte List here. " +STARTLINE +DO_NOT_WRITE}
16 | pickerRemove {0 0 0 0 0 0 0 0}
17 | addUserKnob {26 pickerRemoveLabel l "Picker Remove" -STARTLINE T " "}
18 |
19 | addUserKnob {26 ""}
20 |
21 | addUserKnob {6 previewEnabled l "Preview" +STARTLINE}
22 | previewEnabled true
23 | addUserKnob {4 previewMode l "" t "Choose how Cryptomatte will visualize keyable regions." -STARTLINE M {Colors Edges None ""}}
24 |
25 | addUserKnob {6 matteOnly l "Matte Only" t "Extracted matte is copied to RGB channels as well. This disables keying. " +STARTLINE}
26 | addUserKnob {6 singleSelection l "Single Selection" t "Picker only selects matte at a time, rather than selecting a list. " -STARTLINE}
27 | addUserKnob {6 RemoveChannels l "Remove Channels" t "Removes all non-RGBA channels for the output. This will leave the downstream cleaner. " -STARTLINE}
28 |
29 | addUserKnob {26 ""}
30 |
31 | addUserKnob {41 matteOutput l "Matte Output" t "Set the channel(s) the matte will write to in \"Matte Only\" mode. For example, you can use this to store the matte in a custom channel called \"Matte\" and use it for color-correction downstream." T ShuffleCopy_embedMask.out}
32 | addUserKnob {6 unpremultiply l Unpremultiply -STARTLINE}
33 |
34 | addUserKnob {1 matteList l "Matte List" t "The list of names the mattes are built from. Color picking values with the color fields above works by populating this field. "}
35 | addUserKnob {22 clear l Clear t "Clears the selection in this Gizmo" T "try: \n import cryptomatte_utilities as cu\n cu.clear_cryptomatte_gizmo(nuke.thisNode())\nexcept Exception as err:\n import traceback\n nuke.message('''Unable to run Cryptomatte Gizmo update script. This script is necessary for the Cryptomatte system to work properly. Please check with Pipeline that the Cryptomatte python plugin is available on this project. \n\nError Traceback (send this to Pipeline): \n\n%s''' % traceback.format_exc())" +STARTLINE}
36 | addUserKnob {22 forceUpdate l "Force Update" t "Updates the Gizmo based on which channels are available in the input. \n\nThis happens automatically when input changes, when loading the nuke script, or when a new gizmo is created. This is how it deals with differently named channels in the different Cryptomatte layers, and different depths that it's possible to render at. " -STARTLINE T "try: \n import cryptomatte_utilities as cu\nexcept Exception as err:\n import traceback\n nuke.message('''Unable to run Cryptomatte Gizmo update script. This script is necessary for the Cryptomatte system to work properly. \n\nError Traceback: \n\n%s''' % traceback.format_exc())"}
37 | addUserKnob {6 stopAutoUpdate l "Stop Auto Update" t "Stops the automatic update of this copy of the Gizmo." -STARTLINE}
38 | addUserKnob {6 useWildcards l "Use Wildcards" t "Expands wildcard entries in the Matte List knob." -STARTLINE}
39 | useWildcards false
40 |
41 | addUserKnob {26 ""}
42 | addUserKnob {4 cryptoLayerChoice l "Layer Selection" t "Choose which Cryptomatte layer to key." M {" " ""} +DO_NOT_WRITE}
43 | addUserKnob {1 cryptoLayer l INVISIBLE t "Internal storage of selection between multiple cryptomattes." -STARTLINE +INVISIBLE}
44 | addUserKnob {1 metadataCache l INVISIBLE t "Internal storage of selection between multiple cryptomatte metadata keys." -STARTLINE +INVISIBLE +DO_NOT_WRITE}
45 | addUserKnob {6 cryptoLayerLock l "Lock Layer Selection" t "Stops the automatic update of the layer selection." -STARTLINE}
46 | addUserKnob {41 expression l "Keyer Expression" t "The built expression. This knob is set automatically and is only left exposed as information for the user. " T Expression_key.expr0}
47 |
48 | addUserKnob {20 Advanced}
49 |
50 | addUserKnob {36 ColorKey l "" t "Key an object here to check its name. It will not effect your mattes. " -STARTLINE +HIDDEN}
51 | ColorKey {0 0 0 0 0 0 0 0}
52 | addUserKnob {6 ColorKey_panelDropped l "panel dropped state" -STARTLINE +HIDDEN}
53 | addUserKnob {26 ColorKeyLabel l "Name Checker" -STARTLINE T " " +HIDDEN}
54 | addUserKnob {1 keyedName l "Keyed Name" t "This field is for information only." +HIDDEN}
55 | addUserKnob {26 "" +HIDDEN}
56 |
57 | addUserKnob {26 cryptomatteVersion l "Cryptomatte Version" T 1.4.0 +DO_NOT_WRITE}
58 | addUserKnob {22 troubleshoot l "Troubleshoot" +STARTLINE
59 | t "'Force Update All' will run 'Force Update' on all Cryptomatte gizmos in the Nuke script. 'Force Update' orders the gizmos to re-configure themselves based on available metadata, Cryptomatte depth, and the matte list. This updates all aspects of thier operation, from the preview modes to the extraction expression. Usually these updates occur automatically on certain actions, such as 'keying' the image, changing layer selection, or reconnecting images. However if changes occur upstream of the gizmos that require manually invoked updates, 'Force Update' and 'Force Update All' may be used. "
60 | T "
61 | try:
62 | import cryptomatte_utilities as cu
63 | cu.troubleshoot_gizmo(nuke.thisNode())
64 | except ImportError as err:
65 | nuke.message('''Could not import cryptomatte_utilities.py, the python files are not available. \n\nError Traceback: \n\n%s''' % traceback.format_exc())
66 | except Exception as err:
67 | import traceback
68 | nuke.message('''Something went wrong. If you would like to report this, please the text in this window: \n\nError Traceback: \n\n%s''' % traceback.format_exc())
69 | "}
70 | addUserKnob {26 ""}
71 |
72 | addUserKnob {22 decryptomatte l "Decryptomatte (Replace with Expression)" +STARTLINE
73 | t "Replaces this gizmo with an expression node that does the extraction. This will replicate the matte extraction, but not the preview modes. "
74 | T "
75 | try:
76 | import cryptomatte_utilities as cu
77 | cu.decryptomatte_button(nuke.thisNode())
78 | except Exception as err:
79 | import traceback
80 | nuke.message('''Unable to run a Cryptomatte script. This script is necessary for the Cryptomatte system to work properly. \n\nError Traceback: \n\n%s''' % traceback.format_exc())
81 | "}
82 |
83 | addUserKnob {22 unloadManifest l "Unload Manifest (Extract all Mattes)" +STARTLINE
84 | t "Unload Manifest will create a separate gizmo for every named matte in the Cryptomatte manifest. This can potentially be thousands of nodes, though if the number is high a warning will be displayed before creating them. "
85 | T "
86 | try:
87 | import cryptomatte_utilities as cu
88 | cu.unload_manifest(nuke.thisNode())
89 | except Exception as err:
90 | import traceback
91 | nuke.message('''Unable to run a Cryptomatte script. This script is necessary for the Cryptomatte system to work properly. \n\nError Traceback: \n\n%s''' % traceback.format_exc())
92 | "}
93 |
94 | addUserKnob {22 forceUpdateAll l "Force Update All (Update all Gizmos)" +STARTLINE
95 | t "'Force Update All' will run 'Force Update' on all Cryptomatte gizmos in the Nuke script. 'Force Update' orders the gizmos to re-configure themselves based on available metadata, Cryptomatte depth, and the matte list. This updates all aspects of thier operation, from the preview modes to the extraction expression. Usually these updates occur automatically on certain actions, such as 'keying' the image, changing layer selection, or reconnecting images. However if changes occur upstream of the gizmos that require manually invoked updates, 'Force Update' and 'Force Update All' may be used. "
96 | T "
97 | try:
98 | import cryptomatte_utilities as cu
99 | cu.update_all_cryptomatte_gizmos()
100 | except Exception as err:
101 | import traceback
102 | nuke.message('''Unable to run Cryptomatte Gizmo update script. This script is necessary for the Cryptomatte system to work properly. \n\nError Traceback: \n\n%s''' % traceback.format_exc())
103 | "}
104 | addUserKnob {3 frame l INVISIBLE +INVISIBLE}
105 | addUserKnob {1 manifestKey l INVISIBLE +INVISIBLE}
106 |
107 | addUserKnob {41 previewExpression0 l INVISIBLE +INVISIBLE T Expression_preview.expr0}
108 | addUserKnob {41 previewExpression1 l INVISIBLE +INVISIBLE T Expression_preview.expr1}
109 | addUserKnob {41 previewExpression2 l INVISIBLE +INVISIBLE T Expression_preview.expr2}
110 | addUserKnob {41 previewExpression3 l INVISIBLE +INVISIBLE T Expression_preview.expr3}
111 |
112 | addUserKnob {11 previewChannel +HIDDEN}
113 | previewChannel none
114 | addUserKnob {11 in00 +HIDDEN}
115 | addUserKnob {11 in01 +HIDDEN}
116 | addUserKnob {11 in02 +HIDDEN}
117 | addUserKnob {11 in03 +HIDDEN}
118 | addUserKnob {11 in04 +HIDDEN}
119 | addUserKnob {11 in05 +HIDDEN}
120 | addUserKnob {11 in06 +HIDDEN}
121 | addUserKnob {11 in07 +HIDDEN}
122 | addUserKnob {11 in08 +HIDDEN}
123 | addUserKnob {11 in09 +HIDDEN}
124 | addUserKnob {11 in10 +HIDDEN}
125 | addUserKnob {11 in11 +HIDDEN}
126 | addUserKnob {26 "" +HIDDEN}
127 |
128 | }
129 | Input {
130 | inputs 0
131 | name Input1
132 | xpos -1361
133 | ypos -499
134 | }
135 | Dot {
136 | name Dot4
137 | xpos -1327
138 | ypos -439
139 | }
140 | set N13c4bc00 [stack 0]
141 | Dot {
142 | name Dot15
143 | xpos -1093
144 | ypos -439
145 | }
146 | set N13c4b800 [stack 0]
147 | Dot {
148 | name Dot1
149 | xpos -960
150 | ypos -439
151 | }
152 | Shuffle {
153 | red black
154 | green black
155 | blue black
156 | name Shuffle_blackRGB
157 | xpos -994
158 | ypos -398
159 | }
160 | Expression {
161 | channel1 none
162 | channel2 none
163 | channel3 none
164 | name Expression_key
165 | xpos -994
166 | ypos -372
167 | }
168 | Unpremult {
169 | channels {rgba.red -rgba.green -rgba.blue none}
170 | name Unpremult_matte
171 | xpos -994
172 | ypos -340
173 | disable {{!parent.unpremultiply}}
174 | }
175 | set N13c4a400 [stack 0]
176 | Dot {
177 | name Dot11
178 | xpos -960
179 | ypos -142
180 | }
181 | set N13c4a000 [stack 0]
182 | Dot {
183 | name Dot2
184 | xpos -960
185 | ypos -65
186 | }
187 | push $N13c4a000
188 | push $N13c4bc00
189 | Dot {
190 | name Dot8
191 | xpos -1327
192 | ypos -395
193 | }
194 | set N12b01800 [stack 0]
195 | Dot {
196 | name Dot9
197 | xpos -1227
198 | ypos -395
199 | }
200 | Remove {
201 | operation keep
202 | channels rgba
203 | name Remove_channels
204 | xpos -1261
205 | ypos -360
206 | }
207 | push $N12b01800
208 | Switch {
209 | inputs 2
210 | which {{parent.RemoveChannels}}
211 | name Switch_removeChannels
212 | xpos -1361
213 | ypos -312
214 | }
215 | Dot {
216 | name Dot17
217 | xpos -1327
218 | ypos -235
219 | }
220 | set N12b00c00 [stack 0]
221 | Dot {
222 | name Dot10
223 | xpos -1327
224 | ypos -193
225 | }
226 | set N12b00800 [stack 0]
227 | ShuffleCopy {
228 | inputs 2
229 | red red
230 | green red
231 | blue red
232 | alpha red
233 | name ShuffleCopy_matteOnly
234 | xpos -1361
235 | ypos -146
236 | }
237 | Dot {
238 | name Dot16
239 | xpos -1327
240 | ypos -91
241 | }
242 | push $N13c4a400
243 | push $N13c4b800
244 | Shuffle {
245 | alpha black
246 | name Shuffle_blackAlpha
247 | xpos -1127
248 | ypos -394
249 | }
250 | Expression {
251 | name Expression_preview
252 | xpos -1127
253 | ypos -368
254 | }
255 | Grade {
256 | inputs 1+1
257 | channels {rgba.red rgba.green -rgba.blue none}
258 | multiply 0
259 | add 1
260 | black_clamp false
261 | maskChannelMask rgba.red
262 | name Grade_selection
263 | xpos -1127
264 | ypos -340
265 | }
266 | Grade {
267 | channels {-rgba.red rgba.green rgba.blue none}
268 | multiply 0
269 | add 1
270 | black_clamp false
271 | maskChannelInput rgba.alpha
272 | name Grade_highlight
273 | xpos -1127
274 | ypos -302
275 | }
276 | push $N12b00c00
277 | ShuffleCopy {
278 | inputs 2
279 | red red
280 | green green
281 | blue blue
282 | alpha alpha2
283 | name ShuffleCopy_restoreAlpha
284 | xpos -1127
285 | ypos -239
286 | }
287 | push $N12b00800
288 | Switch {
289 | inputs 2
290 | which {{parent.previewEnabled}}
291 | name Switch_preview
292 | xpos -1127
293 | ypos -197
294 | }
295 | Switch {
296 | inputs 2
297 | which {{parent.matteOnly}}
298 | name Switch_matteOnly
299 | xpos -1127
300 | ypos -95
301 | }
302 | ShuffleCopy {
303 | inputs 2
304 | red red
305 | green red
306 | blue red
307 | alpha red
308 | out alpha
309 | name ShuffleCopy_embedMask
310 | xpos -1127
311 | ypos -69
312 | }
313 | Output {
314 | name Output
315 | xpos -1127
316 | ypos -21
317 | }
318 | end_group
319 |
--------------------------------------------------------------------------------
/nuke/Encryptomatte.gizmo:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2014, 2015, 2016, 2017 Psyop Media Company, LLC
3 | # See license.txt
4 | #
5 | version 7.0 v1
6 | Gizmo {
7 | inputs 2
8 | help "Composites new mattes to be added to a set of Cryptomatte-encoded mattes."
9 | addUserKnob {20 Encryptomatte}
10 | addUserKnob {1 matteName l "Matte Name" t "Enter the descriptive name of your matte. If the name is empty, the node does nothing."}
11 | addUserKnob {4 mergeOperation l "Merge Operation" t "Choose a compositing mode to control how your new matte will be merged with the existing set. \n\nThe new matte will be treated like the A input, while the existing mattes will be treated like the B input. The combined result of A and B will be placed over the background matte." M {over under "" ""}}
12 | addUserKnob {7 id l INVISIBLE +INVISIBLE}
13 | addUserKnob {1 idHex l INVISIBLE +INVISIBLE}
14 | addUserKnob {18 previewColor l INVISIBLE +INVISIBLE}
15 | previewColor {0 0 0}
16 | addUserKnob {6 previewColor_panelDropped l "panel dropped state" -STARTLINE +HIDDEN}
17 | addUserKnob {1 cryptoLayer l "Layer Selection" t "If there are multiple cryptomattes, this is how you select the layer."}
18 | addUserKnob {6 cryptoLayerLock l "Lock Layer Selection" t "Stops the automatic update of the layer selection." -STARTLINE}
19 | addUserKnob {1 metadataCache l INVISIBLE t "Internal storage of selection between multiple cryptomatte metadata keys." -STARTLINE +INVISIBLE +DO_NOT_WRITE}
20 | addUserKnob {22 forceUpdate l "Force Update" t "Updates the Gizmo based on which channels are available in the input. \n\nThis happens automatically when input changes, when loading the nuke script, or when a new gizmo is created. This is how it deals with differently named channels in the different Cryptomatte layers, and different depths that it's possible to render at. "
21 | T "
22 | try:
23 | import cryptomatte_utilities as cu
24 | cu.update_encryptomatte_gizmo(nuke.thisNode(), True)
25 | except Exception as err:
26 | import traceback
27 | nuke.message('''Unable to run Encryptomatte Gizmo update script. This script is necessary for the Cryptomatte system to work properly. Please check that the Cryptomatte python plugin is loaded. \n\nError Traceback: \n\n%s''' % traceback.format_exc())
28 | " +STARTLINE}
29 | addUserKnob {6 stopAutoUpdate l "Stop Auto Update" t "Stops the automatic update of this copy of the Gizmo." -STARTLINE}
30 | addUserKnob {41 alphaExpression l INVISIBLE +INVISIBLE T Expression_alpha.expr3}
31 | addUserKnob {1 manifestKey l INVISIBLE +INVISIBLE}
32 | addUserKnob {3 cryptoLayers l Layers t "Number of cryptomatte layers to use."}
33 | cryptoLayers 3
34 |
35 | addUserKnob {3 inputCryptoLayers l INVISIBLE +INVISIBLE}
36 | addUserKnob {6 setupLayers l "Setup Layers" t "Set up the Cryptomatte layers if they do not already exist, and remove any extras." -STARTLINE}
37 | addUserKnob {6 newLayer l INVISIBLE +INVISIBLE +STARTLINE}
38 | addUserKnob {41 previewChannel l INVISIBLE +INVISIBLE T Shuffle_previewChannel.in}
39 | addUserKnob {41 in00 l INVISIBLE +INVISIBLE T Shuffle_00.in}
40 | addUserKnob {41 in01 l INVISIBLE +INVISIBLE T Shuffle_01.in}
41 | addUserKnob {41 in02 l INVISIBLE +INVISIBLE T Shuffle_02.in}
42 | addUserKnob {41 in03 l INVISIBLE +INVISIBLE T Shuffle_03.in}
43 | addUserKnob {41 in04 l INVISIBLE +INVISIBLE T Shuffle_04.in}
44 | addUserKnob {41 in05 l INVISIBLE +INVISIBLE T Shuffle_05.in}
45 | addUserKnob {41 in06 l INVISIBLE +INVISIBLE T Shuffle_06.in}
46 | addUserKnob {41 in07 l INVISIBLE +INVISIBLE T Shuffle_07.in}
47 | addUserKnob {41 in08 l INVISIBLE +INVISIBLE T Shuffle_08.in}
48 | addUserKnob {41 in09 l INVISIBLE +INVISIBLE T Shuffle_09.in}
49 | addUserKnob {41 in10 l INVISIBLE +INVISIBLE T Shuffle_10.in}
50 | addUserKnob {41 in11 l INVISIBLE +INVISIBLE T Shuffle_11.in}
51 | addUserKnob {41 removePreviewChannel l INVISIBLE +INVISIBLE T Remove_previewChannel.channels}
52 | addUserKnob {41 remove00 l INVISIBLE +INVISIBLE T Remove_00_03.channels}
53 | addUserKnob {41 remove01 l INVISIBLE +INVISIBLE T Remove_00_03.channels2}
54 | addUserKnob {41 remove02 l INVISIBLE +INVISIBLE T Remove_00_03.channels3}
55 | addUserKnob {41 remove03 l INVISIBLE +INVISIBLE T Remove_00_03.channels4}
56 | addUserKnob {41 remove04 l INVISIBLE +INVISIBLE T Remove_04_07.channels}
57 | addUserKnob {41 remove05 l INVISIBLE +INVISIBLE T Remove_04_07.channels2}
58 | addUserKnob {41 remove06 l INVISIBLE +INVISIBLE T Remove_04_07.channels3}
59 | addUserKnob {41 remove07 l INVISIBLE +INVISIBLE T Remove_04_07.channels4}
60 | addUserKnob {41 addPreviewChannel l INVISIBLE +INVISIBLE T AddChannels_previewChannel.channels}
61 | addUserKnob {41 add00 l INVISIBLE +INVISIBLE T AddChannels_00_03.channels}
62 | addUserKnob {41 add01 l INVISIBLE +INVISIBLE T AddChannels_00_03.channels2}
63 | addUserKnob {41 add02 l INVISIBLE +INVISIBLE T AddChannels_00_03.channels3}
64 | addUserKnob {41 add03 l INVISIBLE +INVISIBLE T AddChannels_00_03.channels4}
65 | addUserKnob {41 add04 l INVISIBLE +INVISIBLE T AddChannels_04_07.channels}
66 | addUserKnob {41 add05 l INVISIBLE +INVISIBLE T AddChannels_04_07.channels2}
67 | addUserKnob {41 add06 l INVISIBLE +INVISIBLE T AddChannels_04_07.channels3}
68 | addUserKnob {41 add07 l INVISIBLE +INVISIBLE T AddChannels_04_07.channels4}
69 |
70 | addUserKnob {20 Advanced}
71 |
72 | addUserKnob {26 cryptomatteVersion l "Cryptomatte Version" T 1.4.0}
73 | }
74 | Input {
75 | inputs 0
76 | name Input1
77 | xpos -1305
78 | ypos -1346
79 | }
80 | Dot {
81 | name Dot47
82 | xpos -1271
83 | ypos -1287
84 | }
85 | set N6fbc7400 [stack 0]
86 | Dot {
87 | name Dot48
88 | xpos -1491
89 | ypos -1287
90 | }
91 | Remove {
92 | channels none
93 | name Remove_previewChannel
94 | xpos -1525
95 | ypos -1257
96 | }
97 | Remove {
98 | channels none
99 | name Remove_00_03
100 | xpos -1525
101 | ypos -1219
102 | }
103 | Remove {
104 | channels none
105 | name Remove_04_07
106 | xpos -1525
107 | ypos -1181
108 | }
109 | AddChannels {
110 | name AddChannels_previewChannel
111 | xpos -1525
112 | ypos -1120
113 | }
114 | AddChannels {
115 | name AddChannels_00_03
116 | xpos -1525
117 | ypos -1082
118 | }
119 | AddChannels {
120 | name AddChannels_04_07
121 | xpos -1525
122 | ypos -1044
123 | }
124 | set N9419b800 [stack 0]
125 | Dot {
126 | name Dot52
127 | xpos -1379
128 | ypos -1034
129 | }
130 | Shuffle {
131 | in {{{parent.Shuffle_00.in}}}
132 | red black
133 | green white
134 | blue black
135 | alpha black
136 | out {{{parent.Shuffle_00.in}}}
137 | name Shuffle_SetBG
138 | xpos -1413
139 | ypos -989
140 | }
141 | ModifyMetaData {
142 | metadata {
143 | {set "\[value parent.manifestKey]manifest" "\{\}"}
144 | {set "\[value parent.manifestKey]conversion" uint32_to_float32}
145 | {set "\[value parent.manifestKey]hash" MurmurHash3_32}
146 | {set "\[value parent.manifestKey]name" "\[value parent.cryptoLayer]"}
147 | }
148 | name ModifyMetaData1
149 | xpos -1413
150 | ypos -940
151 | }
152 | push $N9419b800
153 | Dot {
154 | name Dot50
155 | xpos -1491
156 | ypos -899
157 | }
158 | Switch {
159 | inputs 2
160 | which {{parent.newLayer}}
161 | name Switch_ResetMetadata
162 | xpos -1413
163 | ypos -903
164 | }
165 | Dot {
166 | name Dot49
167 | xpos -1379
168 | ypos -847
169 | }
170 | push $N6fbc7400
171 | Switch {
172 | inputs 2
173 | which {{parent.setupLayers}}
174 | name Switch_SetupLayers
175 | xpos -1305
176 | ypos -851
177 | }
178 | Dot {
179 | name Dot15
180 | xpos -1271
181 | ypos -693
182 | }
183 | set N9419a000 [stack 0]
184 | Dot {
185 | name Dot14
186 | xpos -1271
187 | ypos 1856
188 | }
189 | set N9949c00 [stack 0]
190 | Dot {
191 | name Dot46
192 | xpos -1271
193 | ypos 1954
194 | }
195 | Input {
196 | inputs 0
197 | name Matte
198 | xpos 455
199 | ypos -820
200 | number 1
201 | }
202 | Dot {
203 | name Dot53
204 | xpos 489
205 | ypos -674
206 | }
207 | set N9949000 [stack 0]
208 | Dot {
209 | name Dot51
210 | xpos 599
211 | ypos -674
212 | }
213 | Shuffle {
214 | red black
215 | green black
216 | blue black
217 | name Shuffle6
218 | xpos 565
219 | ypos 1349
220 | }
221 | Add {
222 | channels rgba
223 | value {{parent.previewColor.r} {parent.previewColor.g} {parent.previewColor.b} 0}
224 | name Add1
225 | xpos 565
226 | ypos 1435
227 | }
228 | Premult {
229 | name Premult1
230 | xpos 565
231 | ypos 1509
232 | }
233 | push $N9419a000
234 | Dot {
235 | name Dot1
236 | xpos -1074
237 | ypos -693
238 | }
239 | set N9971c00 [stack 0]
240 | Dot {
241 | name Dot11
242 | xpos -897
243 | ypos -693
244 | }
245 | set N9971800 [stack 0]
246 | Dot {
247 | name Dot16
248 | xpos 119
249 | ypos -700
250 | }
251 | set N9971400 [stack 0]
252 | Dot {
253 | name Dot41
254 | xpos 261
255 | ypos -700
256 | }
257 | Expression {
258 | channel0 none
259 | channel1 none
260 | channel2 none
261 | channel3 alpha
262 | name Expression_alpha
263 | xpos 227
264 | ypos -682
265 | }
266 | Invert {
267 | channels alpha
268 | name Invert1
269 | xpos 227
270 | ypos -656
271 | }
272 | Dot {
273 | name Dot4
274 | xpos 261
275 | ypos -597
276 | }
277 | set N9970000 [stack 0]
278 | Dot {
279 | name Dot6
280 | xpos 261
281 | ypos 1236
282 | }
283 | set N9991c00 [stack 0]
284 | Dot {
285 | name Dot44
286 | xpos 360
287 | ypos 1236
288 | }
289 | Shuffle {
290 | in none
291 | in2 rgba
292 | alpha alpha2
293 | name Shuffle_previewChannel
294 | xpos 326
295 | ypos 1347
296 | }
297 | Merge2 {
298 | inputs 2
299 | operation {{"\[python nuke.thisKnob().values().index(nuke.thisParent().knob('mergeOperation').value())]"}}
300 | name Merge_AB
301 | xpos 326
302 | ypos 1509
303 | addUserKnob {20 User}
304 | addUserKnob {22 createExpression l "Create Expression" T "nuke.thisNode().knob('operation').setExpression(\"\[python nuke.thisKnob().values().index(nuke.thisParent().knob('mergeOperation').value())]\")" +STARTLINE}
305 | }
306 | set C9991000 [stack 0]
307 | push $N9991c00
308 | Shuffle {
309 | red black
310 | green black
311 | blue black
312 | alpha white
313 | name Shuffle1
314 | xpos 227
315 | ypos 1345
316 | }
317 | Merge2 {
318 | inputs 2
319 | name Merge_Background
320 | xpos 227
321 | ypos 1570
322 | }
323 | set C9990800 [stack 0]
324 | push $N9949000
325 | Shuffle {
326 | red black
327 | green black
328 | blue white
329 | name Shuffle_A
330 | xpos 455
331 | ypos -601
332 | }
333 | Premult {
334 | name Premult3
335 | xpos 455
336 | ypos -548
337 | }
338 | push $N9970000
339 | Shuffle {
340 | red white
341 | green black
342 | blue black
343 | name Shuffle_B
344 | xpos 339
345 | ypos -601
346 | }
347 | Premult {
348 | name Premult2
349 | xpos 339
350 | ypos -549
351 | }
352 | clone $C9991000 {
353 | inputs 2
354 | xpos 455
355 | ypos -478
356 | selected false
357 | }
358 | push $N9971400
359 | Dot {
360 | name Dot42
361 | xpos 119
362 | ypos -507
363 | }
364 | Dot {
365 | name Dot43
366 | xpos 376
367 | ypos -507
368 | }
369 | Shuffle {
370 | red black
371 | green white
372 | blue black
373 | alpha white
374 | name Shuffle_Background
375 | xpos 342
376 | ypos -460
377 | }
378 | clone $C9990800 {
379 | inputs 2
380 | xpos 455
381 | ypos -392
382 | selected true
383 | }
384 | set N99c6400 [stack 0]
385 | Shuffle {
386 | red black
387 | name Shuffle_Under
388 | xpos 511
389 | ypos -283
390 | }
391 | push $N99c6400
392 | Shuffle {
393 | red blue
394 | name Shuffle_Over
395 | xpos 408
396 | ypos -284
397 | }
398 | Switch {
399 | inputs 2
400 | which {{parent.mergeOperation}}
401 | name Switch_MatteExisting
402 | xpos 456
403 | ypos -189
404 | }
405 | Dot {
406 | name Dot19
407 | xpos -3
408 | ypos -185
409 | }
410 | set N99fb800 [stack 0]
411 | Dot {
412 | name Dot29
413 | xpos -73
414 | ypos -185
415 | }
416 | set N99fb400 [stack 0]
417 | Dot {
418 | name Dot28
419 | xpos -183
420 | ypos -185
421 | }
422 | set N99fb000 [stack 0]
423 | push $N9971800
424 | Dot {
425 | name Dot10
426 | xpos -897
427 | ypos -293
428 | }
429 | set N99fac00 [stack 0]
430 | Dot {
431 | name Dot12
432 | xpos -787
433 | ypos -293
434 | }
435 | set N99fa800 [stack 0]
436 | Dot {
437 | name Dot13
438 | xpos -677
439 | ypos -293
440 | }
441 | set N99fa400 [stack 0]
442 | Dot {
443 | name Dot17
444 | xpos -567
445 | ypos -293
446 | }
447 | set N99fa000 [stack 0]
448 | Dot {
449 | name Dot18
450 | xpos -457
451 | ypos -293
452 | }
453 | set N9a1fc00 [stack 0]
454 | Dot {
455 | name Dot22
456 | xpos -347
457 | ypos -293
458 | }
459 | set N9a1f800 [stack 0]
460 | Dot {
461 | name Dot23
462 | xpos -237
463 | ypos -293
464 | }
465 | set N9a1f400 [stack 0]
466 | Shuffle {
467 | in none
468 | name Shuffle_06
469 | xpos -271
470 | ypos -263
471 | }
472 | Multiply {
473 | inputs 1+1
474 | channels {-rgba.red rgba.green -rgba.blue rgba.alpha}
475 | value {1 0 1 0}
476 | maskChannelMask rgba.red
477 | name Multiply1
478 | xpos -271
479 | ypos -127
480 | }
481 | set C9a1ec00 [stack 0]
482 | Dot {
483 | name Dot34
484 | xpos -237
485 | ypos 6
486 | }
487 | set N9a1e800 [stack 0]
488 | push $N99fb400
489 | push $N9a1f400
490 | Dot {
491 | name Dot24
492 | xpos -127
493 | ypos -293
494 | }
495 | Shuffle {
496 | in none
497 | name Shuffle_07
498 | xpos -161
499 | ypos -264
500 | }
501 | clone $C9a1ec00 {
502 | inputs 1+1
503 | xpos -161
504 | ypos -126
505 | selected false
506 | }
507 | push $N99fb800
508 | Shuffle {
509 | red black
510 | blue black
511 | alpha blue
512 | name Shuffle_ForegroundBackground
513 | xpos -37
514 | ypos -126
515 | }
516 | Add {
517 | channels {-rgba.red -rgba.green rgba.blue none}
518 | value {0 0 {parent.id} 0}
519 | name Add2
520 | xpos -37
521 | ypos -78
522 | }
523 | set Na1fb400 [stack 0]
524 | MergeExpression {
525 | inputs 2
526 | temp_name0 orderAr
527 | temp_expr0 "(A.green * (A.red != 0.0) >= A.alpha * (A.blue != 0.0)) + (A.green * (A.red != 0.0) >= B.green) + (A.green * (A.red != 0.0) >= B.alpha)"
528 | temp_name1 orderAb
529 | temp_expr1 "(A.alpha * (A.blue != 0.0) > A.green * (A.red != 0.0)) + (A.alpha >= B.green) + (A.alpha * (A.blue != 0.0) >= B.alpha)"
530 | temp_name2 orderBr
531 | temp_expr2 "(B.green > A.green * (A.red != 0.0)) + (B.green > A.alpha * (A.blue != 0.0)) + (B.green >= B.alpha)"
532 | temp_name3 orderBb
533 | temp_expr3 "(B.alpha > A.green * (A.red != 0.0)) + (B.alpha > B.green) + (B.alpha > A.alpha * (A.blue != 0.0))"
534 | expr0 "(orderAr == 3.0) * A.red + (orderBr == 3.0) * B.red + (orderAb == 3.0) * A.blue + (orderBb == 3.0) * B.blue"
535 | expr1 "(orderAr == 3.0) * A.green * (A.red != 0.0) + (orderBr == 3.0) * B.green + (orderAb == 3.0) * A.alpha * (A.blue != 0.0) + (orderBb == 3.0) * B.alpha"
536 | expr2 "(orderAr == 2.0) * A.red + (orderBr == 2.0) * B.red + (orderAb == 2.0) * A.blue + (orderBb == 2.0) * B.blue"
537 | channel3 alpha
538 | expr3 "(orderAr == 2.0) * A.green * (A.red != 0.0) + (orderBr == 2.0) * B.green + (orderAb == 2.0) * A.alpha * (A.blue != 0.0) + (orderBb == 2.0) * B.alpha"
539 | name MergeExpression7
540 | xpos -161
541 | ypos 4
542 | }
543 | set Ca1fb000 [stack 0]
544 | push $Na1fb400
545 | Dot {
546 | name Dot35
547 | xpos -3
548 | ypos 77
549 | }
550 | Switch {
551 | inputs 2
552 | which {{"parent.cryptoLayers > 7"}}
553 | name Switch_07
554 | xpos -161
555 | ypos 73
556 | disable true
557 | }
558 | set C6f60d200 [stack 0]
559 | set N6f60d200 [stack 0]
560 | MergeExpression {
561 | inputs 2
562 | temp_name0 orderAr
563 | temp_expr0 "(A.green * (A.red != 0.0) >= A.alpha * (A.blue != 0.0)) + (A.green * (A.red != 0.0) >= B.green) + (A.green * (A.red != 0.0) >= B.alpha)"
564 | temp_name1 orderAb
565 | temp_expr1 "(A.alpha * (A.blue != 0.0) > A.green * (A.red != 0.0)) + (A.alpha >= B.green) + (A.alpha * (A.blue != 0.0) >= B.alpha)"
566 | temp_name2 orderBr
567 | temp_expr2 "(B.green > A.green * (A.red != 0.0)) + (B.green > A.alpha * (A.blue != 0.0)) + (B.green >= B.alpha)"
568 | temp_name3 orderBb
569 | temp_expr3 "(B.alpha > A.green * (A.red != 0.0)) + (B.alpha > B.green) + (B.alpha > A.alpha * (A.blue != 0.0))"
570 | expr0 "(orderAr == 1.0) * A.red + (orderBr == 1.0) * B.red + (orderAb == 1.0) * A.blue + (orderBb == 1.0) * B.blue"
571 | expr1 "(orderAr == 1.0) * A.green * (A.red != 0.0) + (orderBr == 1.0) * B.green + (orderAb == 1.0) * A.alpha * (A.blue != 0.0) + (orderBb == 1.0) * B.alpha"
572 | expr2 "(orderAr == 0.0) * A.red + (orderBr == 0.0) * B.red + (orderAb == 0.0) * A.blue + (orderBb == 0.0) * B.blue"
573 | channel3 alpha
574 | expr3 "(orderAr == 0.0) * A.green * (A.red != 0.0) + (orderBr == 0.0) * B.green + (orderAb == 0.0) * A.alpha * (A.blue != 0.0) + (orderBb == 0.0) * B.alpha"
575 | name MergeExpression2
576 | xpos -161
577 | ypos 154
578 | }
579 | set Ca1fa400 [stack 0]
580 | Dot {
581 | name Dot40
582 | xpos -130
583 | ypos 1257
584 | }
585 | push $N99fb000
586 | Dot {
587 | name Dot27
588 | xpos -293
589 | ypos -185
590 | }
591 | set Na22d800 [stack 0]
592 | push $N9a1f800
593 | Shuffle {
594 | in none
595 | name Shuffle_05
596 | xpos -381
597 | ypos -264
598 | }
599 | clone $C9a1ec00 {
600 | inputs 1+1
601 | xpos -381
602 | ypos -127
603 | selected false
604 | }
605 | Dot {
606 | name Dot33
607 | xpos -347
608 | ypos 75
609 | }
610 | set Na22cc00 [stack 0]
611 | push $N9a1e800
612 | push $N6f60d200
613 | clone $Ca1fb000 {
614 | inputs 2
615 | xpos -271
616 | ypos 71
617 | selected false
618 | }
619 | push $N6f60d200
620 | Switch {
621 | inputs 2
622 | which {{"parent.cryptoLayers > 6"}}
623 | name Switch_06
624 | xpos -271
625 | ypos 137
626 | disable true
627 | }
628 | set C6f60cd80 [stack 0]
629 | set N6f60cd80 [stack 0]
630 | clone $Ca1fa400 {
631 | inputs 2
632 | xpos -271
633 | ypos 221
634 | selected false
635 | }
636 | Dot {
637 | name Dot39
638 | xpos -240
639 | ypos 1184
640 | }
641 | push $Na22d800
642 | Dot {
643 | name Dot26
644 | xpos -398
645 | ypos -185
646 | }
647 | set Na255400 [stack 0]
648 | push $N9a1fc00
649 | Shuffle {
650 | in none
651 | name Shuffle_04
652 | xpos -491
653 | ypos -264
654 | }
655 | clone $C9a1ec00 {
656 | inputs 1+1
657 | xpos -491
658 | ypos -128
659 | selected false
660 | }
661 | Dot {
662 | name Dot32
663 | xpos -457
664 | ypos 141
665 | }
666 | set Na254800 [stack 0]
667 | push $Na22cc00
668 | push $N6f60cd80
669 | clone $Ca1fb000 {
670 | inputs 2
671 | xpos -381
672 | ypos 137
673 | selected false
674 | }
675 | push $N6f60cd80
676 | Switch {
677 | inputs 2
678 | which {{"parent.cryptoLayers > 5"}}
679 | name Switch_05
680 | xpos -381
681 | ypos 203
682 | disable true
683 | }
684 | set C6f60c900 [stack 0]
685 | set N6f60c900 [stack 0]
686 | clone $Ca1fa400 {
687 | inputs 2
688 | xpos -381
689 | ypos 288
690 | selected false
691 | }
692 | Dot {
693 | name Dot38
694 | xpos -347
695 | ypos 1120
696 | }
697 | push $Na255400
698 | Dot {
699 | name Dot25
700 | xpos -508
701 | ypos -185
702 | }
703 | set Na289000 [stack 0]
704 | push $N99fa000
705 | Shuffle {
706 | in none
707 | name Shuffle_03
708 | xpos -601
709 | ypos -264
710 | }
711 | clone $C9a1ec00 {
712 | inputs 1+1
713 | xpos -601
714 | ypos -128
715 | selected false
716 | }
717 | Dot {
718 | name Dot31
719 | xpos -567
720 | ypos 207
721 | }
722 | set Na288400 [stack 0]
723 | push $Na254800
724 | push $N6f60c900
725 | clone $Ca1fb000 {
726 | inputs 2
727 | xpos -491
728 | ypos 203
729 | selected false
730 | }
731 | push $N6f60c900
732 | Switch {
733 | inputs 2
734 | which {{"parent.cryptoLayers > 4"}}
735 | name Switch_04
736 | xpos -491
737 | ypos 269
738 | disable true
739 | }
740 | set C6f60c480 [stack 0]
741 | set N6f60c480 [stack 0]
742 | clone $Ca1fa400 {
743 | inputs 2
744 | xpos -491
745 | ypos 353
746 | selected false
747 | }
748 | Dot {
749 | name Dot37
750 | xpos -457
751 | ypos 1054
752 | }
753 | push $Na289000
754 | Dot {
755 | name Dot3
756 | xpos -618
757 | ypos -185
758 | }
759 | set Na2aac00 [stack 0]
760 | push $N99fa400
761 | Shuffle {
762 | in none
763 | name Shuffle_02
764 | xpos -711
765 | ypos -264
766 | }
767 | clone $C9a1ec00 {
768 | inputs 1+1
769 | xpos -711
770 | ypos -128
771 | selected false
772 | }
773 | Dot {
774 | name Dot30
775 | xpos -677
776 | ypos 273
777 | }
778 | set Na2aa000 [stack 0]
779 | push $Na288400
780 | push $N6f60c480
781 | clone $Ca1fb000 {
782 | inputs 2
783 | xpos -601
784 | ypos 269
785 | selected false
786 | }
787 | push $N6f60c480
788 | Switch {
789 | inputs 2
790 | which {{"parent.cryptoLayers > 3"}}
791 | name Switch_03
792 | xpos -601
793 | ypos 337
794 | disable true
795 | }
796 | set C6f60c000 [stack 0]
797 | set N6f60c000 [stack 0]
798 | clone $Ca1fa400 {
799 | inputs 2
800 | xpos -601
801 | ypos 420
802 | selected false
803 | }
804 | Dot {
805 | name Dot36
806 | xpos -567
807 | ypos 978
808 | }
809 | push $Na2aac00
810 | Dot {
811 | name Dot5
812 | xpos -728
813 | ypos -185
814 | }
815 | set Na2dc800 [stack 0]
816 | push $N99fa800
817 | Shuffle {
818 | in none
819 | name Shuffle_01
820 | xpos -821
821 | ypos -263
822 | }
823 | clone $C9a1ec00 {
824 | inputs 1+1
825 | xpos -821
826 | ypos -129
827 | selected false
828 | }
829 | Dot {
830 | name Dot9
831 | xpos -787
832 | ypos 339
833 | }
834 | set N4b26bc00 [stack 0]
835 | push $Na2aa000
836 | push $N6f60c000
837 | clone $Ca1fb000 {
838 | inputs 2
839 | xpos -711
840 | ypos 337
841 | selected false
842 | }
843 | push $N6f60c000
844 | Switch {
845 | inputs 2
846 | which {{"parent.cryptoLayers > 2"}}
847 | name Switch_02
848 | xpos -711
849 | ypos 411
850 | }
851 | set C4b27da80 [stack 0]
852 | set N4b27da80 [stack 0]
853 | clone $Ca1fa400 {
854 | inputs 2
855 | xpos -711
856 | ypos 489
857 | selected false
858 | }
859 | Dot {
860 | name Dot21
861 | xpos -677
862 | ypos 913
863 | }
864 | push $Na2dc800
865 | Dot {
866 | name Dot7
867 | xpos -838
868 | ypos -185
869 | }
870 | push $N99fac00
871 | Shuffle {
872 | in none
873 | black red
874 | white green
875 | red2 blue
876 | green2 alpha
877 | name Shuffle_00
878 | xpos -931
879 | ypos -262
880 | }
881 | clone $C9a1ec00 {
882 | inputs 1+1
883 | xpos -931
884 | ypos -129
885 | selected false
886 | }
887 | Dot {
888 | name Dot8
889 | xpos -897
890 | ypos 409
891 | }
892 | set N4b299800 [stack 0]
893 | push $N4b26bc00
894 | push $N4b27da80
895 | clone $Ca1fb000 {
896 | inputs 2
897 | xpos -821
898 | ypos 406
899 | selected false
900 | }
901 | push $N4b27da80
902 | Switch {
903 | inputs 2
904 | which {{"parent.cryptoLayers > 1"}}
905 | name Switch_01
906 | xpos -821
907 | ypos 475
908 | }
909 | set C4b27d600 [stack 0]
910 | set N4b27d600 [stack 0]
911 | clone $Ca1fa400 {
912 | inputs 2
913 | xpos -821
914 | ypos 561
915 | selected false
916 | }
917 | Dot {
918 | name Dot20
919 | xpos -787
920 | ypos 828
921 | }
922 | push $N4b299800
923 | push $N4b27d600
924 | clone $Ca1fb000 {
925 | inputs 2
926 | xpos -931
927 | ypos 475
928 | selected false
929 | }
930 | push $N4b27d600
931 | Switch {
932 | inputs 2
933 | which {{"parent.cryptoLayers > 0"}}
934 | name Switch_00
935 | xpos -931
936 | ypos 536
937 | }
938 | set C4b27d180 [stack 0]
939 | push $N9971c00
940 | Dot {
941 | name Dot2
942 | xpos -1074
943 | ypos 802
944 | }
945 | set N4b2c5800 [stack 0]
946 | ShuffleCopy {
947 | inputs 2
948 | alpha alpha2
949 | black red
950 | white green
951 | red2 blue
952 | green2 alpha
953 | out2 {{{parent.Shuffle_00.in}}}
954 | name ShuffleCopy_00
955 | xpos -931
956 | ypos 798
957 | addUserKnob {20 User}
958 | addUserKnob {22 setExpression l "Set Expression" T "nuke.thisNode().knob('out2').setExpression('\[value parent.in00]')" +STARTLINE}
959 | }
960 | push $N4b2c5800
961 | clone $C4b27d180 {
962 | inputs 2
963 | xpos -1108
964 | ypos 857
965 | selected false
966 | }
967 | set N4b27cd00 [stack 0]
968 | ShuffleCopy {
969 | inputs 2
970 | alpha alpha2
971 | black red
972 | white green
973 | red2 blue
974 | green2 alpha
975 | out2 {{{parent.Shuffle_01.in}}}
976 | name ShuffleCopy_01
977 | xpos -931
978 | ypos 857
979 | }
980 | push $N4b27cd00
981 | clone $C4b27d600 {
982 | inputs 2
983 | xpos -1108
984 | ypos 910
985 | selected false
986 | }
987 | set N4b27c880 [stack 0]
988 | ShuffleCopy {
989 | inputs 2
990 | alpha alpha2
991 | black red
992 | white green
993 | red2 blue
994 | green2 alpha
995 | out2 {{{parent.Shuffle_02.in}}}
996 | name ShuffleCopy_02
997 | xpos -931
998 | ypos 909
999 | }
1000 | push $N4b27c880
1001 | clone $C4b27da80 {
1002 | inputs 2
1003 | xpos -1108
1004 | ypos 974
1005 | selected false
1006 | }
1007 | set N4b27c400 [stack 0]
1008 | ShuffleCopy {
1009 | inputs 2
1010 | alpha alpha2
1011 | black red
1012 | white green
1013 | red2 blue
1014 | green2 alpha
1015 | out2 {{{parent.Shuffle_03.in}}}
1016 | name ShuffleCopy_03
1017 | xpos -931
1018 | ypos 974
1019 | }
1020 | push $N4b27c400
1021 | clone $C6f60c000 {
1022 | inputs 2
1023 | xpos -1108
1024 | ypos 1053
1025 | selected false
1026 | }
1027 | set N4b27bf80 [stack 0]
1028 | ShuffleCopy {
1029 | inputs 2
1030 | alpha alpha2
1031 | black red
1032 | white green
1033 | red2 blue
1034 | green2 alpha
1035 | out2 {{{parent.Shuffle_04.in}}}
1036 | name ShuffleCopy_04
1037 | xpos -931
1038 | ypos 1050
1039 | }
1040 | push $N4b27bf80
1041 | clone $C6f60c480 {
1042 | inputs 2
1043 | xpos -1108
1044 | ypos 1120
1045 | selected false
1046 | }
1047 | set N4b27bb00 [stack 0]
1048 | ShuffleCopy {
1049 | inputs 2
1050 | alpha alpha2
1051 | black red
1052 | white green
1053 | red2 blue
1054 | green2 alpha
1055 | out2 {{{parent.Shuffle_05.in}}}
1056 | name ShuffleCopy_05
1057 | xpos -931
1058 | ypos 1116
1059 | }
1060 | push $N4b27bb00
1061 | clone $C6f60c900 {
1062 | inputs 2
1063 | xpos -1108
1064 | ypos 1185
1065 | selected false
1066 | }
1067 | set N4b27b680 [stack 0]
1068 | ShuffleCopy {
1069 | inputs 2
1070 | alpha alpha2
1071 | black red
1072 | white green
1073 | red2 blue
1074 | green2 alpha
1075 | out2 {{{parent.Shuffle_06.in}}}
1076 | name ShuffleCopy_06
1077 | xpos -931
1078 | ypos 1180
1079 | }
1080 | push $N4b27b680
1081 | clone $C6f60cd80 {
1082 | inputs 2
1083 | xpos -1108
1084 | ypos 1256
1085 | selected false
1086 | }
1087 | set N4b27b200 [stack 0]
1088 | ShuffleCopy {
1089 | inputs 2
1090 | alpha alpha2
1091 | black red
1092 | white green
1093 | red2 blue
1094 | green2 alpha
1095 | out2 {{{parent.Shuffle_07.in}}}
1096 | name ShuffleCopy_07
1097 | xpos -931
1098 | ypos 1253
1099 | }
1100 | push $N4b27b200
1101 | clone $C6f60d200 {
1102 | inputs 2
1103 | xpos -1108
1104 | ypos 1328
1105 | selected false
1106 | }
1107 | Dot {
1108 | name Dot45
1109 | xpos -1074
1110 | ypos 1646
1111 | }
1112 | ShuffleCopy {
1113 | inputs 2
1114 | alpha alpha2
1115 | black red
1116 | white green
1117 | red2 blue
1118 | green2 alpha
1119 | out2 {{{parent.Shuffle_previewChannel.in}}}
1120 | name ShuffleCopy_previewChannel
1121 | xpos 227
1122 | ypos 1642
1123 | }
1124 | ModifyMetaData {
1125 | metadata {
1126 | {set "\[value parent.manifestKey]manifest" "\[python -execlocal import cryptomatte_utilities\\nret=cryptomatte_utilities.encryptomatte_add_manifest_id()]"}
1127 | }
1128 | name ModifyMetaData2
1129 | xpos 227
1130 | ypos 1703
1131 | }
1132 | push $N9949c00
1133 | Switch {
1134 | inputs 2
1135 | which {{parent.id!=0.0}}
1136 | name Switch1
1137 | xpos 227
1138 | ypos 1852
1139 | }
1140 | Switch {
1141 | inputs 2
1142 | which {{"\[python (nuke.thisParent().input(0)\\ is\\ None)\\ and\\ (nuke.thisParent().input(1)\\ is\\ None)\\ and\\ not\\ nuke.thisParent()\\\['setupLayers'\\].value()]"}}
1143 | name Switch2
1144 | xpos 227
1145 | ypos 1950
1146 | }
1147 | Output {
1148 | name Output1
1149 | xpos 227
1150 | ypos 2051
1151 | }
1152 | end_group
1153 |
--------------------------------------------------------------------------------
/nuke/cryptomatte_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/nuke/cryptomatte_logo.png
--------------------------------------------------------------------------------
/nuke/init.py:
--------------------------------------------------------------------------------
1 | #
2 | #
3 | # Copyright (c) 2014, 2015, 2016, 2017 Psyop Media Company, LLC
4 | # See license.txt
5 | #
6 | #
7 |
8 | import cryptomatte_utilities
9 | cryptomatte_utilities.setup_cryptomatte()
10 |
11 |
--------------------------------------------------------------------------------
/nuke/menu.py:
--------------------------------------------------------------------------------
1 | #
2 | #
3 | # Copyright (c) 2014, 2015, 2016, 2017 Psyop Media Company, LLC
4 | # See license.txt
5 | #
6 | #
7 |
8 | import cryptomatte_utilities
9 | cryptomatte_utilities.setup_cryptomatte_ui()
10 |
11 |
--------------------------------------------------------------------------------
/nuke/pymmh3.py:
--------------------------------------------------------------------------------
1 | '''
2 | pymmh3 was written by Fredrik Kihlander and enhanced by Swapnil Gusani, and is placed in the public
3 | domain. The authors hereby disclaim copyright to this source code.
4 |
5 | pure python implementation of the murmur3 hash algorithm
6 |
7 | https://code.google.com/p/smhasher/wiki/MurmurHash3
8 |
9 | This was written for the times when you do not want to compile c-code and install modules,
10 | and you only want a drop-in murmur3 implementation.
11 |
12 | As this is purely python it is FAR from performant and if performance is anything that is needed
13 | a proper c-module is suggested!
14 |
15 | This module is written to have the same format as mmh3 python package found here for simple conversions:
16 |
17 | https://pypi.python.org/pypi/mmh3/2.3.1
18 | '''
19 |
20 | import sys as _sys
21 | if (_sys.version_info > (3, 0)):
22 | def xrange( a, b, c ):
23 | return list(range( a, b, c))
24 | def xencode(x):
25 | if isinstance(x, bytes) or isinstance(x, bytearray):
26 | return x
27 | else:
28 | return x.encode()
29 | else:
30 | def xencode(x):
31 | return x
32 | del _sys
33 |
34 | def hash( key, seed = 0x0 ):
35 | ''' Implements 32bit murmur3 hash. '''
36 |
37 | key = bytearray( xencode(key) )
38 |
39 | def fmix( h ):
40 | h ^= h >> 16
41 | h = ( h * 0x85ebca6b ) & 0xFFFFFFFF
42 | h ^= h >> 13
43 | h = ( h * 0xc2b2ae35 ) & 0xFFFFFFFF
44 | h ^= h >> 16
45 | return h
46 |
47 | length = len( key )
48 | nblocks = int( length / 4 )
49 |
50 | h1 = seed
51 |
52 | c1 = 0xcc9e2d51
53 | c2 = 0x1b873593
54 |
55 | # body
56 | for block_start in range( 0, nblocks * 4, 4 ):
57 | # ??? big endian?
58 | k1 = key[ block_start + 3 ] << 24 | \
59 | key[ block_start + 2 ] << 16 | \
60 | key[ block_start + 1 ] << 8 | \
61 | key[ block_start + 0 ]
62 |
63 | k1 = ( c1 * k1 ) & 0xFFFFFFFF
64 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32
65 | k1 = ( c2 * k1 ) & 0xFFFFFFFF
66 |
67 | h1 ^= k1
68 | h1 = ( h1 << 13 | h1 >> 19 ) & 0xFFFFFFFF # inlined ROTL32
69 | h1 = ( h1 * 5 + 0xe6546b64 ) & 0xFFFFFFFF
70 |
71 | # tail
72 | tail_index = nblocks * 4
73 | k1 = 0
74 | tail_size = length & 3
75 |
76 | if tail_size >= 3:
77 | k1 ^= key[ tail_index + 2 ] << 16
78 | if tail_size >= 2:
79 | k1 ^= key[ tail_index + 1 ] << 8
80 | if tail_size >= 1:
81 | k1 ^= key[ tail_index + 0 ]
82 |
83 | if tail_size > 0:
84 | k1 = ( k1 * c1 ) & 0xFFFFFFFF
85 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32
86 | k1 = ( k1 * c2 ) & 0xFFFFFFFF
87 | h1 ^= k1
88 |
89 | #finalization
90 | unsigned_val = fmix( h1 ^ length )
91 | if unsigned_val & 0x80000000 == 0:
92 | return unsigned_val
93 | else:
94 | return -( (unsigned_val ^ 0xFFFFFFFF) + 1 )
95 |
96 |
97 | def hash128( key, seed = 0x0, x64arch = True ):
98 | ''' Implements 128bit murmur3 hash. '''
99 | def hash128_x64( key, seed ):
100 | ''' Implements 128bit murmur3 hash for x64. '''
101 |
102 | def fmix( k ):
103 | k ^= k >> 33
104 | k = ( k * 0xff51afd7ed558ccd ) & 0xFFFFFFFFFFFFFFFF
105 | k ^= k >> 33
106 | k = ( k * 0xc4ceb9fe1a85ec53 ) & 0xFFFFFFFFFFFFFFFF
107 | k ^= k >> 33
108 | return k
109 |
110 | length = len( key )
111 | nblocks = int( length / 16 )
112 |
113 | h1 = seed
114 | h2 = seed
115 |
116 | c1 = 0x87c37b91114253d5
117 | c2 = 0x4cf5ad432745937f
118 |
119 | #body
120 | for block_start in range( 0, nblocks * 8, 8 ):
121 | # ??? big endian?
122 | k1 = key[ 2 * block_start + 7 ] << 56 | \
123 | key[ 2 * block_start + 6 ] << 48 | \
124 | key[ 2 * block_start + 5 ] << 40 | \
125 | key[ 2 * block_start + 4 ] << 32 | \
126 | key[ 2 * block_start + 3 ] << 24 | \
127 | key[ 2 * block_start + 2 ] << 16 | \
128 | key[ 2 * block_start + 1 ] << 8 | \
129 | key[ 2 * block_start + 0 ]
130 |
131 | k2 = key[ 2 * block_start + 15 ] << 56 | \
132 | key[ 2 * block_start + 14 ] << 48 | \
133 | key[ 2 * block_start + 13 ] << 40 | \
134 | key[ 2 * block_start + 12 ] << 32 | \
135 | key[ 2 * block_start + 11 ] << 24 | \
136 | key[ 2 * block_start + 10 ] << 16 | \
137 | key[ 2 * block_start + 9 ] << 8 | \
138 | key[ 2 * block_start + 8 ]
139 |
140 | k1 = ( c1 * k1 ) & 0xFFFFFFFFFFFFFFFF
141 | k1 = ( k1 << 31 | k1 >> 33 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64
142 | k1 = ( c2 * k1 ) & 0xFFFFFFFFFFFFFFFF
143 | h1 ^= k1
144 |
145 | h1 = ( h1 << 27 | h1 >> 37 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64
146 | h1 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF
147 | h1 = ( h1 * 5 + 0x52dce729 ) & 0xFFFFFFFFFFFFFFFF
148 |
149 | k2 = ( c2 * k2 ) & 0xFFFFFFFFFFFFFFFF
150 | k2 = ( k2 << 33 | k2 >> 31 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64
151 | k2 = ( c1 * k2 ) & 0xFFFFFFFFFFFFFFFF
152 | h2 ^= k2
153 |
154 | h2 = ( h2 << 31 | h2 >> 33 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64
155 | h2 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF
156 | h2 = ( h2 * 5 + 0x38495ab5 ) & 0xFFFFFFFFFFFFFFFF
157 |
158 | #tail
159 | tail_index = nblocks * 16
160 | k1 = 0
161 | k2 = 0
162 | tail_size = length & 15
163 |
164 | if tail_size >= 15:
165 | k2 ^= key[ tail_index + 14 ] << 48
166 | if tail_size >= 14:
167 | k2 ^= key[ tail_index + 13 ] << 40
168 | if tail_size >= 13:
169 | k2 ^= key[ tail_index + 12 ] << 32
170 | if tail_size >= 12:
171 | k2 ^= key[ tail_index + 11 ] << 24
172 | if tail_size >= 11:
173 | k2 ^= key[ tail_index + 10 ] << 16
174 | if tail_size >= 10:
175 | k2 ^= key[ tail_index + 9 ] << 8
176 | if tail_size >= 9:
177 | k2 ^= key[ tail_index + 8 ]
178 |
179 | if tail_size > 8:
180 | k2 = ( k2 * c2 ) & 0xFFFFFFFFFFFFFFFF
181 | k2 = ( k2 << 33 | k2 >> 31 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64
182 | k2 = ( k2 * c1 ) & 0xFFFFFFFFFFFFFFFF
183 | h2 ^= k2
184 |
185 | if tail_size >= 8:
186 | k1 ^= key[ tail_index + 7 ] << 56
187 | if tail_size >= 7:
188 | k1 ^= key[ tail_index + 6 ] << 48
189 | if tail_size >= 6:
190 | k1 ^= key[ tail_index + 5 ] << 40
191 | if tail_size >= 5:
192 | k1 ^= key[ tail_index + 4 ] << 32
193 | if tail_size >= 4:
194 | k1 ^= key[ tail_index + 3 ] << 24
195 | if tail_size >= 3:
196 | k1 ^= key[ tail_index + 2 ] << 16
197 | if tail_size >= 2:
198 | k1 ^= key[ tail_index + 1 ] << 8
199 | if tail_size >= 1:
200 | k1 ^= key[ tail_index + 0 ]
201 |
202 | if tail_size > 0:
203 | k1 = ( k1 * c1 ) & 0xFFFFFFFFFFFFFFFF
204 | k1 = ( k1 << 31 | k1 >> 33 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64
205 | k1 = ( k1 * c2 ) & 0xFFFFFFFFFFFFFFFF
206 | h1 ^= k1
207 |
208 | #finalization
209 | h1 ^= length
210 | h2 ^= length
211 |
212 | h1 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF
213 | h2 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF
214 |
215 | h1 = fmix( h1 )
216 | h2 = fmix( h2 )
217 |
218 | h1 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF
219 | h2 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF
220 |
221 | return ( h2 << 64 | h1 )
222 |
223 | def hash128_x86( key, seed ):
224 | ''' Implements 128bit murmur3 hash for x86. '''
225 |
226 | def fmix( h ):
227 | h ^= h >> 16
228 | h = ( h * 0x85ebca6b ) & 0xFFFFFFFF
229 | h ^= h >> 13
230 | h = ( h * 0xc2b2ae35 ) & 0xFFFFFFFF
231 | h ^= h >> 16
232 | return h
233 |
234 | length = len( key )
235 | nblocks = int( length / 16 )
236 |
237 | h1 = seed
238 | h2 = seed
239 | h3 = seed
240 | h4 = seed
241 |
242 | c1 = 0x239b961b
243 | c2 = 0xab0e9789
244 | c3 = 0x38b34ae5
245 | c4 = 0xa1e38b93
246 |
247 | #body
248 | for block_start in range( 0, nblocks * 16, 16 ):
249 | k1 = key[ block_start + 3 ] << 24 | \
250 | key[ block_start + 2 ] << 16 | \
251 | key[ block_start + 1 ] << 8 | \
252 | key[ block_start + 0 ]
253 |
254 | k2 = key[ block_start + 7 ] << 24 | \
255 | key[ block_start + 6 ] << 16 | \
256 | key[ block_start + 5 ] << 8 | \
257 | key[ block_start + 4 ]
258 |
259 | k3 = key[ block_start + 11 ] << 24 | \
260 | key[ block_start + 10 ] << 16 | \
261 | key[ block_start + 9 ] << 8 | \
262 | key[ block_start + 8 ]
263 |
264 | k4 = key[ block_start + 15 ] << 24 | \
265 | key[ block_start + 14 ] << 16 | \
266 | key[ block_start + 13 ] << 8 | \
267 | key[ block_start + 12 ]
268 |
269 | k1 = ( c1 * k1 ) & 0xFFFFFFFF
270 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32
271 | k1 = ( c2 * k1 ) & 0xFFFFFFFF
272 | h1 ^= k1
273 |
274 | h1 = ( h1 << 19 | h1 >> 13 ) & 0xFFFFFFFF # inlined ROTL32
275 | h1 = ( h1 + h2 ) & 0xFFFFFFFF
276 | h1 = ( h1 * 5 + 0x561ccd1b ) & 0xFFFFFFFF
277 |
278 | k2 = ( c2 * k2 ) & 0xFFFFFFFF
279 | k2 = ( k2 << 16 | k2 >> 16 ) & 0xFFFFFFFF # inlined ROTL32
280 | k2 = ( c3 * k2 ) & 0xFFFFFFFF
281 | h2 ^= k2
282 |
283 | h2 = ( h2 << 17 | h2 >> 15 ) & 0xFFFFFFFF # inlined ROTL32
284 | h2 = ( h2 + h3 ) & 0xFFFFFFFF
285 | h2 = ( h2 * 5 + 0x0bcaa747 ) & 0xFFFFFFFF
286 |
287 | k3 = ( c3 * k3 ) & 0xFFFFFFFF
288 | k3 = ( k3 << 17 | k3 >> 15 ) & 0xFFFFFFFF # inlined ROTL32
289 | k3 = ( c4 * k3 ) & 0xFFFFFFFF
290 | h3 ^= k3
291 |
292 | h3 = ( h3 << 15 | h3 >> 17 ) & 0xFFFFFFFF # inlined ROTL32
293 | h3 = ( h3 + h4 ) & 0xFFFFFFFF
294 | h3 = ( h3 * 5 + 0x96cd1c35 ) & 0xFFFFFFFF
295 |
296 | k4 = ( c4 * k4 ) & 0xFFFFFFFF
297 | k4 = ( k4 << 18 | k4 >> 14 ) & 0xFFFFFFFF # inlined ROTL32
298 | k4 = ( c1 * k4 ) & 0xFFFFFFFF
299 | h4 ^= k4
300 |
301 | h4 = ( h4 << 13 | h4 >> 19 ) & 0xFFFFFFFF # inlined ROTL32
302 | h4 = ( h1 + h4 ) & 0xFFFFFFFF
303 | h4 = ( h4 * 5 + 0x32ac3b17 ) & 0xFFFFFFFF
304 |
305 | #tail
306 | tail_index = nblocks * 16
307 | k1 = 0
308 | k2 = 0
309 | k3 = 0
310 | k4 = 0
311 | tail_size = length & 15
312 |
313 | if tail_size >= 15:
314 | k4 ^= key[ tail_index + 14 ] << 16
315 | if tail_size >= 14:
316 | k4 ^= key[ tail_index + 13 ] << 8
317 | if tail_size >= 13:
318 | k4 ^= key[ tail_index + 12 ]
319 |
320 | if tail_size > 12:
321 | k4 = ( k4 * c4 ) & 0xFFFFFFFF
322 | k4 = ( k4 << 18 | k4 >> 14 ) & 0xFFFFFFFF # inlined ROTL32
323 | k4 = ( k4 * c1 ) & 0xFFFFFFFF
324 | h4 ^= k4
325 |
326 | if tail_size >= 12:
327 | k3 ^= key[ tail_index + 11 ] << 24
328 | if tail_size >= 11:
329 | k3 ^= key[ tail_index + 10 ] << 16
330 | if tail_size >= 10:
331 | k3 ^= key[ tail_index + 9 ] << 8
332 | if tail_size >= 9:
333 | k3 ^= key[ tail_index + 8 ]
334 |
335 | if tail_size > 8:
336 | k3 = ( k3 * c3 ) & 0xFFFFFFFF
337 | k3 = ( k3 << 17 | k3 >> 15 ) & 0xFFFFFFFF # inlined ROTL32
338 | k3 = ( k3 * c4 ) & 0xFFFFFFFF
339 | h3 ^= k3
340 |
341 | if tail_size >= 8:
342 | k2 ^= key[ tail_index + 7 ] << 24
343 | if tail_size >= 7:
344 | k2 ^= key[ tail_index + 6 ] << 16
345 | if tail_size >= 6:
346 | k2 ^= key[ tail_index + 5 ] << 8
347 | if tail_size >= 5:
348 | k2 ^= key[ tail_index + 4 ]
349 |
350 | if tail_size > 4:
351 | k2 = ( k2 * c2 ) & 0xFFFFFFFF
352 | k2 = ( k2 << 16 | k2 >> 16 ) & 0xFFFFFFFF # inlined ROTL32
353 | k2 = ( k2 * c3 ) & 0xFFFFFFFF
354 | h2 ^= k2
355 |
356 | if tail_size >= 4:
357 | k1 ^= key[ tail_index + 3 ] << 24
358 | if tail_size >= 3:
359 | k1 ^= key[ tail_index + 2 ] << 16
360 | if tail_size >= 2:
361 | k1 ^= key[ tail_index + 1 ] << 8
362 | if tail_size >= 1:
363 | k1 ^= key[ tail_index + 0 ]
364 |
365 | if tail_size > 0:
366 | k1 = ( k1 * c1 ) & 0xFFFFFFFF
367 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32
368 | k1 = ( k1 * c2 ) & 0xFFFFFFFF
369 | h1 ^= k1
370 |
371 | #finalization
372 | h1 ^= length
373 | h2 ^= length
374 | h3 ^= length
375 | h4 ^= length
376 |
377 | h1 = ( h1 + h2 ) & 0xFFFFFFFF
378 | h1 = ( h1 + h3 ) & 0xFFFFFFFF
379 | h1 = ( h1 + h4 ) & 0xFFFFFFFF
380 | h2 = ( h1 + h2 ) & 0xFFFFFFFF
381 | h3 = ( h1 + h3 ) & 0xFFFFFFFF
382 | h4 = ( h1 + h4 ) & 0xFFFFFFFF
383 |
384 | h1 = fmix( h1 )
385 | h2 = fmix( h2 )
386 | h3 = fmix( h3 )
387 | h4 = fmix( h4 )
388 |
389 | h1 = ( h1 + h2 ) & 0xFFFFFFFF
390 | h1 = ( h1 + h3 ) & 0xFFFFFFFF
391 | h1 = ( h1 + h4 ) & 0xFFFFFFFF
392 | h2 = ( h1 + h2 ) & 0xFFFFFFFF
393 | h3 = ( h1 + h3 ) & 0xFFFFFFFF
394 | h4 = ( h1 + h4 ) & 0xFFFFFFFF
395 |
396 | return ( h4 << 96 | h3 << 64 | h2 << 32 | h1 )
397 |
398 | key = bytearray( xencode(key) )
399 |
400 | if x64arch:
401 | return hash128_x64( key, seed )
402 | else:
403 | return hash128_x86( key, seed )
404 |
405 |
406 | def hash64( key, seed = 0x0, x64arch = True ):
407 | ''' Implements 64bit murmur3 hash. Returns a tuple. '''
408 |
409 | hash_128 = hash128( key, seed, x64arch )
410 |
411 | unsigned_val1 = hash_128 & 0xFFFFFFFFFFFFFFFF
412 | if unsigned_val1 & 0x8000000000000000 == 0:
413 | signed_val1 = unsigned_val1
414 | else:
415 | signed_val1 = -( (unsigned_val1 ^ 0xFFFFFFFFFFFFFFFF) + 1 )
416 |
417 | unsigned_val2 = ( hash_128 >> 64 ) & 0xFFFFFFFFFFFFFFFF
418 | if unsigned_val2 & 0x8000000000000000 == 0:
419 | signed_val2 = unsigned_val2
420 | else:
421 | signed_val2 = -( (unsigned_val2 ^ 0xFFFFFFFFFFFFFFFF) + 1 )
422 |
423 | return ( int( signed_val1 ), int( signed_val2 ) )
424 |
425 |
426 | def hash_bytes( key, seed = 0x0, x64arch = True ):
427 | ''' Implements 128bit murmur3 hash. Returns a byte string. '''
428 |
429 | hash_128 = hash128( key, seed, x64arch )
430 |
431 | bytestring = ''
432 |
433 | for i in range(0, 16, 1):
434 | lsbyte = hash_128 & 0xFF
435 | bytestring = bytestring + str( chr( lsbyte ) )
436 | hash_128 = hash_128 >> 8
437 |
438 | return bytestring
439 |
440 |
441 | if __name__ == "__main__":
442 | import argparse
443 |
444 | parser = argparse.ArgumentParser( 'pymurmur3', 'pymurmur [options] "string to hash"' )
445 | parser.add_argument( '--seed', type = int, default = 0 )
446 | parser.add_argument( 'strings', default = [], nargs='+')
447 |
448 | opts = parser.parse_args()
449 |
450 | for str_to_hash in opts.strings:
451 | sys.stdout.write( '"%s" = 0x%08X\n' % ( str_to_hash, hash( str_to_hash ) ) )
452 |
--------------------------------------------------------------------------------
/sample_images/bunny_CryptoAsset.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/bunny_CryptoAsset.exr
--------------------------------------------------------------------------------
/sample_images/bunny_CryptoMaterial.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/bunny_CryptoMaterial.exr
--------------------------------------------------------------------------------
/sample_images/bunny_CryptoObject.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/bunny_CryptoObject.exr
--------------------------------------------------------------------------------
/sample_images/cornellBox_CryptoWildcard.0001.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/cornellBox_CryptoWildcard.0001.exr
--------------------------------------------------------------------------------
/sample_images/cornellBox_CryptoWildcard.0002.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/cornellBox_CryptoWildcard.0002.exr
--------------------------------------------------------------------------------
/sample_images/debug_images/about.md:
--------------------------------------------------------------------------------
1 | These are small, low resolution images for testing features of Cryptomatte.
2 |
3 | * multichannel.exr: Contains three cryptomattes.
4 | * sidecar_manifest.exr: Has a sidecar manifest.
5 | * special_chars.exr: Contains UTF-8 characters, as well as spaces, quotes, and commas.
6 |
7 |
--------------------------------------------------------------------------------
/sample_images/debug_images/multichannel.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/debug_images/multichannel.exr
--------------------------------------------------------------------------------
/sample_images/debug_images/sidecar_manifest.crypto_asset.json:
--------------------------------------------------------------------------------
1 | {"default":"42c9679f","default_111":"ad58c73a","default_222":"24c0148d","default_333":"64fdaf51","default_444":"8ca57ad9","default_555":"56c1f4ca","leftAsset":"ce406a47","rightAsset":"8f3ccbde"}
--------------------------------------------------------------------------------
/sample_images/debug_images/sidecar_manifest.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/debug_images/sidecar_manifest.exr
--------------------------------------------------------------------------------
/sample_images/debug_images/special_chars.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/debug_images/special_chars.exr
--------------------------------------------------------------------------------
/sample_images/sidecar_manifest/bunny_CryptoObject.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/sidecar_manifest/bunny_CryptoObject.exr
--------------------------------------------------------------------------------
/sample_images/testGrid_CryptoObject.exr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/sample_images/testGrid_CryptoObject.exr
--------------------------------------------------------------------------------
/specification/IDmattes_poster.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/specification/IDmattes_poster.pdf
--------------------------------------------------------------------------------
/specification/cryptomatte_specification.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Psyop/Cryptomatte/968d5e4b6171e29ba5f89d554117132a164e747e/specification/cryptomatte_specification.pdf
--------------------------------------------------------------------------------