Skip to content

Commit

Permalink
Add shader display adjustments to MM ImagePlane.
Browse files Browse the repository at this point in the history
Adds new features and replaces the old Maya-shader shader node approach.

The shader node was removed from the image plane.
This change is not backwards compatible with previous mmSolver releases
:(

New display shader features:
- Color Gain as RGB colour, not just float.
- Exposure adjustment.
- Gamma adjustment.
- Saturation adjustment.
- Soft-clip adjustment.
- Saturation Image Channel mode.

GitHub issue #254.
  • Loading branch information
david-cattermole committed Jun 27, 2024
1 parent 9881dbc commit 6e334e5
Show file tree
Hide file tree
Showing 11 changed files with 653 additions and 564 deletions.
72 changes: 46 additions & 26 deletions mel/AETemplates/AEmmImagePlaneShapeTemplate.mel
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (C) 2022 David Cattermole.
// Copyright (C) 2022, 2024 David Cattermole.
//
// This file is part of mmSolver.
//
Expand Down Expand Up @@ -97,11 +97,14 @@ global proc AEmmImagePlaneShape_browser(
string $cmd = "";
$cmd = $cmd + "import mmSolver.tools.createimageplane.tool as tool;\n";
$cmd = $cmd + "import mmSolver.tools.createimageplane.lib as lib;\n";
$cmd = $cmd + "\n";
$cmd = $cmd + "image_seq = tool.prompt_user_for_image_sequence();\n";
$cmd = $cmd + "\n";
$cmd = $cmd + "mm_ip_shp = \"" + $image_plane_shp + "\";\n";
$cmd = $cmd + "attr_name = \"" + $attr_name + "\";\n";
$cmd = $cmd + "current_slot_attr = \"" + $slot_attr_name + "\";\n";
$cmd = $cmd + "\n";
$cmd = $cmd + "if image_seq:\n";
$cmd = $cmd + " mm_ip_shp = \"" + $image_plane_shp + "\";\n";
$cmd = $cmd + " attr_name = \"" + $attr_name + "\";\n";
$cmd = $cmd + " current_slot_attr = \"" + $slot_attr_name + "\";\n";
$cmd = $cmd + " if attr_name == current_slot_attr:\n";
$cmd = $cmd + " lib.set_image_sequence(\n";
$cmd = $cmd + " mm_ip_shp,\n";
Expand Down Expand Up @@ -132,16 +135,18 @@ global proc AEmmImagePlaneShape_sequenceSlotChanged(
AEmmImagePlaneShape_setSlotValue($image_plane_shp, $slot_attr_value);

string $cmd = "";
$cmd = $cmd + "import os.path;\n";
$cmd = $cmd + "import mmSolver.tools.createimageplane.tool as tool;\n";
$cmd = $cmd + "import mmSolver.tools.createimageplane.lib as lib;\n";
$cmd = $cmd + "\n";
$cmd = $cmd + "mm_ip_shp = \"" + $image_plane_shp + "\";\n";
$cmd = $cmd + "attr_name = \"" + $attr_name + "\";\n";
$cmd = $cmd + "current_slot_attr = \"" + $slot_attr_name + "\";\n";
$cmd = $cmd + "\n";
$cmd = $cmd + "image_seq = maya.cmds.getAttr(\n";
$cmd = $cmd + " mm_ip_shp + '.' + current_slot_attr) or ''\n";
$cmd = $cmd + "if len(image_seq) == 0 or not os.path.isfile(image_seq):\n";
$cmd = $cmd + "if len(image_seq) == 0:\n";
$cmd = $cmd + " image_seq = lib.get_default_image_path();\n";
$cmd = $cmd + "\n";
$cmd = $cmd + "lib.set_image_sequence(\n";
$cmd = $cmd + " mm_ip_shp,\n";
$cmd = $cmd + " image_seq,\n";
Expand Down Expand Up @@ -233,12 +238,15 @@ global proc AEmmImagePlaneShapeTemplate(string $nodeName)
editorTemplate -beginLayout "Display" -collapse 0;
editorTemplate -addControl "visibleToCameraOnly";
editorTemplate -addSeparator;
editorTemplate -addControl "exposure";
editorTemplate -addControl "gamma";
editorTemplate -addControl "colorGain";
editorTemplate -addControl "colorExposure";
editorTemplate -addControl "colorGamma";
editorTemplate -addControl "colorSaturation";
editorTemplate -addControl "colorSoftClip";
editorTemplate -addControl "alphaGain";
// editorTemplate -addSeparator;
// editorTemplate -addControl "colorSpace"; // Might not be possible.
editorTemplate -addSeparator;
editorTemplate -addControl "imageIgnoreAlpha";
editorTemplate -addControl "displayChannel";
editorTemplate -endLayout;

editorTemplate -beginLayout "Image Sequence" -collapse 0;
Expand Down Expand Up @@ -270,6 +278,18 @@ global proc AEmmImagePlaneShapeTemplate(string $nodeName)
"AEmmImagePlaneShape_imageSequenceReplace"
"imageSequenceAlternate3";

editorTemplate -addSeparator;
editorTemplate -addControl "imageWidth";
editorTemplate -addControl "imageHeight";
editorTemplate -addControl "imagePixelAspect";
editorTemplate -addSeparator;
editorTemplate -addControl "imageSequenceStartFrame";
editorTemplate -addControl "imageSequenceEndFrame";
editorTemplate -addSeparator;
// TODO: Use mmColorIO results to allow users to manually give the
// inputColorSpace.
editorTemplate -addControl "inputColorSpace";
editorTemplate -addSeparator;
// TODO: Add radio button to choose what will connect to the
// 'imageSequenceFrame' value? Options are:
// - Scene Time (time1)
Expand All @@ -279,15 +299,8 @@ global proc AEmmImagePlaneShapeTemplate(string $nodeName)
editorTemplate -addControl "imageSequenceFirstFrame";
editorTemplate -addControl "imageSequenceFrameOutput";
editorTemplate -addSeparator;
editorTemplate -addControl "imageLoadEnable";
editorTemplate -addControl "imageUseAlphaChannel";
editorTemplate -addSeparator;
editorTemplate -addControl "imageWidth";
editorTemplate -addControl "imageHeight";
editorTemplate -addControl "imagePixelAspect";
editorTemplate -addSeparator;
editorTemplate -addControl "imageSequenceStartFrame";
editorTemplate -addControl "imageSequenceEndFrame";
editorTemplate -addControl "imageFlip";
editorTemplate -addControl "imageFlop";
editorTemplate -endLayout;

editorTemplate -beginLayout "HUD" -collapse 0;
Expand All @@ -298,24 +311,31 @@ global proc AEmmImagePlaneShapeTemplate(string $nodeName)
// TODO: Add 'hudTextColor' - control the HUD text color.
editorTemplate -endLayout;

// editorTemplate -beginLayout "Image Cache" -collapse 1;
// // TODO: Add controls to view and edit the image cache.
// editorTemplate -endLayout;

editorTemplate -beginLayout "Miscellaneous" -collapse 1;
editorTemplate -addControl "meshResolution";
editorTemplate -addControl "imageDefaultColor"; // Cannot be textured.
editorTemplate -addControl "shaderIsTransparent";
editorTemplate -endLayout;

editorTemplate -beginLayout "Nodes" -collapse 1;
editorTemplate -addControl "shaderNode";
editorTemplate -addControl "shaderFileNode";
editorTemplate -addControl "geometryNode";
editorTemplate -addControl "cameraNode";
editorTemplate -addControl "imagePlaneShapeNode";
editorTemplate -endLayout;

editorTemplate -suppress "imageSequencePadding";
editorTemplate -suppress "cameraWidthInch";
editorTemplate -suppress "cameraHeightInch";
editorTemplate -suppress "lensHashCurrent";
editorTemplate -suppress "lensHashPrevious";
// // Internals that we don't want the user to see.
// editorTemplate -suppress "imageSequencePadding";
// editorTemplate -suppress "cameraWidthInch";
// editorTemplate -suppress "cameraHeightInch";
// editorTemplate -suppress "lensHashCurrent";
// editorTemplate -suppress "lensHashPrevious";
// editorTemplate -suppress "imageFilePath";
// editorTemplate -suppress "inputColorSpace";
// editorTemplate -suppress "outputColorSpace";

AEmmNodeShapeTemplateCommonEnd($nodeName);
}
19 changes: 18 additions & 1 deletion python/mmSolver/tools/createimageplane/_lib/constant.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2022 David Cattermole.
# Copyright (C) 2022, 2024 David Cattermole.
#
# This file is part of mmSolver.
#
Expand All @@ -17,3 +17,20 @@
#

DEFAULT_IMAGE_SEQUENCE_ATTR_NAME = 'imageSequenceMain'
ALT_1_IMAGE_SEQUENCE_ATTR_NAME = 'imageSequenceAlternate1'
ALT_2_IMAGE_SEQUENCE_ATTR_NAME = 'imageSequenceAlternate2'
ALT_3_IMAGE_SEQUENCE_ATTR_NAME = 'imageSequenceAlternate3'

VALID_INPUT_IMAGE_SEQUENCE_ATTR_NAMES = [
DEFAULT_IMAGE_SEQUENCE_ATTR_NAME,
ALT_1_IMAGE_SEQUENCE_ATTR_NAME,
ALT_2_IMAGE_SEQUENCE_ATTR_NAME,
ALT_3_IMAGE_SEQUENCE_ATTR_NAME,
]

SHADER_FILE_PATH_ATTR_NAME = 'imageFilePath'
INPUT_COLOR_SPACE_ATTR_NAME = 'inputColorSpace'
OUTPUT_COLOR_SPACE_ATTR_NAME = 'outputColorSpace'

SCENE_LINEAR_FILE_EXTENSIONS = ['exr', 'sxr']
SRGB_FILE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'tif', 'tiff', 'tga', 'iff']
97 changes: 65 additions & 32 deletions python/mmSolver/tools/createimageplane/_lib/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2020, 2022 David Cattermole.
# Copyright (C) 2020, 2022, 2024 David Cattermole.
#
# This file is part of mmSolver.
#
Expand All @@ -25,12 +25,13 @@
import mmSolver.logger
import mmSolver.api as mmapi
import mmSolver.utils.camera as camera_utils
import mmSolver.utils.constant as const_utils
import mmSolver.utils.imageseq as imageseq_utils
import mmSolver.utils.python_compat as pycompat

import mmSolver.tools.createimageplane.constant as const
import mmSolver.tools.createimageplane._lib.constant as lib_const
import mmSolver.tools.createimageplane._lib.utilities as lib_utils
import mmSolver.tools.createimageplane._lib.shader as lib_shader
import mmSolver.tools.createimageplane._lib.mmimageplane as lib_mmimageplane
import mmSolver.tools.createimageplane._lib.polyplane as lib_polyplane
import mmSolver.tools.createimageplane._lib.nativeimageplane as lib_nativeimageplane
Expand All @@ -56,20 +57,18 @@ def create_image_plane_on_camera(cam, name=None):
poly_plane_name, mm_ip_tfm, cam_shp
)

