【メモ】Maya アニメーションのランダムな動きを与える

ChatGPTで作成
選択したオブジェクトの親階層以下、あるいは子階層のみのモーションにランダムを与える。

import maya.cmds as cmds
import random
WINDOW_NAME = "rotationNoiseTool_v6"
def get_hierarchy_transforms(include_selected_parent=True):
selected = cmds.ls(selection=True, long=True) or []
targets = []
for obj in selected:
if include_selected_parent and cmds.nodeType(obj) == "transform":
targets.append(obj)
children = cmds.listRelatives(
obj,
allDescendents=True,
type="transform",
fullPath=True
) or []
targets.extend(children)
return list(dict.fromkeys(targets))
def add_rotation_noise(
min_interval=3,
max_interval=12,
min_percent=5.0,
max_percent=400.0,
spline_ratio=0.5,
fallback_base=1.0,
no_key_random_min=-10.0,
no_key_random_max=10.0,
include_selected_parent=True
):
targets = get_hierarchy_transforms(include_selected_parent)
if not targets:
cmds.warning("対象オブジェクトがありません。")
return
if min_interval > max_interval:
min_interval, max_interval = max_interval, min_interval
if min_percent > max_percent:
min_percent, max_percent = max_percent, min_percent
if no_key_random_min > no_key_random_max:
no_key_random_min, no_key_random_max = no_key_random_max, no_key_random_min
start = int(cmds.playbackOptions(q=True, min=True))
end = int(cmds.playbackOptions(q=True, max=True))
rotate_attrs = ["rotateX", "rotateY", "rotateZ"]
inserted_count = 0
for obj in targets:
for attr in rotate_attrs:
plug = obj + "." + attr
if not cmds.objExists(plug):
continue
if cmds.getAttr(plug, lock=True):
continue
key_times = cmds.keyframe(plug, q=True, timeChange=True) or []
key_times = sorted(set([float(k) for k in key_times]))
frame = start + random.randint(min_interval, max_interval)
while frame <= end:
base_value = cmds.getAttr(plug, time=frame)
if not key_times:
random_offset = random.uniform(no_key_random_min, no_key_random_max)
new_value = base_value + random_offset
else:
prev_keys = [k for k in key_times if k < frame]
next_keys = [k for k in key_times if k > frame]
prev_key = max(prev_keys) if prev_keys else None
next_key = min(next_keys) if next_keys else None
if prev_key is not None and next_key is not None:
prev_value = cmds.getAttr(plug, time=prev_key)
next_value = cmds.getAttr(plug, time=next_key)
delta_base = abs(next_value - prev_value)
elif prev_key is not None:
prev_value = cmds.getAttr(plug, time=prev_key)
delta_base = abs(base_value - prev_value)
elif next_key is not None:
next_value = cmds.getAttr(plug, time=next_key)
delta_base = abs(next_value - base_value)
else:
delta_base = fallback_base
if delta_base == 0:
delta_base = fallback_base
percent = random.uniform(min_percent, max_percent) / 100.0
amount = delta_base * percent
direction = random.choice([-1, 1])
new_value = base_value + amount * direction
cmds.setKeyframe(
plug,
time=frame,
value=new_value
)
tangent_type = "spline" if random.random() < spline_ratio else "linear"
cmds.keyTangent(
plug,
time=(frame, frame),
inTangentType=tangent_type,
outTangentType=tangent_type
)
inserted_count += 1
key_times.append(float(frame))
key_times = sorted(set(key_times))
frame += random.randint(min_interval, max_interval)
cmds.inViewMessage(
amg="回転キーを {} 個追加しました".format(inserted_count),
pos="midCenter",
fade=True
)
print("Rotation keys inserted:", inserted_count)
def run_from_ui(*args):
add_rotation_noise(
min_interval=cmds.intSliderGrp("minInterval", q=True, value=True),
max_interval=cmds.intSliderGrp("maxInterval", q=True, value=True),
min_percent=cmds.floatSliderGrp("minPercent", q=True, value=True),
max_percent=cmds.floatSliderGrp("maxPercent", q=True, value=True),
spline_ratio=cmds.floatSliderGrp("splineRatio", q=True, value=True),
fallback_base=cmds.floatSliderGrp("fallbackBase", q=True, value=True),
no_key_random_min=cmds.floatSliderGrp("noKeyRandomMin", q=True, value=True),
no_key_random_max=cmds.floatSliderGrp("noKeyRandomMax", q=True, value=True),
include_selected_parent=cmds.checkBox("includeSelectedParent", q=True, value=True)
)
def create_ui():
if cmds.window(WINDOW_NAME, exists=True):
cmds.deleteUI(WINDOW_NAME)
cmds.window(WINDOW_NAME, title="Rotation Noise Tool v6", widthHeight=(470, 420))
cmds.columnLayout(adjustableColumn=True, rowSpacing=10)
cmds.text(label="選択オブジェクト+下階層の回転にランダムキーを追加")
cmds.checkBox(
"includeSelectedParent",
label="最初に選択した親オブジェクトにも回転キーを追加する",
value=True
)
cmds.intSliderGrp(
"minInterval",
label="間隔 下限",
field=True,
minValue=1,
maxValue=100,
value=3
)
cmds.intSliderGrp(
"maxInterval",
label="間隔 上限",
field=True,
minValue=1,
maxValue=100,
value=12
)
cmds.floatSliderGrp(
"minPercent",
label="変化量 下限 %",
field=True,
minValue=5.0,
maxValue=400.0,
value=5.0
)
cmds.floatSliderGrp(
"maxPercent",
label="変化量 上限 %",
field=True,
minValue=5.0,
maxValue=400.0,
value=400.0
)
cmds.floatSliderGrp(
"fallbackBase",
label="基準差分が0の時の角度",
field=True,
minValue=0.1,
maxValue=30.0,
value=1.0
)
cmds.floatSliderGrp(
"noKeyRandomMin",
label="キー無し時 最小角度",
field=True,
minValue=-180.0,
maxValue=180.0,
value=-10.0
)
cmds.floatSliderGrp(
"noKeyRandomMax",
label="キー無し時 最大角度",
field=True,
minValue=-180.0,
maxValue=180.0,
value=10.0
)
cmds.floatSliderGrp(
"splineRatio",
label="Spline比率",
field=True,
minValue=0.0,
maxValue=1.0,
value=0.5
)
cmds.button(
label="回転キーを追加",
height=40,
command=run_from_ui
)
cmds.showWindow(WINDOW_NAME)
create_ui()Code language: Python (python) 