【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