Skip to content

Instantly share code, notes, and snippets.

@Pakmanv
Created May 2, 2025 17:52
Show Gist options
  • Select an option

  • Save Pakmanv/9e9cca5785917c2e8f6411a4748756ee to your computer and use it in GitHub Desktop.

Select an option

Save Pakmanv/9e9cca5785917c2e8f6411a4748756ee to your computer and use it in GitHub Desktop.
Scene Unit and Finaling VV
import maya.cmds as cmds
import os
class SceneUnitConverter:
def __init__(self):
self.window_name = "sceneUnitVVWindow"
self.maya_units = {
"Millimeter": "mm",
"Centimeter": "cm",
"Meter": "m",
"Inch": "inch",
"Foot": "ft",
"Yard": "yd"
}
self.current_unit = "Foot"
self.grid_size = 12
self.grid_spacing = 5
self.grid_subdivisions = 5
self.distance_feet = 6
self.distance_inches = 6
self.reference_path = "O:\\productions\\inviz\\SKTL\\00_cg\\scenes\\default_setup\\sizecomp_joint_referernce_VV_Realworld_UE_Scales.ma"
self.is_referenced = False
self.joint_size = 0.01
self.current_file = cmds.file(query=True, sceneName=True) or "Untitled.ma"
self.create_ui()
def create_ui(self):
if cmds.window(self.window_name, exists=True):
cmds.deleteUI(self.window_name)
self.window = cmds.window(self.window_name, title="Scene Unit and Finaling VV 4.0",
widthHeight=(300, 750))
self.scroll_layout = cmds.scrollLayout(horizontalScrollBarThickness=16,
verticalScrollBarThickness=16)
self.main_layout = cmds.columnLayout(adjustableColumn=True, rowSpacing=5)
# Working Units Section
self.working_frame = cmds.frameLayout(label="Working Units", collapsable=True, collapse=False)
cmds.text(label="Current Unit:")
self.current_unit_field = cmds.text(label=f"{self.current_unit}")
cmds.text(label="Select Unit:")
self.unit_menu = cmds.optionMenu()
for unit in self.maya_units.keys():
cmds.menuItem(label=unit)
cmds.optionMenu(self.unit_menu, edit=True, value="Foot")
cmds.button(label="Change Unit", command=self.change_unit, backgroundColor=(1.0, 0.8, 0.8))
cmds.setParent("..")
# Grid Settings Section
self.grid_frame = cmds.frameLayout(label="Grid Settings", collapsable=True, collapse=False)
cmds.text(label="Size:")
self.size_field = cmds.floatField(value=self.grid_size, precision=2)
cmds.text(label="Grid Lines Every:")
self.spacing_field = cmds.floatField(value=self.grid_spacing, precision=2)
cmds.text(label="Subdivisions:")
self.subdiv_field = cmds.intField(value=self.grid_subdivisions, minValue=1)
cmds.button(label="Commit Grid", command=self.update_grid, backgroundColor=(0.6, 0.8, 1.0))
cmds.setParent("..")
# Distance Tool Section
self.distance_frame = cmds.frameLayout(label="Distance Tool", collapsable=True, collapse=False)
cmds.rowLayout(numberOfColumns=6, columnWidth6=(60, 60, 30, 60, 30, 80))
cmds.text(label="Height:")
self.feet_field = cmds.intField(value=self.distance_feet, width=60)
cmds.text(label="ft")
self.inches_field = cmds.intField(value=self.distance_inches, width=60)
cmds.text(label="in")
self.conversion_label = cmds.text(label="= 0.0 units")
cmds.setParent("..")
cmds.rowLayout(numberOfColumns=3, columnWidth3=(100, 80, 80))
cmds.text(label="Convert to:")
self.conversion_unit_menu = cmds.optionMenu(width=80)
for unit in self.maya_units.keys():
cmds.menuItem(label=unit)
cmds.optionMenu(self.conversion_unit_menu, edit=True, value="Foot")
cmds.button(label="Convert", command=self.convert_distance)
cmds.setParent("..")
cmds.button(label="Create Distance", command=self.create_distance, backgroundColor=(1.0, 1.0, 0.6))
cmds.setParent("..")
# Reference Toggle Section
self.reference_frame = cmds.frameLayout(label="Reference Toggle", collapsable=True, collapse=False)
cmds.text(label="Reference Path:")
self.reference_path_field = cmds.text(label=self.reference_path, wordWrap=True, height=40)
cmds.button(label="Change Reference Path", command=self.change_reference_path)
self.toggle_button = cmds.button(label="Load Reference", command=self.toggle_reference)
self.status_field = cmds.text(label="Reference not loaded")
cmds.setParent("..")
# Joint Size Section
self.joint_frame = cmds.frameLayout(label="Joint Size Changer", collapsable=True, collapse=False)
cmds.text(label="Set all joint sizes in scene", height=20)
self.joint_size_field = cmds.floatFieldGrp(label="Joint Size", value1=self.joint_size, precision=3)
cmds.button(label="Apply Joint Size", command=self.change_joint_size, backgroundColor=(0.9, 0.8, 1.0))
cmds.setParent("..")
# Geometry Tools Section
self.geometry_frame = cmds.frameLayout(label="Geometry Tools", collapsable=True, collapse=False)
cmds.button(label="Freeze All Geometry", command=self.freeze_geometry, backgroundColor=(0.7, 0.9, 0.9))
cmds.button(label="Freeze Selection", command=self.freeze_selection, backgroundColor=(0.8, 1.0, 0.8))
cmds.button(label="Reset Root Pivot to Origin", command=self.reset_root_pivot)
cmds.button(label="Center Pivot", command=self.center_pivot)
cmds.button(label="Unhide All Nodes", command=self.unhide_all_nodes)
cmds.setParent("..")
# Camera Clip Planes Section (Updated)
self.camera_frame = cmds.frameLayout(label="Camera Clip Planes", collapsable=True, collapse=False)
current_camera = self.get_active_camera()
near_clip, far_clip = self.get_camera_clip_values(current_camera)
cmds.text(label=f"Current Camera: {current_camera}")
self.near_clip_field = cmds.floatFieldGrp(label="Near Clip", value1=near_clip, precision=2)
self.far_clip_field = cmds.floatFieldGrp(label="Far Clip", value1=far_clip, precision=2)
cmds.button(label="Update Clip Planes", command=self.update_clip_planes, backgroundColor=(0.7, 0.9, 0.85))
cmds.button(label="Refresh Camera", command=self.refresh_camera_info, backgroundColor=(0.7, 0.9, 0.85))
cmds.setParent("..")
# Notes Section
self.notes_frame = cmds.frameLayout(label="Scene Notes", collapsable=True, collapse=False)
self.notes_field = cmds.scrollField(editable=True, height=100, wordWrap=True)
cmds.button(label="Apply Notes to Root", command=self.apply_notes)
cmds.setParent("..")
# File Management Section
self.file_frame = cmds.frameLayout(label="File Management", collapsable=True, collapse=False)
cmds.text(label="Current File:")
self.file_name_field = cmds.textField(text=self.current_file, width=280)
cmds.button(label="Open", command=self.open_file, backgroundColor=(0.7, 0.9, 1.0))
cmds.button(label="Save", command=self.save_file, backgroundColor=(1.0, 0.7, 0.7))
cmds.button(label="Save As", command=self.save_as_file, backgroundColor=(1.0, 0.85, 0.6))
cmds.text(label="Tool created by Vypac Voeur and shouldn't be distributed.",
align="center", height=20)
cmds.setParent("..")
cmds.setParent("..")
cmds.setParent("..")
cmds.showWindow(self.window)
def get_active_camera(self):
"""Get the camera from the active viewport"""
visible_panels = cmds.getPanel(visiblePanels=True) or []
for panel in visible_panels:
if cmds.getPanel(typeOf=panel) == "modelPanel":
cam = cmds.modelPanel(panel, query=True, camera=True)
if cam:
return cam
return "persp" # Fallback
def get_camera_clip_values(self, camera):
"""Get near and far clip values from the camera's shape node"""
shapes = cmds.listRelatives(camera, shapes=True, fullPath=True) or [camera]
cam_shape = shapes[0]
near_clip = cmds.getAttr(f"{cam_shape}.nearClipPlane")
far_clip = cmds.getAttr(f"{cam_shape}.farClipPlane")
return near_clip, far_clip
def change_unit(self, *args):
"""Update Maya's working unit preference and UI display"""
self.current_unit = cmds.optionMenu(self.unit_menu, query=True, value=True)
maya_unit = self.maya_units[self.current_unit]
cmds.optionVar(stringValue=("linearUnit", maya_unit))
cmds.currentUnit(linear=maya_unit)
cmds.text(self.current_unit_field, edit=True, label=f"{self.current_unit}")
def update_grid(self, *args):
"""Update Maya's grid settings"""
try:
self.grid_size = cmds.floatField(self.size_field, query=True, value=True)
self.grid_spacing = cmds.floatField(self.spacing_field, query=True, value=True)
self.grid_subdivisions = cmds.intField(self.subdiv_field, query=True, value=True)
cmds.grid(size=self.grid_size,
spacing=self.grid_spacing,
divisions=self.grid_subdivisions)
except Exception as e:
cmds.warning(f"Failed to update grid: {str(e)}")
def create_distance(self, *args):
"""Create distance measurement with bright yellow locators using feet and inches in scene units"""
try:
feet = cmds.intField(self.feet_field, query=True, value=True)
inches = cmds.intField(self.inches_field, query=True, value=True)
total_feet = feet + (inches / 12.0)
conversion_rates = {
"Foot": 1.0,
"Inch": 12.0,
"Millimeter": 304.8,
"Centimeter": 30.48,
"Meter": 0.3048,
"Yard": 0.333333
}
current_maya_unit = self.maya_units[self.current_unit]
distance_in_scene_units = total_feet * conversion_rates[self.current_unit]
loc1 = cmds.spaceLocator(position=(0, 0, 0), name="distanceLoc1")[0]
loc2 = cmds.spaceLocator(position=(0, distance_in_scene_units, 0),
name="distanceLoc2")[0]
for loc in [loc1, loc2]:
shape = cmds.listRelatives(loc, shapes=True, fullPath=True)[0]
cmds.setAttr(f"{shape}.overrideEnabled", 1)
cmds.setAttr(f"{shape}.overrideRGBColors", 1)
cmds.setAttr(f"{shape}.overrideColorRGB", 1.0, 1.0, 0.0) # Bright yellow
distance_obj = cmds.distanceDimension(sp=(0, 0, 0),
ep=(0, distance_in_scene_units, 0))
cmds.connectAttr(f"{loc1}.worldPosition[0]", f"{distance_obj}.startPoint")
cmds.connectAttr(f"{loc2}.worldPosition[0]", f"{distance_obj}.endPoint")
cmds.select(distance_obj)
except Exception as e:
cmds.warning(f"Failed to create distance: {str(e)}")
def convert_distance(self, *args):
"""Convert feet and inches to selected unit and update label"""
try:
feet = cmds.intField(self.feet_field, query=True, value=True)
inches = cmds.intField(self.inches_field, query=True, value=True)
total_feet = feet + (inches / 12.0)
conversion_rates = {
"Foot": 1.0,
"Inch": 12.0,
"Millimeter": 304.8,
"Centimeter": 30.48,
"Meter": 0.3048,
"Yard": 0.333333
}
convert_to_unit = cmds.optionMenu(self.conversion_unit_menu, query=True, value=True)
distance_in_target_unit = total_feet * conversion_rates[convert_to_unit]
cmds.text(self.conversion_label, edit=True,
label=f"= {distance_in_target_unit:.2f} {self.maya_units[convert_to_unit]}")
except Exception as e:
cmds.warning(f"Failed to convert distance: {str(e)}")
def toggle_reference(self, *args):
"""Toggle reference file loading"""
try:
if not self.is_referenced:
cmds.file(
self.reference_path,
reference=True,
options="v=0;p=17;f=0",
ignoreVersion=True
)
self.is_referenced = True
cmds.button(self.toggle_button, edit=True, label="Remove Reference")
cmds.text(self.status_field, edit=True, label="Reference loaded")
else:
ref_node = cmds.referenceQuery(self.reference_path, referenceNode=True)
if ref_node:
cmds.file(self.reference_path, removeReference=True)
self.is_referenced = False
cmds.button(self.toggle_button, edit=True, label="Load Reference")
cmds.text(self.status_field, edit=True, label="Reference removed")
except Exception as e:
cmds.warning(f"Failed to toggle reference: {str(e)}")
def change_reference_path(self, *args):
"""Change the reference file path"""
try:
new_path = cmds.fileDialog2(fileMode=1, caption="Select Reference File",
fileFilter="Maya Files (*.ma *.mb)")
if new_path:
self.reference_path = new_path[0]
cmds.text(self.reference_path_field, edit=True, label=self.reference_path)
if self.is_referenced:
cmds.file(self.reference_path, removeReference=True, force=True)
cmds.file(self.reference_path, reference=True, options="v=0;p=17;f=0",
ignoreVersion=True)
cmds.text(self.status_field, edit=True, label="Reference updated")
print(f"Reference path updated to: {self.reference_path}")
except Exception as e:
cmds.warning(f"Failed to change reference path: {str(e)}")
def change_joint_size(self, *args):
"""Change size of all joints in the scene"""
try:
new_size = cmds.floatFieldGrp(self.joint_size_field, query=True, value1=True)
all_joints = cmds.ls(type="joint")
if not all_joints:
cmds.warning("No joints found in the scene!")
return
for joint in all_joints:
cmds.setAttr(f"{joint}.radius", new_size)
print(f"Changed {len(all_joints)} joints to size {new_size}")
except Exception as e:
cmds.warning(f"Failed to change joint size: {str(e)}")
def freeze_geometry(self, *args):
"""Freeze transformations on all geometry objects only"""
try:
geometry = cmds.ls(type=["mesh", "nurbsSurface"], geometry=True)
if not geometry:
cmds.warning("No geometry found in scene!")
return
transforms = cmds.listRelatives(geometry, parent=True, fullPath=True) or []
transforms = list(set(transforms))
geo_transforms = [t for t in transforms if cmds.nodeType(t) == "transform"]
if not geo_transforms:
cmds.warning("No geometry transform nodes found!")
return
cmds.makeIdentity(geo_transforms, apply=True, translate=True,
rotate=True, scale=True, normal=0)
print(f"Froze transformations on {len(geo_transforms)} geometry objects")
except Exception as e:
cmds.warning(f"Failed to freeze geometry: {str(e)}")
def freeze_selection(self, *args):
"""Freeze transformations on any selected transform objects"""
try:
selected = cmds.ls(selection=True, long=True)
if not selected:
cmds.warning("No objects selected!")
return
transforms = [obj for obj in selected if cmds.nodeType(obj) == "transform"]
if not transforms:
cmds.warning("No transform nodes selected to freeze!")
return
cmds.makeIdentity(transforms, apply=True, translate=True,
rotate=True, scale=True, normal=0)
print(f"Froze transformations on {len(transforms)} selected objects")
except Exception as e:
cmds.warning(f"Failed to freeze selection: {str(e)}")
def reset_root_pivot(self, *args):
"""Move pivot of root-level groups to origin (0,0,0)"""
try:
root_nodes = cmds.ls(assemblies=True, long=True)
if not root_nodes:
cmds.warning("No root nodes found in scene!")
return
count = 0
for node in root_nodes:
if cmds.nodeType(node) == "transform":
cmds.xform(node, pivots=(0, 0, 0), worldSpace=True)
count += 1
print(f"Reset pivots to origin for {count} root nodes")
except Exception as e:
cmds.warning(f"Failed to reset pivots: {str(e)}")
def center_pivot(self, *args):
"""Center pivot for each geometry object individually"""
try:
geometry = cmds.ls(type=["mesh", "nurbsSurface"], geometry=True)
if not geometry:
cmds.warning("No geometry found in scene!")
return
transforms = cmds.listRelatives(geometry, parent=True, fullPath=True) or []
transforms = list(set(transforms))
geo_transforms = [t for t in transforms if cmds.nodeType(t) == "transform"]
if not geo_transforms:
cmds.warning("No geometry transform nodes found!")
return
count = 0
for transform in geo_transforms:
cmds.xform(transform, centerPivots=True)
count += 1
print(f"Centered pivots for {count} geometry objects")
except Exception as e:
cmds.warning(f"Failed to center pivots: {str(e)}")
def unhide_all_nodes(self, *args):
"""Unhide all hidden nodes in the scene that have a visibility attribute"""
try:
all_nodes = cmds.ls(long=True)
hidden_nodes = [node for node in all_nodes
if cmds.attributeQuery("visibility", node=node, exists=True)
and cmds.getAttr(f"{node}.visibility") == 0]
if not hidden_nodes:
print("No hidden nodes found in the scene.")
return
for node in hidden_nodes:
cmds.setAttr(f"{node}.visibility", 1)
print(f"Unhidden {len(hidden_nodes)} nodes in the scene.")
except Exception as e:
cmds.warning(f"Failed to unhide nodes: {str(e)}")
def update_clip_planes(self, *args):
"""Update the near and far clip planes of the current camera"""
try:
current_camera = self.get_active_camera()
near_clip = cmds.floatFieldGrp(self.near_clip_field, query=True, value1=True)
far_clip = cmds.floatFieldGrp(self.far_clip_field, query=True, value1=True)
if near_clip <= 0:
cmds.warning("Near Clip Plane must be greater than 0!")
return
if far_clip <= near_clip:
cmds.warning("Far Clip Plane must be greater than Near Clip Plane!")
return
shapes = cmds.listRelatives(current_camera, shapes=True, fullPath=True) or [current_camera]
cam_shape = shapes[0]
cmds.setAttr(f"{cam_shape}.nearClipPlane", near_clip)
cmds.setAttr(f"{cam_shape}.farClipPlane", far_clip)
print(f"Updated clip planes for {current_camera}: Near = {near_clip}, Far = {far_clip}")
except Exception as e:
cmds.warning(f"Failed to update clip planes: {str(e)}")
def refresh_camera_info(self, *args):
"""Refresh the camera clip plane UI with current camera values"""
current_camera = self.get_active_camera()
near_clip, far_clip = self.get_camera_clip_values(current_camera)
cmds.text(self.camera_frame, edit=True, label=f"Camera Clip Planes - {current_camera}")
cmds.floatFieldGrp(self.near_clip_field, edit=True, value1=near_clip)
cmds.floatFieldGrp(self.far_clip_field, edit=True, value1=far_clip)
def apply_notes(self, *args):
"""Apply notes to root transform attributes"""
try:
notes = cmds.scrollField(self.notes_field, query=True, text=True)
root_nodes = cmds.ls(assemblies=True, long=True)
if not root_nodes:
cmds.warning("No root nodes found to apply notes!")
return
count = 0
for node in root_nodes:
if cmds.nodeType(node) == "transform":
if not cmds.attributeQuery("notes", node=node, exists=True):
cmds.addAttr(node, longName="notes", dataType="string")
cmds.setAttr(f"{node}.notes", notes, type="string")
count += 1
print(f"Applied notes to {count} root nodes")
except Exception as e:
cmds.warning(f"Failed to apply notes: {str(e)}")
def save_file(self, *args):
"""Save the current file"""
try:
file_name = cmds.textField(self.file_name_field, query=True, text=True)
if not file_name:
cmds.warning("No file name specified!")
return
cmds.file(rename=file_name)
cmds.file(save=True, type="mayaAscii")
self.current_file = file_name
cmds.textField(self.file_name_field, edit=True, text=self.current_file)
print(f"Saved file as: {self.current_file}")
except Exception as e:
cmds.warning(f"Failed to save file: {str(e)}")
def save_as_file(self, *args):
"""Save the file with a new name"""
try:
new_file = cmds.fileDialog2(fileMode=0, caption="Save As",
fileFilter="Maya ASCII (*.ma)")
if new_file:
new_file_path = new_file[0]
cmds.file(rename=new_file_path)
cmds.file(save=True, type="mayaAscii")
self.current_file = new_file_path
cmds.textField(self.file_name_field, edit=True, text=self.current_file)
print(f"Saved as: {self.current_file}")
except Exception as e:
cmds.warning(f"Failed to save as: {str(e)}")
def open_file(self, *args):
"""Open a new scene file and update save location"""
try:
new_file = cmds.fileDialog2(fileMode=1, caption="Open File",
fileFilter="Maya Files (*.ma *.mb)")
if new_file:
new_file_path = new_file[0]
cmds.file(new_file_path, open=True, force=True)
self.current_file = cmds.file(query=True, sceneName=True) or "Untitled.ma"
cmds.textField(self.file_name_field, edit=True, text=self.current_file)
print(f"Opened file: {self.current_file}")
except Exception as e:
cmds.warning(f"Failed to open file: {str(e)}")
def main():
cmds.optionVar(stringValue=("linearUnit", "ft"))
cmds.currentUnit(linear="ft")
cmds.grid(size=12, spacing=5, divisions=5, reset=True)
SceneUnitConverter()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment