Skip to content

Commit e1cc593

Browse files
Add shader display adjustments to MM ImagePlane.
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.
1 parent 145a0e8 commit e1cc593

File tree

11 files changed

+653
-564
lines changed

11 files changed

+653
-564
lines changed

mel/AETemplates/AEmmImagePlaneShapeTemplate.mel

+46-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (C) 2022 David Cattermole.
2+
// Copyright (C) 2022, 2024 David Cattermole.
33
//
44
// This file is part of mmSolver.
55
//
@@ -97,11 +97,14 @@ global proc AEmmImagePlaneShape_browser(
9797
string $cmd = "";
9898
$cmd = $cmd + "import mmSolver.tools.createimageplane.tool as tool;\n";
9999
$cmd = $cmd + "import mmSolver.tools.createimageplane.lib as lib;\n";
100+
$cmd = $cmd + "\n";
100101
$cmd = $cmd + "image_seq = tool.prompt_user_for_image_sequence();\n";
102+
$cmd = $cmd + "\n";
103+
$cmd = $cmd + "mm_ip_shp = \"" + $image_plane_shp + "\";\n";
104+
$cmd = $cmd + "attr_name = \"" + $attr_name + "\";\n";
105+
$cmd = $cmd + "current_slot_attr = \"" + $slot_attr_name + "\";\n";
106+
$cmd = $cmd + "\n";
101107
$cmd = $cmd + "if image_seq:\n";
102-
$cmd = $cmd + " mm_ip_shp = \"" + $image_plane_shp + "\";\n";
103-
$cmd = $cmd + " attr_name = \"" + $attr_name + "\";\n";
104-
$cmd = $cmd + " current_slot_attr = \"" + $slot_attr_name + "\";\n";
105108
$cmd = $cmd + " if attr_name == current_slot_attr:\n";
106109
$cmd = $cmd + " lib.set_image_sequence(\n";
107110
$cmd = $cmd + " mm_ip_shp,\n";
@@ -132,16 +135,18 @@ global proc AEmmImagePlaneShape_sequenceSlotChanged(
132135
AEmmImagePlaneShape_setSlotValue($image_plane_shp, $slot_attr_value);
133136

134137
string $cmd = "";
135-
$cmd = $cmd + "import os.path;\n";
136138
$cmd = $cmd + "import mmSolver.tools.createimageplane.tool as tool;\n";
137139
$cmd = $cmd + "import mmSolver.tools.createimageplane.lib as lib;\n";
140+
$cmd = $cmd + "\n";
138141
$cmd = $cmd + "mm_ip_shp = \"" + $image_plane_shp + "\";\n";
139142
$cmd = $cmd + "attr_name = \"" + $attr_name + "\";\n";
140143
$cmd = $cmd + "current_slot_attr = \"" + $slot_attr_name + "\";\n";
144+
$cmd = $cmd + "\n";
141145
$cmd = $cmd + "image_seq = maya.cmds.getAttr(\n";
142146
$cmd = $cmd + " mm_ip_shp + '.' + current_slot_attr) or ''\n";
143-
$cmd = $cmd + "if len(image_seq) == 0 or not os.path.isfile(image_seq):\n";
147+
$cmd = $cmd + "if len(image_seq) == 0:\n";
144148
$cmd = $cmd + " image_seq = lib.get_default_image_path();\n";
149+
$cmd = $cmd + "\n";
145150
$cmd = $cmd + "lib.set_image_sequence(\n";
146151
$cmd = $cmd + " mm_ip_shp,\n";
147152
$cmd = $cmd + " image_seq,\n";
@@ -233,12 +238,15 @@ global proc AEmmImagePlaneShapeTemplate(string $nodeName)
233238
editorTemplate -beginLayout "Display" -collapse 0;
234239
editorTemplate -addControl "visibleToCameraOnly";
235240
editorTemplate -addSeparator;
236-
editorTemplate -addControl "exposure";
237-
editorTemplate -addControl "gamma";
238241
editorTemplate -addControl "colorGain";
242+
editorTemplate -addControl "colorExposure";
243+
editorTemplate -addControl "colorGamma";
244+
editorTemplate -addControl "colorSaturation";
245+
editorTemplate -addControl "colorSoftClip";
239246
editorTemplate -addControl "alphaGain";
240-
// editorTemplate -addSeparator;
241-
// editorTemplate -addControl "colorSpace"; // Might not be possible.
247+
editorTemplate -addSeparator;
248+
editorTemplate -addControl "imageIgnoreAlpha";
249+
editorTemplate -addControl "displayChannel";
242250
editorTemplate -endLayout;
243251

244252
editorTemplate -beginLayout "Image Sequence" -collapse 0;
@@ -270,6 +278,18 @@ global proc AEmmImagePlaneShapeTemplate(string $nodeName)
270278
"AEmmImagePlaneShape_imageSequenceReplace"
271279
"imageSequenceAlternate3";
272280

281+
editorTemplate -addSeparator;
282+
editorTemplate -addControl "imageWidth";
283+
editorTemplate -addControl "imageHeight";
284+
editorTemplate -addControl "imagePixelAspect";
285+
editorTemplate -addSeparator;
286+
editorTemplate -addControl "imageSequenceStartFrame";
287+
editorTemplate -addControl "imageSequenceEndFrame";
288+
editorTemplate -addSeparator;
289+
// TODO: Use mmColorIO results to allow users to manually give the
290+
// inputColorSpace.
291+
editorTemplate -addControl "inputColorSpace";
292+
editorTemplate -addSeparator;
273293
// TODO: Add radio button to choose what will connect to the
274294
// 'imageSequenceFrame' value? Options are:
275295
// - Scene Time (time1)
@@ -279,15 +299,8 @@ global proc AEmmImagePlaneShapeTemplate(string $nodeName)
279299
editorTemplate -addControl "imageSequenceFirstFrame";
280300
editorTemplate -addControl "imageSequenceFrameOutput";
281301
editorTemplate -addSeparator;
282-
editorTemplate -addControl "imageLoadEnable";
283-
editorTemplate -addControl "imageUseAlphaChannel";
284-
editorTemplate -addSeparator;
285-
editorTemplate -addControl "imageWidth";
286-
editorTemplate -addControl "imageHeight";
287-
editorTemplate -addControl "imagePixelAspect";
288-
editorTemplate -addSeparator;
289-
editorTemplate -addControl "imageSequenceStartFrame";
290-
editorTemplate -addControl "imageSequenceEndFrame";
302+
editorTemplate -addControl "imageFlip";
303+
editorTemplate -addControl "imageFlop";
291304
editorTemplate -endLayout;
292305

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

314+
// editorTemplate -beginLayout "Image Cache" -collapse 1;
315+
// // TODO: Add controls to view and edit the image cache.
316+
// editorTemplate -endLayout;
317+
301318
editorTemplate -beginLayout "Miscellaneous" -collapse 1;
302319
editorTemplate -addControl "meshResolution";
303320
editorTemplate -addControl "imageDefaultColor"; // Cannot be textured.
321+
editorTemplate -addControl "shaderIsTransparent";
304322
editorTemplate -endLayout;
305323

306324
editorTemplate -beginLayout "Nodes" -collapse 1;
307-
editorTemplate -addControl "shaderNode";
308-
editorTemplate -addControl "shaderFileNode";
309325
editorTemplate -addControl "geometryNode";
310326
editorTemplate -addControl "cameraNode";
311327
editorTemplate -addControl "imagePlaneShapeNode";
312328
editorTemplate -endLayout;
313329

314-
editorTemplate -suppress "imageSequencePadding";
315-
editorTemplate -suppress "cameraWidthInch";
316-
editorTemplate -suppress "cameraHeightInch";
317-
editorTemplate -suppress "lensHashCurrent";
318-
editorTemplate -suppress "lensHashPrevious";
330+
// // Internals that we don't want the user to see.
331+
// editorTemplate -suppress "imageSequencePadding";
332+
// editorTemplate -suppress "cameraWidthInch";
333+
// editorTemplate -suppress "cameraHeightInch";
334+
// editorTemplate -suppress "lensHashCurrent";
335+
// editorTemplate -suppress "lensHashPrevious";
336+
// editorTemplate -suppress "imageFilePath";
337+
// editorTemplate -suppress "inputColorSpace";
338+
// editorTemplate -suppress "outputColorSpace";
319339

320340
AEmmNodeShapeTemplateCommonEnd($nodeName);
321341
}

python/mmSolver/tools/createimageplane/_lib/constant.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (C) 2022 David Cattermole.
1+
# Copyright (C) 2022, 2024 David Cattermole.
22
#
33
# This file is part of mmSolver.
44
#
@@ -17,3 +17,20 @@
1717
#
1818

1919
DEFAULT_IMAGE_SEQUENCE_ATTR_NAME = 'imageSequenceMain'
20+
ALT_1_IMAGE_SEQUENCE_ATTR_NAME = 'imageSequenceAlternate1'
21+
ALT_2_IMAGE_SEQUENCE_ATTR_NAME = 'imageSequenceAlternate2'
22+
ALT_3_IMAGE_SEQUENCE_ATTR_NAME = 'imageSequenceAlternate3'
23+
24+
VALID_INPUT_IMAGE_SEQUENCE_ATTR_NAMES = [
25+
DEFAULT_IMAGE_SEQUENCE_ATTR_NAME,
26+
ALT_1_IMAGE_SEQUENCE_ATTR_NAME,
27+
ALT_2_IMAGE_SEQUENCE_ATTR_NAME,
28+
ALT_3_IMAGE_SEQUENCE_ATTR_NAME,
29+
]
30+
31+
SHADER_FILE_PATH_ATTR_NAME = 'imageFilePath'
32+
INPUT_COLOR_SPACE_ATTR_NAME = 'inputColorSpace'
33+
OUTPUT_COLOR_SPACE_ATTR_NAME = 'outputColorSpace'
34+
35+
SCENE_LINEAR_FILE_EXTENSIONS = ['exr', 'sxr']
36+
SRGB_FILE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'tif', 'tiff', 'tga', 'iff']

python/mmSolver/tools/createimageplane/_lib/main.py

+65-32
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (C) 2020, 2022 David Cattermole.
1+
# Copyright (C) 2020, 2022, 2024 David Cattermole.
22
#
33
# This file is part of mmSolver.
44
#
@@ -25,12 +25,13 @@
2525
import mmSolver.logger
2626
import mmSolver.api as mmapi
2727
import mmSolver.utils.camera as camera_utils
28+
import mmSolver.utils.constant as const_utils
29+
import mmSolver.utils.imageseq as imageseq_utils
2830
import mmSolver.utils.python_compat as pycompat
2931

3032
import mmSolver.tools.createimageplane.constant as const
3133
import mmSolver.tools.createimageplane._lib.constant as lib_const
3234
import mmSolver.tools.createimageplane._lib.utilities as lib_utils
33-
import mmSolver.tools.createimageplane._lib.shader as lib_shader
3435
import mmSolver.tools.createimageplane._lib.mmimageplane as lib_mmimageplane
3536
import mmSolver.tools.createimageplane._lib.polyplane as lib_polyplane
3637
import mmSolver.tools.createimageplane._lib.nativeimageplane as lib_nativeimageplane
@@ -56,20 +57,18 @@ def create_image_plane_on_camera(cam, name=None):
5657
poly_plane_name, mm_ip_tfm, cam_shp
5758
)
5859

