Skip to content

Commit 33a705c

Browse files
Center 2D - add support for multi-object and components
This is a long-awaited feature for being able to center on multiple objects at once, or even components of an object - such as a Mesh vertex, edge or face. Using the mmPointFromObjectSet we are able to compute a new point that the mmReprojection node can use.
1 parent 559b864 commit 33a705c

File tree

2 files changed

+184
-48
lines changed

2 files changed

+184
-48
lines changed

python/mmSolver/tools/centertwodee/tool.py

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -80,71 +80,63 @@ def main():
8080
save_sel = maya.cmds.ls(selection=True, long=True) or []
8181

8282
# Get selection
83-
nodes = (
83+
objects = (
8484
maya.cmds.ls(
8585
selection=True,
8686
long=True,
87-
type='transform',
8887
)
8988
or []
9089
)
9190

9291
# Filter out selected imagePlanes.
93-
nodes_tmp = list(nodes)
94-
nodes = []
95-
for node in nodes_tmp:
92+
objects_tmp = list(objects)
93+
objects = []
94+
for obj in objects_tmp:
9695
shps = (
9796
maya.cmds.listRelatives(
98-
node, shapes=True, fullPath=True, type='imagePlane'
97+
obj, shapes=True, fullPath=True, type='imagePlane'
9998
)
10099
or []
101100
)
102101
if len(shps) == 0:
103-
nodes.append(node)
102+
objects.append(obj)
104103

105104
# Create centering node network.
106-
if len(nodes) == 0:
105+
if len(objects) == 0:
107106
msg = 'No objects selected, removing 2D centering.'
108107
LOG.warning(msg)
109108
mmapi.load_plugin()
110109
reproject_utils.remove_reprojection_from_camera(cam_tfm, cam_shp)
111110
reproject_utils.reset_pan_zoom(cam_tfm, cam_shp)
112-
elif len(nodes) == 1:
113-
LOG.warning('Applying 2D centering to %r', nodes)
111+
else:
112+
LOG.warning('Applying 2D centering to %r', objects)
114113
mmapi.load_plugin()
115-
reproj_nodes = reproject_utils.find_reprojection_nodes(cam_tfm, cam_shp)
116-
if len(reproj_nodes) > 0:
117-
maya.cmds.delete(reproj_nodes)
114+
reproject_utils.remove_reprojection_from_camera(cam_tfm, cam_shp)
118115

119116
reproj_node = reproject_utils.create_reprojection_on_camera(
120117
cam_tfm, cam_shp
121118
)
122-
reproject_utils.connect_transform_to_reprojection(nodes[0], reproj_node)
119+
reproject_utils.connect_objects_to_reprojection(objects, reproj_node)
123120

124121
# create 2d offset setup
125122
offset_plus_minus_node = maya.cmds.createNode(
126123
'plusMinusAverage', name='offset_plusMinusAverage1'
127124
)
128-
maya.cmds.connectAttr(
129-
reproj_node + '.outPan', offset_plus_minus_node + '.input2D[0]'
130-
)
131-
maya.cmds.setAttr(
132-
offset_plus_minus_node + '.input2D[1]', 0.0, 0.0, type='float2'
133-
)
134-
maya.cmds.connectAttr(
135-
offset_plus_minus_node + '.output2D.output2Dx',
136-
cam_shp + '.pan.horizontalPan',
137-
force=True,
138-
)
139-
maya.cmds.connectAttr(
140-
offset_plus_minus_node + '.output2D.output2Dy',
141-
cam_shp + '.pan.verticalPan',
142-
force=True,
143-
)
144125

145-
elif len(nodes) > 1:
146-
msg = 'Please select only 1 node to center on.'
147-
LOG.error(msg)
126+
src = reproj_node + '.outPan'
127+
dst = offset_plus_minus_node + '.input2D[0]'
128+
maya.cmds.connectAttr(src, dst)
129+
130+
plug = offset_plus_minus_node + '.input2D[1]'
131+
maya.cmds.setAttr(plug, 0.0, 0.0, type='float2')
132+
133+
src = offset_plus_minus_node + '.output2D.output2Dx'
134+
dst = cam_shp + '.pan.horizontalPan'
135+
maya.cmds.connectAttr(src, dst, force=True)
136+
137+
src = offset_plus_minus_node + '.output2D.output2Dy'
138+
dst = cam_shp + '.pan.verticalPan'
139+
maya.cmds.connectAttr(src, dst, force=True)
148140

149141
if len(save_sel) > 0:
150142
maya.cmds.select(save_sel, replace=True)

python/mmSolver/utils/reproject.py

Lines changed: 159 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -133,24 +133,62 @@ def create_reprojection_on_camera(cam_tfm, cam_shp):
133133
return node
134134

135135

136-
def find_reprojection_nodes(cam_tfm, cam_shp):
136+
def _find_auxiliary_set_nodes(point_from_set_node):
137137
"""
138138
Find all the reprojection nodes on the camera.
139139
"""
140-
nodes = (
140+
nodes = []
141+
142+
object_set_nodes = (
141143
maya.cmds.listConnections(
142-
cam_shp + '.focalLength',
143-
source=False,
144-
destination=True,
145-
type='mmReprojection',
144+
point_from_set_node + '.set',
145+
source=True,
146+
destination=False,
147+
type='objectSet',
146148
exactType=True,
147149
skipConversionNodes=True,
148150
)
149151
or []
150152
)
151-
if not nodes:
152-
return nodes
153-
reprojection_node = nodes[0]
153+
nodes += object_set_nodes
154+
155+
# transform_plugs = (
156+
# maya.cmds.listConnections(
157+
# point_from_set_node + '.matrix',
158+
# source=True,
159+
# destination=False,
160+
# plugs=True,
161+
# type='transform',
162+
# exactType=False,
163+
# skipConversionNodes=True,
164+
# )
165+
# or []
166+
# )
167+
# # nodes += transform_nodes
168+
169+
# mesh_plugs = (
170+
# maya.cmds.listConnections(
171+
# point_from_set_node + '.mesh',
172+
# source=True,
173+
# destination=False,
174+
# plugs=True,
175+
# type='mesh',
176+
# exactType=True,
177+
# skipConversionNodes=True,
178+
# )
179+
# or []
180+
# )
181+
# # nodes += mesh_nodes
182+
183+
return nodes
184+
185+
186+
def _find_auxiliary_reprojection_nodes(reprojection_node):
187+
"""
188+
Find all the reprojection nodes on the camera.
189+
"""
190+
nodes = []
191+
154192
# Get connected MultiplyDivide nodes connected.
155193
mult_nodes = (
156194
maya.cmds.listConnections(
@@ -165,6 +203,7 @@ def find_reprojection_nodes(cam_tfm, cam_shp):
165203
or []
166204
)
167205
nodes += mult_nodes
206+
168207
# Get connected offset PlusMinusAverage nodes.
169208
offset_plusminus_nodes = (
170209
maya.cmds.listConnections(
@@ -178,6 +217,58 @@ def find_reprojection_nodes(cam_tfm, cam_shp):
178217
or []
179218
)
180219
nodes += offset_plusminus_nodes
220+
221+
# Get connected mmPointFromObjectSet nodes.
222+
point_from_set_nodes = (
223+
maya.cmds.listConnections(
224+
reprojection_node + '.transformWorldMatrix',
225+
source=True,
226+
destination=False,
227+
type='mmPointFromObjectSet',
228+
exactType=True,
229+
skipConversionNodes=True,
230+
)
231+
or []
232+
)
233+
nodes += point_from_set_nodes
234+
235+
return nodes
236+
237+
238+
def _find_object_set_nodes(reproj_node):
239+
reproj_aux_nodes = _find_auxiliary_reprojection_nodes(reproj_node)
240+
point_from_set_nodes = [
241+
x for x in reproj_aux_nodes if maya.cmds.nodeType(x) == 'mmPointFromObjectSet'
242+
]
243+
set_nodes = []
244+
for point_from_set_node in point_from_set_nodes:
245+
set_nodes += _find_auxiliary_set_nodes(point_from_set_node)
246+
247+
return list(sorted(set(set_nodes + point_from_set_nodes)))
248+
249+
250+
def find_reprojection_nodes(cam_tfm, cam_shp):
251+
"""
252+
Find all the reprojection nodes on the camera.
253+
"""
254+
nodes = (
255+
maya.cmds.listConnections(
256+
cam_shp + '.focalLength',
257+
source=False,
258+
destination=True,
259+
type='mmReprojection',
260+
exactType=True,
261+
skipConversionNodes=True,
262+
)
263+
or []
264+
)
265+
if not nodes:
266+
return nodes
267+
reprojection_node = nodes[0]
268+
269+
# Get the other nodes.
270+
nodes += _find_auxiliary_reprojection_nodes(reprojection_node)
271+
nodes += _find_object_set_nodes(reprojection_node)
181272
return nodes
182273

183274

@@ -215,17 +306,70 @@ def reset_pan_zoom(cam_tfm, cam_shp):
215306
return
216307

217308

218-
def connect_transform_to_reprojection(tfm, reproj):
309+
def _cleanup_object_set_nodes(reproj_node):
310+
old_nodes = _find_object_set_nodes(reproj_node)
311+
if len(old_nodes) > 0:
312+
maya.cmds.delete(old_nodes)
313+
return len(old_nodes)
314+
315+
316+
def connect_transform_to_reprojection(tfm, reproj_node):
219317
"""
220-
Connect 'tfm' to the reprojection node, 'reproj'.
318+
Connect 'tfm' to the reprojection node, 'reproj_node'.
221319
222320
:param tfm: Transform node name to be connected.
223321
:type tfm: str
224322
225-
:param reproj: The re-projection node.
226-
:type reproj: str
323+
:param reproj_node: The re-projection node.
324+
:type reproj_node: str
227325
"""
326+
_cleanup_object_set_nodes(reproj_node)
327+
228328
src = tfm + '.worldMatrix'
229-
dst = reproj + '.transformWorldMatrix'
230-
maya.cmds.connectAttr(src, dst)
329+
dst = reproj_node + '.transformWorldMatrix'
330+
maya.cmds.connectAttr(src, dst, force=True)
331+
return
332+
333+
334+
def connect_objects_to_reprojection(objects, reproj_node):
335+
"""
336+
Connect all the objects and components in 'objects' to the
337+
reprojection node, 'reproj_node'.
338+
339+
:param objects:
340+
:type objects: str
341+
342+
:param reproj_node: The re-projection node.
343+
:type reproj_node: str
344+
345+
"""
346+
_cleanup_object_set_nodes(reproj_node)
347+
348+
point_from_set_node = maya.cmds.createNode('mmPointFromObjectSet')
349+
set_node = maya.cmds.sets(objects, name=reproj_node + '_center_objectSet')
350+
maya.cmds.connectAttr(
351+
set_node + '.message', point_from_set_node + '.set', force=True
352+
)
353+
354+
nodes = maya.cmds.ls(objects, objectsOnly=True, long=True)
355+
for i, node in enumerate(nodes):
356+
if not node.startswith('|'):
357+
# Only DAG objects can be connected.
358+
continue
359+
360+
# Both shapes and transforms should always contain a
361+
# worldMatrix attribute.
362+
src = node + '.worldMatrix[0]'
363+
dst = point_from_set_node + '.matrix[{}]'.format(i)
364+
maya.cmds.connectAttr(src, dst, force=True)
365+
366+
node_type = maya.cmds.nodeType(node)
367+
if node_type == 'mesh':
368+
src = node + '.worldMesh[0]'
369+
dst = point_from_set_node + '.mesh[{}]'.format(i)
370+
maya.cmds.connectAttr(src, dst, force=True)
371+
372+
src = point_from_set_node + '.outMatrix'
373+
dst = reproj_node + '.transformWorldMatrix'
374+
maya.cmds.connectAttr(src, dst, force=True)
231375
return

0 commit comments

Comments
 (0)