Skip to content

Commit

Permalink
0.9.0 address initial feedback from 0.8.0 (#5)
Browse files Browse the repository at this point in the history
- add GradeBeautyLayer plugin
- GradeBeauty.cpp : add black clamping
- GradeBeauty.cpp : refactor and make sure hidden knobs are correctly set at script open or copy
- enhance nuke plugin menu and made menu.py more explicit
- turn on target layers in case the user create a new layer
- refactored grade type plugin code to avoid duplication
- Grade type nodes : revise precomputeValues function and black outside handling
- ConfigTester: updated to user argparse, can disable terminal printing (disabled on nuke startup)
- documentation popup for nuke nodes removed from callbacks and is now QT, if possible (fallback to web browser for Nuke 11)
- refine the autolabel function
- add mask indicators
- add github PR template
- PR comment : move documentation/help functions to separate module
  • Loading branch information
sebjacob authored Jan 22, 2020
1 parent 990de01 commit 0cd92de
Show file tree
Hide file tree
Showing 30 changed files with 843 additions and 401 deletions.
24 changes: 24 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## Description

Explain what, why and the though process leading to the changes

link to issue if relevant.

### code changes
- point form description of changes

## Type of change

is this a major or a minor or patch update ?

## How Has This Been Tested?

Describe operating system and Nuke versions

## Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
4 changes: 2 additions & 2 deletions documentation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ add_custom_target(documentation ALL
add_custom_target(documentation_package
DEPENDS documentation
COMMENT "creating documentation package for ${PROJECT_PACKAGE_NAME}"
COMMAND ${CMAKE_COMMAND} -E tar "cfvz" "${PROJECT_NAME}-${LAYER_ALCHEMY_VERSION_STRING}_documentation.tgz" "${CMAKE_CURRENT_BINARY_DIR}/documentation"
COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_NAME}-${LAYER_ALCHEMY_VERSION_STRING}_documentation.tgz" "../"
COMMAND ${CMAKE_COMMAND} -E tar "cfvz" "${PROJECT_NAME}-${LAYER_ALCHEMY_VERSION_STRING}_documentation.tar.gz" "${CMAKE_CURRENT_BINARY_DIR}/documentation"
COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_NAME}-${LAYER_ALCHEMY_VERSION_STRING}_documentation.tar.gz" "../"
)

