【Maya】キーフレームのスタート / エンドの取得 | リグログ!
ノード単体からの取得する関数です。
元の関数と同じようにTranslate / Rotate / Scale から対象選べるようにしてみました。
(もうちょいスマートな方法ある気がしますが。。。)
import maya.cmds as cmds
def get_time_range_from_node(node=None, t=True, r=True, s=True):
'''
ノードからアニメカーブの範囲を取得する
t : Translate
r : Rotate
s : Scale
'''
anim_curves = []
if t is True:
anim_curves += cmds.listConnections(node, t='animCurveTL', et=True)
if r is True:
anim_curves += cmds.listConnections(node, t='animCurveTA', et=True)
if s is True:
anim_curves += cmds.listConnections(node, t='animCurveTU', et=True)
min_time = None
max_time = None
for anim_curve in anim_curves:
indices = cmds.getAttr('%s.ktv' %anim_curve, mi=True)
for i in indices:
t,v = cmds.getAttr('%s.ktv[%i]' %(anim_curve,i))[0]
if min_time is None or t < min_time:
min_time = t
elif max_time is None or max_time < t:
max_time = t
return min_time,max_time
multi_prog_win = None
class MultiProgressWin(object):
WIDTH = 300
def __init__(self, title="MultiProgressWin", max=100, display_text=""):
self.showwin = False
if multi_prog_win is None:
global multi_prog_win
multi_prog_win = cmds.window(t=title, w=self.WIDTH, s=False)
cmds.showWindow(multi_prog_win)
self.showwin = True
self.__add_bar(display_text, max)
cmds.refresh()
def __add_bar(self, display_text, max):
self.layout = cmds.columnLayout(p=multi_prog_win)
self.text = cmds.text(display_text, p=self.layout)
self.bar = cmds.progressBar(maxValue=max, w=self.WIDTH, p=self.layout, progress=0)
# デフォルトの高さが39ずつ増えていたのでキリが良いように40増やしてみる
preHeight = cmds.window(multi_prog_win, q=True, height=True)
global multi_prog_win
cmds.window(multi_prog_win, edit=True, h=preHeight + 40)
def update(self, display_text=None, step=1):
'''
プログレスバーを動かす。
通常は1ずつ増加
'''
cmds.progressBar(self.bar, e=True, step=step)
if display_text is not None:
cmds.text(self.text, e=True, l=display_text)
cmds.refresh()
progress = cmds.progressBar(self.bar, q=True, progress=True)
max = cmds.progressBar(self.bar, q=True, maxValue=True)
global multi_prog_win
preHeight = cmds.window(multi_prog_win, q=True, height=True)
if progress == max and preHeight - 40 > 0: # 0以下になったときのエラー回避
cmds.window(multi_prog_win, edit=True, h=preHeight - 40)
def reset(self, display_text=None):
'''
プログレスバーのリセット
'''
cmds.progressBar(self.bar, e=True, progress=0)
if display_text is not None:
cmds.text(self.text, e=True, l=display_text)
cmds.refresh()
def kill(self):
'''
作ったものを削除。
Windowを生成していたらWindowが消えるが、
追加プログレスバーの場合だったらプログレスバーだけ消える
'''
if self.showwin is False:
cmds.deleteUI(self.layout, control=True)
return
global multi_prog_win
cmds.deleteUI(multi_prog_win)
del multi_prog_win
def test(text=u"一つ追加"):
pw = MultiProgressWin(display_text=text, max=100)
for i in range(100):
pw.update(text)
time.sleep(0.02)
pw.kill()
def test2():
text=u"追加一つ目"
pw = MultiProgressWin(display_text=text, max=100)
for i in range(100):
pw.update(text)
time.sleep(0.02)
if i == 50:
test(u"二つ目追加!!")
text=u"2つ目が終わったので再開"
pw.kill()
pw = MultiProgressWin(display_text="ベースのプログレスバー" ,max=5)
time.sleep(1)
pw.update()
time.sleep(1)
pw.update("プログレスバー1つ追加するよ")
time.sleep(1)
test()
pw.update("ベースのプログレスバー")
time.sleep(1)
pw.update("プログレスバー2つ追加するよ")
time.sleep(1)
test2()
pw.update()
time.sleep(1)
pw.reset("リセットもできる")
time.sleep(2)
pw.kill()
PySideでGUI作りたいけど、PySideというキーワードでググっても情報出てこない…
これ、どうやって勉強すればいいの…??
と思っていたんですが、「PyQtのコード観ればいいだったわ(`・ω・´)」という事に今更ながら気づいたので、メモ。
PythonのPyQtによるクロスプラットフォームGUIアプリ作成入門 - MyEnigma
PyQt QTreeWidget サンプル - T&T simple
Datの如く: [PyQt]QTreeView内にWidgetを配置
コノあたりのサンプルコードはちょっと変更するだけでMayaでも動作させられます。
from PyQt4 import QtGui, QtCore,Qt
となっている部分を以下の様に書き換えます(元の内容によって変わりますが。)
from PySide import QtCore, QtGui
次にクラスの定義部分。
class Example(QtGui.QWidget):
Mayaで表示させるために以下の様にします。
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin class Example(MayaQWidgetBaseMixin, QtGui.QWidget):
GUIの表示部分
app = QtGui.QApplication(sys.argv) ex = Example() sys.exit(app.exec_())
こんな感じに。
app = QtGui.QApplication.instance() Example() sys.exit() app.exec_()
後ろ二つについては以前の記事とおなじですね。
MOCHI-MOCHI 【MAYA】Maya2015からはshiboken使わなくてもいいらしい
ただし、PyQtとPySideの差異もあるので考慮しなければならない部分もあるようです。
PySideとPyQtの差異 - None is None is None
しかし、これで色々と情報を入手できそうです!
# -*- coding: utf-8 -*-
from maya import cmds
from PIL import Image
import pymel.core as pm
import os
import stat
def get_shading_engines(root_node=None):
'''
指定ノード以下のshading_engineの重複しないリストを取得
'''
en_list = []
if root_node is None:
shapes = pm.ls(type="mesh")
else:
if isinstance(root_node, (str, unicode)): root_node = pm.PyNode(root_node)
shapes = root_node.listRelatives(ad=True, type="mesh")
file_nodes = []
for i in shapes:
shading_engines = i.shadingGroups()
en_list+=shading_engines
#重複をなくしてから戻す
return list(set(en_list))
def get_all_texture_node(root_node=None):
'''
指定ノード以下に接続されている全テクスチャノードを取得
'''
file_nodes = []
en_list = get_shading_engines(root_node)
for en in en_list:
file_nodes.extend(cmds.ls(cmds.listHistory(en.name()),type='file'))
return list(set(file_nodes))
def get_truth_file_path(filepath, dir):
'''
パスの存在をしらべる。なければセットプロジェクトされているフォルダ以下にないか探しにいく。
'''
if os.path.exists(filepath):
return filepath
workpath = pm.workspace( q=True, rootDirectory=True )
if dir is not None:
workpath = workpath + dir
filename = os.path.basename(filepath)
for root, dirs, files in os.walk(workpath):
for file in files:
if filename == file:
return root + r"/" +file
return filepath
def get_use_texture_path_list(root_node=None):
'''
指定ノード以下に接続されているテクスチャパスのリスト
'''
file_nodes = get_all_texture_node(root_node)
files = []
for tex in file_nodes:
path = cmds.getAttr(tex + '.fileTextureName')
truth_path= get_truth_file_path(path, "sourceimages")
if truth_path is None:continue;
files.append(truth_path)
files = list(set(files))
return files
def set_texture_to_specified_dir(root_node=None, dir=""):
'''
指定ノード以下に接続されているテクスチャを指定のディレクトリに接続し直す
'''
file_nodes = get_all_texture_node(root_node)
for tex in file_nodes:
def_path = cmds.getAttr(tex + '.fileTextureName')
base_name = os.path.basename(def_path)
new_path = os.path.join(dir, base_name)
if os.path.isfile(new_path):
cmds.setAttr(tex + '.fileTextureName', new_path, type='string')
def resize_texture(root_node=None, dir="", magnification=1, width=None, height=None):
'''
指定ノード以下のテクスチャをリサイズ(別フォルダに出力)
画像幅と高さが両方していされてればそっち優先
root_node : テクスチャ書き出すルートノード
export_dir : 書き出すフォルダ
magnification : テクスチャの倍率
width : 画像幅
height: 画像高さ
'''
files = get_use_texture_path_list(root_node)
if os.path.exists(dir) == False:
os.makedirs(dir)
# ペースト先のファイルが読み取り専用だった場合エラーになるので対処しとく
for f in files:
dir_path, file_name = os.path.split(f)
save_file_path = dir+'\\'+file_name
if os.path.exists(save_file_path):
os.chmod(save_file_path, stat.S_IWRITE)
im = Image.open(f)
w = int(im.size[0]) * magnification
h = int(im.size[1]) * magnification
if width is not None and height is not None:
w = width
h = height
im.resize((int(w),int(h))).save(save_file_path)
set_texture_to_specified_dir(root_node=root_node, dir=dir)
resize_texture(root_node='root', dir=r'C:\temp\test', magnification=0.1)
Mayaのシーンファイル(Maya Ascii)をMayaに読み込まずに直接情報を取得します。
## -*- coding: utf-8 -*-
import os
import re
class Node(object):
def __init__(self, path, nodetype):
self.path = path
self.nodetype = nodetype
def _get_value(self, param, stg):
'''
-n "hogehoge" のhogehoge部分を取得
'''
pattern = param + ' "(.+?)"'
matchedList = re.findall(pattern, stg)
if len(matchedList) is 0:
return ''
pattern = '^' + param + ' "|"$'
return re.sub(pattern, '', matchedList[0])
def _get_node_name(self, stg):
return self._get_value('-n', stg)
def _get_parent(self, stg):
return self._get_value('-p', stg)
def search(self):
list = []
fil = "createNode " + self.nodetype
f = open(self.path)
line = self._read(f)
while line:
if fil not in line:
line = self._read(f)
continue
#目的のタイプのノードを発見
nd = NodeData()
nd.name = self._get_node_name(line)
nd.parent = self._get_parent(line)
#attr
line = self._read(f)
while re.match('setAttr' , line) is not None:
at = self._disassembly_setattr_data(line)
nd.attr[at.name] = at
line = self._read(f)
list.append(nd)
f.close()
return list
def _disassembly_setattr_data(self, stg):
'''
setAttrの文字列を分解する
'''
attr = AttrData()
#アトリビュート名
attr.name = re.findall('"\..+?"', stg)
if len(attr.name) > 0:
attr.name = re.sub('"\.|"', '', attr.name[0])
#タイプ
attr.type = re.findall('-type ".+?"', stg)
if len(attr.type) > 0:
attr.type = re.sub('-type "|"', '', attr.type[0])
else:
attr.type = ''
#値(多分末尾に書かれてる)
attr.value = re.sub('^.+ |"|;', '', stg)
attr.value = attr.value.strip()
return attr
def _read(self, file):
'''
;までを1行として読み込む
strip()で先頭と末尾の空白文字(改行・タブなどなど)が簡単に取り除けるらしいよ。
'''
line = file.readline().strip()
while line[-1:] != ';':
l = file.readline().strip()
#EOF
if l == '':
break
line = line + l
return line
class NodeData(object):
'''
ノードデータ
'''
def __init__(self):
self.name = ''
self.parent = ''
self.attr = {}
class AttrData(object):
'''
アトリビュートデータ
'''
def __init__(self):
self.value = ''
self.name = ''
self.type = ''
とりあえず新規シーンをMaya Asciiで保存します。
今回のコードは自分の必要な部分だけなので、取得できるのはノードの情報のみです。
使い方は以下のような感じ。
nodes = Node(r'c:\test.ma', 'camera').search()
これでシーン内のカメラの情報を取得します。
情報をprint文で書き出してみましょ。
4 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [node name]perspShape [parent node]persp [attr name]ncp [value]10 [type] [attr name]imn [value]persp [type]string [attr name]den [value]persp_depth [type]string [attr name]v [value]no [type] [attr name]coi [value]180.75837217595105 [type] [attr name]hc [value]%camera [type]string [attr name]fl [value]128.07659939244272 [type] [attr name]man [value]persp_mask [type]string =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [node name]topShape [parent node]top [attr name]ncp [value]10 [type] [attr name]o [value]yes [type] [attr name]rnd [value]no [type] [attr name]ow [value]30 [type] [attr name]den [value]top_depth [type]string [attr name]v [value]no [type] [attr name]coi [value]100.1 [type] [attr name]hc [value]%camera [type]string [attr name]imn [value]top [type]string [attr name]man [value]top_mask [type]string =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [node name]frontShape [parent node]front [attr name]ncp [value]10 [type] [attr name]o [value]yes [type] [attr name]rnd [value]no [type] [attr name]ow [value]30 [type] [attr name]den [value]front_depth [type]string [attr name]v [value]no [type] [attr name]coi [value]100.1 [type] [attr name]hc [value]%camera [type]string [attr name]imn [value]front [type]string [attr name]man [value]front_mask [type]string =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [node name]sideShape [parent node]side [attr name]ncp [value]10 [type] [attr name]o [value]yes [type] [attr name]rnd [value]no [type] [attr name]ow [value]30 [type] [attr name]den [value]side_depth [type]string [attr name]v [value]no [type] [attr name]coi [value]100.1 [type] [attr name]hc [value]%camera [type]string [attr name]imn [value]side [type]string [attr name]man [value]side_mask [type]string