59-
name_shade = name + 'Shader'
60-
shader_network = lib_shader.create_network(name_shade, mm_ip_tfm)
61-
6260
name_img_shp = name + 'Shape'
6361
mm_ip_shp = lib_mmimageplane.create_shape_node(
64-
name_img_shp, mm_ip_tfm, cam_shp, poly_plane_network, shader_network
65-
)
66-
67-
# Shortcut connections to nodes.
68-
lib_utils.force_connect_attr(
69-
shader_network.file_node + '.message', mm_ip_tfm + '.shaderFileNode'
62+
name_img_shp,
63+
mm_ip_tfm,
64+
cam_shp,
65+
poly_plane_network,
7066
)
7167

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

82-
# Set useFrameExtension temporarily. Setting useFrameExtension to
83-
# False causes frameOffset to be locked (but we need to edit it).
84-
is_seq = maya.cmds.getAttr(shader_network.file_node + '.useFrameExtension')
85-
maya.cmds.setAttr(shader_network.file_node + '.useFrameExtension', True)
86-
87-
file_node_attr = shader_network.file_node + '.frameExtension'
88-
lib_utils.force_connect_attr(shp_node_attr, file_node_attr)
89-
maya.cmds.setAttr(file_node_attr, lock=True)
90-
91-
maya.cmds.setAttr(shader_network.file_node + '.useFrameExtension', is_seq)
92-
9381
# Image sequence.
9482
image_sequence_path = lib_utils.get_default_image_path()
9583
set_image_sequence(mm_ip_tfm, image_sequence_path)
@@ -120,12 +108,12 @@ def convert_image_planes_on_camera(cam):
120108