install(
Expand Down
22 changes: 19 additions & 3 deletions documentation/docs/GradeBeauty.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

Lighters can use it with the light_group [LayerSet](core.md#layersets) to :

* Tweak light group values and animations, (flicker matching)
* Use two nodes, one in _multiply_ mode, and one in _stops_ mode to adhere to the exposure/gain decoupling
* Tweak light group values or animations, (flicker matching)
* Use two nodes, one in _multiply_ mode, and one in _stops_ mode to mimic to the exposure/gain decoupling
* Send the values back to their cg application !

Compositors:
Expand All @@ -42,6 +42,7 @@ Compositors:
| target_layer | enumeration | selects which layer to pre-subtract layers from (if enabled) and add the modified layers to |
| math_type | enumeration | selects the color knob preference
| subtract | bool | controls pre-subtracting the [LayerSet](core.md#layersets) from the target layer |
| black_clamp | bool | clamp negative values from all output layers |
| reset values | button | resets all color knobs to their defaults |

## [PixelIop](https://learn.foundry.com/nuke/developers/11.3/ndkdevguide/2d/pixeliops.html) Knobs
Expand All @@ -61,7 +62,7 @@ Compositors:

### subtract
The purpose of the subtract knob is to make sure that the output will always match the beauty render, even if
some layers are missing, yet included in the beauty render.
some aov layers are missing in the beauty render.

This can happen, so it is enabled by default.

Expand All @@ -70,9 +71,24 @@ This can happen, so it is enabled by default.
| enabled | the additive sum of the chosen [LayerSet](core.md#layersets) is subtracted from the target layer before recombining with this node's modifications | <p><i>this means any difference between the target layer and the render layers is kept in the final output</i></p>
| disabled | bypasses aov/target layer pre-subtraction | _when this is disabled, it replaces the target layer with the result_

!!! info ""

If enabled and you completely remove layers, it's possible that you get negative values when
completely removing aovs AND subtracting. In this scenario, enable black_clamp

### black_clamp
The purpose of the black_clamp knob is to make sure that the output pixels always are alaways positive.

| value | what it does | notes |
| ----- | ------------ | ----- |
| enabled | no negative values are passed to the output | <p><i>in the odd case that you need to stop negative values this will do the job</i></p>
| disabled | bypasses aov/target layer negative clamping |


## Arnold 5 LayerSets

LayerAlchemy includes arnold configurations by default

Arnold can separate the beauty render components in various ways.

The following type are natively supported with the [default](https://docs.arnoldrenderer.com/display/A5AFMUG/AOVs#AOVs-AOVs) aov naming :
Expand Down
22 changes: 22 additions & 0 deletions documentation/docs/GradeBeautyLayer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# GradeBeautyLayer

!!! info ""

GradeBeautyLayer provides a simple way to specifically grade a cg layer and replace it in the beauty
#### Order of operations :
- input layer subtracted from the target layer
- layer is modified
- modified source layer is added to the target layer


![GradeBeautyLayer](media/parameters/GradeBeautyLayer.png)

## Knob reference

| knob name | type | what it does |
| --------- | ---- | ------------
| source_layer | enumeration | layer to to grade |
| target_layer | enumeration | layer to subtract and add the modied source_layer to |
| reset values | button | resets all color knobs to their defaults |

7 changes: 1 addition & 6 deletions documentation/docs/GradeBeautyLayerSet.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@
GradeBeautyLayerSet provides a simple way to specifically grade multiple cg layers using a [LayerSet](core
.md#layersets)

it's a cross between :

- [GradeLayerSet](GradeLayerSet.md)
- [GradeBeauty](GradeBeauty.md)
- [FlattenLayerSet](FlattenLayerSet.md)


Image processing math is exactly like the Nuke Grade node except that, you can grade multiple layers at the
Expand All @@ -30,5 +25,5 @@ same time

| mode name | what it does |
| --------- | ------------ |
| copy | outputs only the addition of modified layers to the target layer |
| copy | outputs only the modified layers to the target layer (added together)|
| add | this first subtracts all layers from the target layer, then adds each of them back
9 changes: 6 additions & 3 deletions documentation/docs/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
| ---- | ---- | ----- | -------- |
| Sébastien Jacob | author, designer | [email](mailto:[email protected]) | [LinkedIn](https://www.linkedin.com/in/s%C3%A9bastien-jacob-3b05112/)

!!! info "special thanks 👍, for their help in kick starting the very first builds goes to :"
# special thanks 👍

- Jean-Christophe Morin
- Gregory Starck
- Charles Fleche
- Christian Morin
- Mathieu Dupuis
- Jean-Christophe Morin
- Gregory Starck

# Contributing

Expand Down
5 changes: 2 additions & 3 deletions documentation/docs/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ as they will will be referenced throughout the documentation

- limited mostly by the callback system to trigger behaviors.
- cannot be cloned in Nuke.
- internally, the algorithm is spread out across multiple nodes that must be managed.
- lots of knob setting python code, and workarounds are required.
- no direct image processing possible.
- internally, the algorithm is spread out across multiple Nuke nodes that must be managed.
- lots python and expression code, workarounds are required.
- some knobs are c++ only.
- In general, the fewer the nodes, the faster the comp.

Expand Down
Binary file modified documentation/docs/media/parameters/GradeBeauty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified documentation/docs/media/parameters/GradeBeauty_uncollapsed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 13 additions & 3 deletions documentation/docs/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@ This also runs at Nuke startup to make sure the config files are ok

ConfigTester 😷

Simple executable to test if a yaml file can be loaded and a LayerMap object can be constructed
Simple executable to validate yaml files

LayerAlchemy 0.9.0
https://github.com/sebjacob/LayerAlchemy

Example usage: ConfigTester /path/to/config.yaml
Example usage:

ConfigTester --config /path/to/config.yaml
ConfigTester --config /path/to/config1.yaml /path/to/config2.yaml
Usage: ./ConfigTester [options]
Options:
--config List of layer names to test (Required)
--quiet disable terminal output, return code only
```

```bash
./ConfigTester $LAYER_ALCHEMY_LAYER_CONFIG
./ConfigTester --config $LAYER_ALCHEMY_LAYER_CONFIG
✅ LayerAlchemy : valid configuration file /path/to/layers.yaml
```

Expand Down
1 change: 1 addition & 0 deletions documentation/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ nav :
- Nuke plugins :
- GradeBeauty.md
- GradeBeautyLayerSet.md
- GradeBeautyLayer.md
- GradeLayerSet.md
- FlattenLayerSet.md
- RemoveLayerSet.md
Expand Down
Binary file added icons/GradeBeautyLayer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions include/nuke/LayerSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ namespace LayerSet {
namespace Utilities {
void hard_copy(const DD::Image::Row& fromRow, int x, int r, DD::Image::ChannelSet channels, DD::Image::Row& toRow);
float* hard_copy(const DD::Image::Row& fromRow, int x, int r, DD::Image::Channel channel, DD::Image::Row& toRow);
// centralized pixel engine code for Grade type plugins
void gradeChannelPixelEngine(const DD::Image::Row& in, int y, int x, int r, DD::Image::ChannelSet& channels, DD::Image::Row& aRow, float* A, float* B, float* G, bool reverse, bool clampBlack, bool clampWhite);
// use to validate if a target layer the user selects is within the required color ranges
void validateTargetLayerColorIndex(DD::Image::Op* t_op, const DD::Image::ChannelSet& targetLayer, unsigned minIndex, unsigned maxIndex);
// test float value for pow functions, NDK states that linux behaves badly for very large or very small exponent values.
float validateGammaValue(const float& gammaValue);
} // End namespace Utilities

namespace Knobs {
Expand Down
2 changes: 1 addition & 1 deletion include/version.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once
#define LAYER_ALCHEMY_VERSION_MAJOR 0
#define LAYER_ALCHEMY_VERSION_MINOR 8
#define LAYER_ALCHEMY_VERSION_MINOR 9
#define LAYER_ALCHEMY_VERSION_PATCH 0

#include <string>
Expand Down
1 change: 1 addition & 0 deletions python/nuke/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
import layer_alchemy.callbacks

if layer_alchemy.utilities.nukeVersionCompatible():
layer_alchemy.utilities.validateConfigFileEnvironmentVariables()
layer_alchemy.utilities.pluginAddPaths()
layer_alchemy.callbacks.setupCallbacks()
57 changes: 20 additions & 37 deletions python/nuke/layer_alchemy/callbacks.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,41 @@
"""LayerAlchemy callback module"""

import os

import nuke
import nukescripts

import utilities
import constants


def setupCallbacks():
"""
Utility function to add all callbacks for plugins in this suite.
Adds knobChanged and autolabel callbacks
"""
for pluginName in constants.LAYER_ALCHEMY_PLUGINS.keys():
nuke.addKnobChanged(
lambda: knobChangedCommon(nuke.thisNode(), nuke.thisKnob()),
nodeClass=pluginName
)
nuke.addAutolabel(autolabel, nodeClass=pluginName)
for pluginName in constants.LAYER_ALCHEMY_PLUGIN_NAMES:
nuke.addAutolabel(_autolabel, nodeClass=pluginName)
pass


def knobChangedCommon(node, knob):
"""
Common knobChanged function for plugins in this suite
:param node: the Nuke node object
:type node: :class:`nuke.Node`
:param knob: the Nuke knob object
:type knob: :class:`nuke.Knob`
"""
if knob.name() == 'docButton':
documentationIndex = utilities.getDocumentationIndexPath()
if not documentationIndex:
message = 'Local documentation is unavailable, please visit :\n\n<i>{website}</i>'.format(
website=constants.LAYER_ALCHEMY_URL)
nuke.message(message)
return
pluginDocFileName = '{0}.{1}'.format(node.Class(), 'html')
htmlFile = os.path.join(os.path.dirname(documentationIndex), pluginDocFileName)
outputPath = htmlFile if os.path.isfile(htmlFile) else documentationIndex
nukescripts.start(outputPath)


def autolabel():
def _autolabel():
"""
Common autolabel function for plugins in this suite
:return: the formatted text to use as a label
:rtype: str
"""

node = nuke.thisNode()
nodeName = node.name()
layerSetKnob = node.knob('layer_set')
index = int(layerSetKnob.getValue())
layerSetName = layerSetKnob.enumName(index)
text = []
for knobName in ('layer_set', 'channels', 'maskChannelInput', 'unpremult'):
knob = node.knob(knobName)
if knob:
index = int(knob.getValue())
value = knob.enumName(index) if isinstance(knob, nuke.Enumeration_Knob) else knob.value()
if value and value != 'none':
text.append(value)

node.knob('indicators').setValue(_getIndicatorValue(node))
if layerSetName:
return '{name}\n({layerSet})'.format(name=nodeName, layerSet=layerSetName)
if text:
return '{name}\n({layers})'.format(name=nodeName, layers=' / '.join(text))
else:
return nodeName

Expand All @@ -71,8 +51,11 @@ def _getIndicatorValue(node):
indicators = 0
knobs = node.allKnobs()
mixKnob = node.knob('mix')
maskKnob = node.knob('maskChannelInput')
if mixKnob and mixKnob.value() != 1:
indicators += 16
if maskKnob and maskKnob.getValue() != 0:
indicators += 4
if node.clones():
indicators += 8
if any(knob.isAnimated() for knob in knobs):
Expand Down
21 changes: 11 additions & 10 deletions python/nuke/layer_alchemy/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@

import os

LAYER_ALCHEMY_PLUGINS = { # The name of the plugin and its icon name
'GradeBeauty': 'GradeBeauty.png',
'GradeBeautyLayerSet': 'GradeBeautyLayerSet.png',
'FlattenLayerSet': 'FlattenLayerSet.png',
'RemoveLayerSet': 'RemoveLayerSet.png',
'MultiplyLayerSet': 'MultiplyLayerSet.png',
'GradeLayerSet': 'GradeLayerSet.png',
}
LAYER_ALCHEMY_URL = 'https://github.com/sebjacob/LayerAlchemy'

LAYER_ALCHEMY_PLUGIN_NAMES = [
'GradeBeauty',
'GradeBeautyLayerSet',
'GradeBeautyLayer',
'GradeLayerSet',
'MultiplyLayerSet',
'RemoveLayerSet',
'FlattenLayerSet'
]

LAYER_ALCHEMY_CONFIGS_DICT = {
'LAYER_ALCHEMY_LAYER_CONFIG': 'layers.yaml',
'LAYER_ALCHEMY_CHANNEL_CONFIG': 'channels.yaml'
}

LAYER_ALCHEMY_URL = 'https://github.com/sebjacob/LayerAlchemy'

_thisDir = os.path.dirname(os.path.realpath(__file__))
_layerAlchemyNukeDir = os.path.abspath(os.path.join(_thisDir, '..'))

Expand Down
Loading

0 comments on commit 0cd92de

Please sign in to comment.