Skip to content

Instantly share code, notes, and snippets.

@yamahigashi
Created April 21, 2022 06:00
Show Gist options
  • Save yamahigashi/887540b99c1b0ac9a950dffc969932f5 to your computer and use it in GitHub Desktop.
Save yamahigashi/887540b99c1b0ac9a950dffc969932f5 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
###############################################################################
import sys
import textwrap
import maya.cmds as cmds
import maya.mel as mel
import maya.api.OpenMayaUI as omui
# import gml_maya.decorator as deco
from logging import ( # noqa:F401 pylint: disable=unused-import, wrong-import-order
StreamHandler,
getLogger,
WARN,
DEBUG,
INFO
)
if sys.version_info >= (3, 0): # pylint: disable=using-constant-test # pylint: disable=using-constant-test, wrong-import-order
# For type annotation
from typing import ( # NOQA: F401 pylint: disable=unused-import
Optional,
Dict,
List,
Tuple,
Pattern,
Callable,
Any,
Text,
Generator,
Union
)
handler = StreamHandler()
handler.setLevel(DEBUG)
logger = getLogger(__name__)
logger.setLevel(INFO)
logger.addHandler(handler)
logger.propagate = False
##############################################################################
def open_objectview(display_objects=None, target=None, camera=None, namespace=None):
# type: (Optional[List[Text]], Optional[Text], Optional[Text], Optional[Text]) -> None
"""Open a window that shows only the objects.
"""
if not display_objects:
display_objects = cmds.ls(sl=True)
if not display_objects:
mes = "nothing to display, cancel opening objectview window"
logger.warning(mes)
cmds.inViewMessage(
assistMessage=mes,
position='topCenter',
fade=True
)
return
delete_invisible_objectview()
if not target:
target = display_objects[0]
if not camera:
camera = get_or_create_target_camera("CustomObjectViewer", target, namespace)
try:
# spawn GUI elements, window, panel and layout
window_id = get_unique_window_id("CustomObjectViewer")
cmds.window()
window = cmds.window(
window_id,
title='Custom ObjectViewer',
sizeable=True,
topLeftCorner=(200, 200),
widthHeight=(400, 470),
)
layout = cmds.formLayout()
model_panel = cmds.modelPanel(
label='CustomObjectViewer_ModelPanel',
camera=camera
)
cmds.setParent('..')
control_panel = ""
cmds.window(
window_id,
edit=True,
closeCommand=(
textwrap.dedent(
"""
cmds.deleteUI("{}", panel=True)
cmds.deleteUI("{}", panel=True)
""".format(model_panel, control_panel)
)
)
)
except RuntimeError:
raise
_fill_objectview_with_layout(namespace, model_panel, control_panel, layout, camera)
_tweak_modelpanel_setting(model_panel, display_objects)
cmds.showWindow(window)
def reset_camera(camera, panel_name):
cmds.xform(camera, r=False, ws=False, t=(0, 0, 0))
cmds.xform(camera, r=False, ws=False, ro=(0, 0, 0))
shape = get_camera_shape(camera)
cmds.setAttr("{}.orthographicWidth".format(shape), 55)
cmds.setAttr("{}.horizontalPan".format(shape), 0)
cmds.setAttr("{}.verticalPan".format(shape), 0)
cmds.setAttr("{}.zoom".format(shape), 1)
# cmds.setAttr("{}.panZoomEnabled".format(shape), False)
cmds.setAttr("{}.centerOfInterest".format(shape), 66)
cmds.modelPanel(
panel_name,
edit=True,
camera=camera
)
def turn_camera_perspective_on(camera):
shape = get_camera_shape(camera)
cmds.setAttr("{}.orthographic".format(shape), False)
def turn_camera_orthographic_on(camera):
shape = get_camera_shape(camera)
cmds.setAttr("{}.orthographic".format(shape), True)
def toggle_camera_orthographic(camera):
shape = get_camera_shape(camera)
current = cmds.getAttr("{}.orthographic".format(shape))
cmds.setAttr("{}.orthographic".format(shape), not current)
def set_camera_focal_length(camera, focal_length):
# type: (Text, float) -> None
turn_camera_perspective_on(camera)
shape = get_camera_shape(camera)
cmds.setAttr("{}.focalLength".format(shape), focal_length)
def get_camera_shape(camera_xform):
# type: (Text) -> Text
shapes = cmds.listRelatives(camera_xform, shapes=True) or []
shape = shapes[0]
return shape
def _fill_objectview_with_layout(namespace, model_panel, control_panel, layout, camera):
# type: (Text, Text, Text, Text, Text) -> None
cmds.setParent('..')
col2 = cmds.columnLayout()
cmds.rowLayout(numberOfColumns=7)
cmds.button(
label="Reset camera",
command=textwrap.dedent(
"""
reset_camera("{}", "{}")
""".format(camera, model_panel)
)
)
cmds.button(
label="Toggle display elements",
command=textwrap.dedent(
"""
import maya.api.OpenMayaUI as omui
mask = omui.M3dView.kDisplayTextures + omui.M3dView.kDisplayMeshes
toggle_displayelements(mask)
""".format(cam=camera)
)
)
cmds.button(
label="18mm",
command=textwrap.dedent(
"""
set_camera_focal_length("{}", {})
""".format(camera, 18.0)
)
)
cmds.button(
label="35mm",
command=textwrap.dedent(
"""
set_camera_focal_length("{}", {})
""".format(camera, 35.0)
)
)
cmds.button(
label="50mm",
command=textwrap.dedent(
"""
set_camera_focal_length("{}", {})
""".format(camera, 50.0)
)
)
cmds.button(
label="Perspective / Orthographic",
command=textwrap.dedent(
"""
toggle_camera_orthographic("{}")
""".format(camera)
)
)
cmds.setParent('..')
cmds.formLayout(
layout,
edit=True,
attachForm=[
(model_panel, 'left', 5),
(model_panel, 'top', 0),
(model_panel, 'bottom', 80),
(model_panel, 'right', 5),
# (control_panel, 'left', 205),
# (control_panel, 'top', 0),
# (control_panel, 'right', 5),
# (control_panel, 'bottom', 80),
(col2, 'left', 5),
# (col2, 'top', 400),
(col2, 'right', 5),
(col2, 'bottom', 20)
] # pyright: ignore
)
# @deco.keep_selection
def _tweak_modelpanel_setting(model_panel, display_objects=None):
# type: (Text, Optional[List[Text]]) -> None
cmds.modelEditor(
model_panel,
edit=True,
grid=False,
displayAppearance='smoothShaded',
activeOnly=False,
displayTextures=True
)
if not display_objects:
return
cmds.refresh()
cmds.select(display_objects)
mel.eval("""isolateSelect -state 1 "{}";""".format(model_panel))
mel.eval("""isolateSelect -addSelectedObjects "{}";""".format(model_panel))
# mel.eval("""enableIsolateSelect "{}" true;""".format(model_panel))
def get_or_create_target_camera(camera_name, target, namespace, offset=None):
# type: (Text, Optional[Text], Text, Optional[Tuple[float, float, float]]) -> Text
if namespace:
query = "Camera_{}_{}".format(camera_name, namespace)
else:
query = "Camera_{}".format(camera_name)
if target:
query = "{}_{}".format(query, camera_name)
candidate = cmds.ls("{}*".format(query), type="transform")
if candidate:
return candidate[0]
return create_camera(camera_name, target, namespace)
def create_camera(name, lookat_object, namespace=None, offset=(0, 4, 50)):
# type: (Text, Optional[Text], Optional[Text], Tuple[int, int, int]) -> Text
"""Returns camera name."""
if namespace:
lookat_object = "{}:{}".format(namespace, lookat_object)
name = "{}_{}".format(name, namespace)
camera_name = "Camera_{}".format(name)
cam = cmds.camera(n=camera_name)
loc = cmds.spaceLocator(n="loc_{}".format(name))
cmds.parent(cam[0], loc)
if cmds.ls(lookat_object):
cmds.parent(loc, lookat_object)
cmds.xform(loc, worldSpace=False, relative=False, ro=(0, 0, 0))
cmds.xform(loc, worldSpace=False, relative=False, t=offset)
try:
cmds.parent(loc, world=True)
except RuntimeError:
pass
cmds.setAttr("{}.centerOfInterest".format(cam[1]), 66)
'''
cmds.expression(
s="""
{cam}.rotateX = 0;
{cam}.rotateY = 0;
{cam}.rotateZ = 0;
""".format(cam=cam[0]),
alwaysEvaluate=False
)
'''
if cmds.ls(lookat_object):
cmds.parentConstraint(lookat_object, loc, maintainOffset=True)
return cam[0]
def delete_invisible_objectview():
all_model_panels = cmds.getPanel(type="modelPanel")
opened_panels = []
for panel in all_model_panels:
label = cmds.panel(panel, q=True, label=True)
# if not isinstance(label, (str, unicode)):
# raise Exception("could not get panel {}".format(panel))
if "CustomObjectViewer" in label:
opened_panels.append(panel)
invis_panel_list = cmds.getPanel(invisiblePanels=True)
for panel in opened_panels:
if panel in invis_panel_list:
cmds.deleteUI(panel, panel=True)
# --------------------------------------------------------------------------------------
# copy from util.__init__.py
# --------------------------------------------------------------------------------------
def get_unique_window_id(candidate):
# type: (Text) -> Text
"""Returns unique id for window it may contain sequencial number."""
if cmds.about(batch=True):
raise Exception("access to the widgets does not supported in batch mode")
def _is_window_exists(query):
return cmds.window(query, q=True, exists=True)
num = 0
query = candidate
while _is_window_exists(query):
query = "{}{}".format(candidate, num)
num += 1
return query
SLIM_MASK = omui.M3dView.kDisplayTextures + omui.M3dView.kDisplayMeshes + omui.M3dView.kDisplayGrid
ALL_MASK = omui.M3dView.kDisplayEverything
def _hoge(mask):
av = omui.M3dView.active3dView()
av.setObjectDisplay(mask)
av.refresh()
def toggle_displayelements(mask=SLIM_MASK):
av = omui.M3dView.active3dView()
current = av.objectDisplay()
if mask == current:
_hoge(ALL_MASK)
else:
_hoge(mask)
# @deco.keep_selection
def open():
sel = cmds.ls(sl=True)
open_objectview(display_objects=sel)
if __name__ == "__main__":
open()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment