簡単なPySideプログラム
# -*- coding: utf-8 -*- import maya.cmds as cmds import maya.mel as mel from PySide.QtCore import * from PySide.QtGui import * from shiboken import wrapInstance from maya import OpenMayaUI as omui from maya.app.general.mayaMixin import MayaQWidgetBaseMixin from pprint import pprint import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx mayaMainWindowPtr = omui.MQtUtil.mainWindow() mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QWidget) class CreatePolygonUI(QWidget): def __init__(self, *args, **kwargs): super(CreatePolygonUI, self).__init__(*args, **kwargs) #Parent widget under Maya main window self.setParent(mayaMainWindow) self.setWindowFlags(Qt.Window) #Set the object name self.setObjectName('CreatePolygonUI_uniqueId') self.setWindowTitle('Create polygon') self.setGeometry(50, 50, 250, 150) self.initUI() self.cmd = 'polyCone' def initUI(self): #Create combo box (drop-down menu) and add menu items self.combo = QComboBox(self) self.combo.addItem( 'Cone' ) self.combo.addItem( 'Cube' ) self.combo.addItem( 'Sphere' ) self.combo.addItem( 'Torus' ) self.combo.setCurrentIndex(0) self.combo.move(20, 20) self.combo.activated[str].connect(self.combo_onActivated) #Create 'Create' button self.button = QPushButton('Create', self) self.button.move(20, 50) self.button.clicked.connect(self.button_onClicked) #Change commmand string when combo box changes def combo_onActivated(self, text): self.cmd = 'poly' + text + '()' #Execute MEL command when button is clicked def button_onClicked(self): mel.eval( self.cmd ) class HelloWorld(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self, argList): ui = CreatePolygonUI() ui.show() return def creator(): return OpenMayaMPx.asMPxPtr( HelloWorld() ) def initializePlugin(obj): plugin = OpenMayaMPx.MFnPlugin(obj, 'plugin', '1.0', 'Any') try: plugin.registerCommand('helloWorld', creator) except: raise RuntimeError def uninitializePlugin(obj): plugin = OpenMayaMPx.MFnPlugin(obj) try: plugin.deregisterCommand('helloWorld') except: raise RuntimeError
プラグインとしてロードして、MELスクリプトからhelloWorldで呼び出すと、ダイアログが表示されプリミティブを作れます。
Lightwaveでボタンとボタンイベントを作る
簡単なボタンコントロールの作り方。
RESOURCE = '\04(k:"%s" c:LWPy)' class HelloClass(lwsdk.IGeneric): def __init__(self, context): super(HelloClass, self).__init__() def func(self,ctl,data): ... def process(self, ga): ui = lwsdk.LWPanels() panel = self.ui.create(RESOURCE % 'test') btn1 = self.panel.button_ctl(RESOURCE % 'button label') btn1.set_event(self.func) panel.align_controls_vertical([btn1]) if panel.open(lwsdk.PANF_BLOCKING | lwsdk.PANF_CANCEL) == 0: ui.destroy(self.panel) return lwsdk.AFUNC_OK return lwsdk.AFUNC_OK
ボタンのサンプルが無かったので。
Lightwaveで外部のモジュールを使いたい。
LightwaveのGUIにPySideを使いたい、というモチベーションで調査開始。
LightwaveのPythonは環境パスのPythonではなく、
C:\Program Files\NewTek\LightWave_2015.2J\bin
(環境によるので注意)にあるdllを呼んでいるっぽい。
PySideを使おうと思ったのだけれど、当然入っていない。
LightwaveのPythonと本体にインストールされているPythonのバージョンが厳密に一致している必要がある。
LightwaveのPythonのバージョンは最初にLayoutツールを起動して、Utilities-Python-Open Consoleでウィンドウ起動したときの、一行目に出てくる。2015.2(64bit)版を利用している私の場合はPython2.7.7であった。
この2.7.7であることが重要で、3.4がNGなことは当然として2.7.11でもだめである。
2.7.10以降?ではpipがデフォルトインストールだが、2.7.7では入っていないため
https://pip.pypa.io/en/latest/installing/
よりget_pip.pyをダウンロード、
python get_pip.py
でpipのインストール。
一番わかりやすいnumpyをLightwave上から呼べるようにする。
pip install numpy
で、numpyのインストール。するとC:\Python27\Lib\site-packages\numpyにインストールされる。
このsite-packagesディレクトリには、Pythonのバージョンが一致している限りはLightwaveから参照されているため、Consoleからnumpyを呼び出してもちゃんと動くことが確認できる。
PySideについて
うまくいかない。pip install PySideで、PySideがインストール
import sys from PySide.QtGui import * from PySide.QtCore import * app = QApplication(sys.argv) # Create a Label and show it label = QLabel("Hello World") label.show() # Enter Qt application main loop app.exec_()
をPythonコンソールで試してみると
QtGUIコマンドを実行したところでLayoutツールがフリーズを起こす。
PySideはあきらめたほうがよさそう。。。
LightwaveのPythonプラグイン
LightwaveのPluginをPythonで作ってみている。
import lwsdk __lwver__ = "11" class hello_world(lwsdk.IGeneric): def __init__(self, context): super(hello_world, self).__init__() def process(self, generic_access): ui = lwsdk.LWPanels() panel = ui.create('Test') if panel.open(lwsdk.PANF_BLOCKING | lwsdk.PANF_CANCEL) == 0: ui.destroy(panel) return lwsdk.AFUNC_OK ui.destroy(panel) return lwsdk.AFUNC_OK ServerTagInfo = [ ( "Python Hello World!", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ), ( "Hello, World!", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH ), ( "Utilities/Python", lwsdk.SRVTAG_MENU | lwsdk.LANGID_USENGLISH )] ServerRecord = { lwsdk.GenericFactory("LW_PyHelloWorld", hello_world) : ServerTagInfo }
[Utilities]タブの[Plugins]-[Add Plugins]で上記のPythonスクリプトを読み込む。
[Plugins]-[Adittional]に"Python Hello World!"というものが一番下?に追加されているので、呼び出すと、OKとCancelボタンがあるダイアログが表示される。
Inspectorにconstな変数を表示したい。
class Global : MonoBehaviour{ const float fVariables = 1.0f; }
のような定数をInspectorで調整したい。でも、プログラムからは変更できないようにしたい。
みたいな状況が起こったのでどうしようかいろいろ考えた。
そもそもInspector上でconstな変数やstaticな変数は表示できない。プロパティの編集もできない。
publicやprivateな変数しか現状はInspector上でいじれない、ということである。
余談ではあるが、プロパティをInspector上で編集させてくれ、という要望も却下されてしまったようである。
staticなパラメータをInspector上で編集できるようにするにはSingletonにすればよいらしい。
しかし、何も考えずにC++的なSingletonを実装したところ、MonoBehaviourはnewが禁止されていることが発覚。結構ここではまる人は多いようである。
で、調べたところ
http://naichilab.blogspot.jp/2013/11/unitymanager.html
のように実装すればいけることがわかった。
試したところ、無事うまくいった。
まとめ
public class SingletonMonoBehaviour<T> : MonoBehaviour where T : MonoBehaviour { private static T instance; public static T Instance { get { if (instance == null) { instance = (T)FindObjectOfType(typeof(T)); if (instance == null) { Debug.LogError(typeof(T) + "is nothing"); } } return instance; } } } class Global : SingletonMonoBehaviour<Global> { public float VARIABLES = 0.0f; }
してHierarchy上に空のGameObjectを配置、Globalをコンポーネントとして追加すれば、VARIABLESがインスペクターに表示されるはずである。
スクリプトから呼ぶときは
float variable = Global.Singleton.VARIABLES;
となる。
とはいえ、結局Instance経由で変数の変更はできてしまうので、staticではあってもconstではない状況。
なにかいい方法はないものか。。。