name_shade = name + 'Shader'
shader_network = lib_shader.create_network(name_shade, mm_ip_tfm)

name_img_shp = name + 'Shape'
mm_ip_shp = lib_mmimageplane.create_shape_node(
name_img_shp, mm_ip_tfm, cam_shp, poly_plane_network, shader_network
)

# Shortcut connections to nodes.
lib_utils.force_connect_attr(
shader_network.file_node + '.message', mm_ip_tfm + '.shaderFileNode'
name_img_shp,
mm_ip_tfm,
cam_shp,
poly_plane_network,
)

# Logic to calculate the frame number.
#
# TODO: Move this expression into a Maya node, because expressions
# are buggy and not flexible.
frame_expr = const.FRAME_EXPRESSION.format(node=mm_ip_shp)
frame_expr = frame_expr.replace('{{', '{')
frame_expr = frame_expr.replace('}}', '}')
Expand All @@ -79,17 +78,6 @@ def create_image_plane_on_camera(cam, name=None):
shp_node_attr = mm_ip_shp + '.imageSequenceFrameOutput'
maya.cmds.setAttr(shp_node_attr, lock=True)

# Set useFrameExtension temporarily. Setting useFrameExtension to
# False causes frameOffset to be locked (but we need to edit it).
is_seq = maya.cmds.getAttr(shader_network.file_node + '.useFrameExtension')
maya.cmds.setAttr(shader_network.file_node + '.useFrameExtension', True)

file_node_attr = shader_network.file_node + '.frameExtension'
lib_utils.force_connect_attr(shp_node_attr, file_node_attr)
maya.cmds.setAttr(file_node_attr, lock=True)

maya.cmds.setAttr(shader_network.file_node + '.useFrameExtension', is_seq)

# Image sequence.
image_sequence_path = lib_utils.get_default_image_path()
set_image_sequence(mm_ip_tfm, image_sequence_path)
Expand Down Expand Up @@ -120,12 +108,12 @@ def convert_image_planes_on_camera(cam):

lib_nativeimageplane.copy_depth_value(mm_ip_tfm, native_ip_shp)

name_shader = name + 'Shader'
shader_network = lib_shader.create_network(name_shader, mm_ip_tfm)

name_img_shp = name + 'Shape'
mm_ip_shp = lib_mmimageplane.create_shape_node(
name_img_shp, mm_ip_tfm, cam_shp, poly_plane_network, shader_network
name_img_shp,
mm_ip_tfm,
cam_shp,
poly_plane_network,
)

# Disable/hide the Maya image plane.
Expand All @@ -138,20 +126,65 @@ def convert_image_planes_on_camera(cam):
return ip_node_pairs


def _guess_color_space(file_path):
file_extension = file_path.lower().split('.')[-1]
if file_extension in lib_const.SCENE_LINEAR_FILE_EXTENSIONS:
color_space = maya.cmds.mmColorIO(roleSceneLinear=True)
elif file_extension in lib_const.SRGB_FILE_EXTENSIONS:
color_space = maya.cmds.mmColorIO(roleColorPicking=True)
else:
color_space = maya.cmds.mmColorIO(guessColorSpaceFromFile=file_path)

if not color_space:
color_space = maya.cmds.mmColorIO(roleData=True)
if not color_space:
color_space = maya.cmds.mmColorIO(roleDefault=True)

exists = maya.cmds.mmColorIO(colorSpaceExists=color_space)
if exists is False:
color_space = None

return color_space


def set_image_sequence(mm_image_plane_node, image_sequence_path, attr_name=None):
if attr_name is None:
attr_name = lib_const.DEFAULT_IMAGE_SEQUENCE_ATTR_NAME
assert isinstance(attr_name, str)
assert attr_name in lib_const.VALID_INPUT_IMAGE_SEQUENCE_ATTR_NAMES

tfm, shp = lib_mmimageplane.get_image_plane_node_pair(mm_image_plane_node)
if tfm is None or shp is None:
LOG.warn('mmImagePlane transform/shape could not be found.')

file_node = lib_mmimageplane.get_file_node(tfm)
if file_node is None:
LOG.warn('mmImagePlane shader file node is invalid.')

if shp is not None:
lib_mmimageplane.set_image_sequence(shp, image_sequence_path, attr_name)
if file_node is not None:
lib_shader.set_file_path(file_node, image_sequence_path)
lib_mmimageplane.set_image_sequence(
shp, image_sequence_path, lib_const.SHADER_FILE_PATH_ATTR_NAME
)

format_style = const_utils.IMAGE_SEQ_FORMAT_STYLE_FIRST_FRAME
(
file_pattern,
_,
_,
_,
_,
) = imageseq_utils.expand_image_sequence_path(image_sequence_path, format_style)
first_frame_file_seq = file_pattern.replace('\\', '/')

input_color_space = _guess_color_space(first_frame_file_seq)
output_color_space = maya.cmds.mmColorIO(roleSceneLinear=True)

maya.cmds.setAttr(
shp + '.' + lib_const.INPUT_COLOR_SPACE_ATTR_NAME,
input_color_space,
type='string',
)
maya.cmds.setAttr(
shp + '.' + lib_const.OUTPUT_COLOR_SPACE_ATTR_NAME,
output_color_space,
type='string',
)

return
Loading

0 comments on commit 6e334e5

Please sign in to comment.