121109
lib_nativeimageplane.copy_depth_value(mm_ip_tfm, native_ip_shp)
122110

123-
name_shader = name + 'Shader'
124-
shader_network = lib_shader.create_network(name_shader, mm_ip_tfm)
125-
126111
name_img_shp = name + 'Shape'
127112
mm_ip_shp = lib_mmimageplane.create_shape_node(
128-
name_img_shp, mm_ip_tfm, cam_shp, poly_plane_network, shader_network
113+
name_img_shp,
114+
mm_ip_tfm,
115+
cam_shp,
116+
poly_plane_network,
129117
)
130118

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

140128

129+
def _guess_color_space(file_path):
130+
file_extension = file_path.lower().split('.')[-1]
131+
if file_extension in lib_const.SCENE_LINEAR_FILE_EXTENSIONS:
132+
color_space = maya.cmds.mmColorIO(roleSceneLinear=True)
133+
elif file_extension in lib_const.SRGB_FILE_EXTENSIONS:
134+
color_space = maya.cmds.mmColorIO(roleColorPicking=True)
135+
else:
136+
color_space = maya.cmds.mmColorIO(guessColorSpaceFromFile=file_path)
137+
138+
if not color_space:
139+
color_space = maya.cmds.mmColorIO(roleData=True)
140+
if not color_space:
141+
color_space = maya.cmds.mmColorIO(roleDefault=True)
142+
143+
exists = maya.cmds.mmColorIO(colorSpaceExists=color_space)
144+
if exists is False:
145+
color_space = None
146+
147+
return color_space
148+
149+
141150
def set_image_sequence(mm_image_plane_node, image_sequence_path, attr_name=None):
142151
if attr_name is None:
143152
attr_name = lib_const.DEFAULT_IMAGE_SEQUENCE_ATTR_NAME
153+
assert isinstance(attr_name, str)
154+
assert attr_name in lib_const.VALID_INPUT_IMAGE_SEQUENCE_ATTR_NAMES
144155

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

149-
file_node = lib_mmimageplane.get_file_node(tfm)
150-
if file_node is None:
151-
LOG.warn('mmImagePlane shader file node is invalid.')
152-
153160
if shp is not None:
154161
lib_mmimageplane.set_image_sequence(shp, image_sequence_path, attr_name)
155-
if file_node is not None:
156-
lib_shader.set_file_path(file_node, image_sequence_path)
162+
lib_mmimageplane.set_image_sequence(
163+
shp, image_sequence_path, lib_const.SHADER_FILE_PATH_ATTR_NAME
164+
)
165+
166+
format_style = const_utils.IMAGE_SEQ_FORMAT_STYLE_FIRST_FRAME
167+
(
168+
file_pattern,
169+
_,
170+
_,
171+
_,
172+
_,
173+
) = imageseq_utils.expand_image_sequence_path(image_sequence_path, format_style)
174+
first_frame_file_seq = file_pattern.replace('\\', '/')
175+
176+
input_color_space = _guess_color_space(first_frame_file_seq)
177+
output_color_space = maya.cmds.mmColorIO(roleSceneLinear=True)
178+
179+
maya.cmds.setAttr(
180+
shp + '.' + lib_const.INPUT_COLOR_SPACE_ATTR_NAME,
181+
input_color_space,
182+
type='string',
183+
)
184+
maya.cmds.setAttr(
185+
shp + '.' + lib_const.OUTPUT_COLOR_SPACE_ATTR_NAME,
186+
output_color_space,
187+
type='string',
188+
)
189+
157190
return

0 commit comments

Comments
 (0)