Maya API のラッパ(wrapper)、イテレータ、関数セット クラスを使用する基本的なスクリプトを作成できます。これらのスクリプトは、Maya モデルを照会し操作することはできますが、Maya に完全に統合されているわけではありません。スクリプト プラグインは、Maya に強固に統合された、より複雑なソリューションを提供します。このセクションでは、基本のスクリプト、スクリプト プラグイン、そしてスタンドアローン型スクリプトを作成する方法について説明します。
Maya Python API は Python ベースの API なので、Python の知識が必要です。
Maya Python API は、いくつかの Python モジュールに内蔵されています。作成するスクリプトで使用する機能を読み込む必要があります。また、Maya Python API は Maya ネームスペース内に存在します。したがって、追加のプリフィックスが必要です。OpenMaya モジュールを読み込むには次を実行します。
import maya.OpenMaya
help コマンドを使用して、任意のモジュールまたはクラスについての情報を表示できます。たとえば、MVector についてのクラス情報を表示する場合、次を使用します。
Maya Python API モジュールには、Python プログラミングで使用可能なクラスが含まれています。これらのクラスは異なるカテゴリに分類され、その関連を示すための適切な命名規則を持っています。クラスには次のような種類があります。
このクラスはイテレータで、MObject に対して演算を行う関数セットとほとんど同じように動作します。たとえば MItCurveCV は、個々の NURBS カーブの CV に対して個別に(MFnNurbsCurveCV は存在しません)、あるいは繰り返し実行することでカーブのすべての CV に対して演算を行うために使用されます。
これらのクラスのほとんどは「ラッパ(wrapper)」ですが、それ以外もあります。このクラスの例には、MVector、MIntArray などがあります。
ラッパ クラスと関数セット クラスを使用して、次のようなスクリプトを作成できます。
import maya.OpenMaya vector1 = maya.OpenMaya.MVector(0,1,0) vector2 = maya.OpenMaya.MVector(1,0,0) vector3 = maya.OpenMaya.MVector(0,0,2) newVector = vector1 + vector2 + vector3 print "newVector %f, %f, %f " % (newVector.x, newVector.y, newVector.z)
import コマンドを修正して、使用されているシンボル名を短くすることが可能です。
import maya.OpenMaya as OpenMaya vector1 = OpenMaya.MVector(0,1,0)
スクリプトは、Maya Python API クラスを使用してディペンデンシー グラフの情報にアクセスすることができます。次のスクリプトでは、persp ノードを検索し、その translateX アトリビュート値を出力します。
# import the OpenMaya module import maya.OpenMaya as OpenMaya # function that returns a node object given a name def nameToNode( name ): selectionList = OpenMaya.MSelectionList() selectionList.add( name ) node = OpenMaya.MObject() selectionList.getDependNode( 0, node ) return node # function that finds a plug given a node object and plug name def nameToNodePlug( attrName, nodeObject ): depNodeFn = OpenMaya.MFnDependencyNode( nodeObject ) attrObject = depNodeFn.attribute( attrName ) plug = OpenMaya.MPlug( nodeObject, attrObject ) return plug # Find the persp camera node print "Find the persp camera" perspNode = nameToNode( "persp" ) print "APItype %d" % perspNode.apiType() print "APItype string %s" % perspNode.apiTypeStr() # Print the translateX value translatePlug = nameToNodePlug( "translateX", perspNode ) print "Plug name: %s" % translatePlug.name() print "Plug value %g" % translatePlug.asDouble())
スクリプト プラグインは、Maya に強固に統合されたソリューションの作成を可能にします。スクリプト プラグインにより開発者はコマンドのアンドゥ、Maya シーン ファイルへの適切な requires 行の構築などの機能をサポートすることができます。スクリプト プラグインを使用するもう 1 つの利点は、MEL と Python の両方で機能を使用きることです。
Maya プラグイン マネージャ(Plug-in Manager)が拡張され、スクリプト プラグインのロードとアンロードがサポートされるようになりました。
MAYA_PLUG_IN_PATH 上にあり、.py 拡張子で終わるファイルが、プラグイン マネージャ(Plug-in Manager)に表示されます。ロード(Loaded)チェック ボックスまたは自動ロード(Auto Load)チェック ボックスのどちらかを選択して、スクリプト プラグインをロードまたは自動ロードします。
プラグインは、プラグイン マネージャ(Plug-in Manager)から、または MEL あるいは Python のコマンド タブからロードできます。MEL では、loadPlugin() コマンドを使用します。Python では、maya.cmds.loadPlugin() コマンドを使用します。
helixCmd.py などのサンプルを実行するには、プラグインをロードし、Python エディタ(Python Editor)のタブに次を入力します。
import maya maya.cmds.spHelix().
この Python スクリプトを起動すると、次が実行されます。
このプラグインは、Python コマンド maya.cmds.unloadPlugin (「helixCmd.py」) を使用してもアンロードできます。
ロードと実行の手順は、MEL エディタ内でも次を使用して起動できます。
loadPlugin helixCmd.py; spHelix();
スクリプト プラグインの作成には、プラグイン内で専用の関数を定義することが必要です。スクリプト プラグインは次を行う必要があります。
以下のセクションで、これらの項目についてサンプルとともに詳しく説明します。
Python は import キーワードを使用して、機能をモジュールからスクリプトにインクルードします。例:
import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys
スクリプト プラグインが複数のファイルに分割されていてもかまいません。import コマンドは、2 次ファイルの機能をスクリプト プラグインにロードするために使用します。
import polyModifier
スクリプト プラグインがロードされると、Maya は定義内の initializePlugin() 関数を検索します。この関数にすべてのプロキシ ノードが登録されます。
# Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) raise
initializePlugin() 関数が見つからない場合、スクリプト プラグインのロードは失敗します。また、ロード時、Maya は uninitializePlugin() 関数も検索します。これが見つからない場合、スクリプト プラグインのロードは失敗します。
Maya では、プラグインのアンロード試行時にあらかじめ見つけておいた uninitializePlugin() 関数がコールされ、プラグインのリソースがアンロードされます。
def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) raise
クリエータ関数は、派生したバージョンのプロキシ クラスを Maya に返すために使用します。バーチャル メソッドが Maya からコールする派生クラスに実装されます。以下は、クラス定義とクリエータ関数の例です。
class scriptedCommand(OpenMayaMPx.MPxCommand): # ... def cmdCreator(): return OpenMayaMPx.asMPxPtr( scriptedCommand() )
新しく作成したプロキシ オブジェクト上で OpenMayaMPx.asMPxPtr() をコールすることが非常に重要です。このコールにより、オブジェクトの所有権が Python から Maya に移行します。このコールを行わなければ、Python でこのオブジェクトの参照が解除され破棄されることがあるため、プログラム エラーが発生します。これにより、Maya にダングリング ポインタが残ります。
プロキシ クラスの実装には、Maya Python API オブジェクトからの派生が必要です。
class scriptedCommand(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self,argList): print "Hello World!"
scriptedCommand クラスは、OpenMayaMPx.MPxCommand から派生します。コンストラクタまたは __init__ メソッドは、親クラスの __init__ メソッドをコールする必要があります。すべてのクラス メソッドには、1 番目のパラメータとして self が必要です。この後、通常の引数リストが続きます。このコマンドの doIt() メソッドは「Hello World!」と出力します。
初期化関数は、MPxNode クラスを使用して新しいプロキシ ノードを定義するスクリプト プラグイン内で使用します。次は、その出力がサイン関数である単純なスクリプト プラグイン ノードを作成する方法を示すサンプルです。
import math, sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx kPluginNodeTypeName = "spSineNode" sineNodeId = OpenMaya.MTypeId(0x8700) # Node definition class sineNode(OpenMayaMPx.MPxNode): # class variables input = OpenMaya.MObject() output = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) def compute(self,plug,dataBlock): if ( plug == sineNode.output ): dataHandle = dataBlock.inputValue( sineNode.input ) inputFloat = dataHandle.asFloat() result = math.sin( inputFloat ) * 10.0 outputHandle = dataBlock.outputValue( sineNode.output ) outputHandle.setFloat( result ) dataBlock.setClean( plug ) # creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( sineNode() ) # initializer def nodeInitializer(): # input nAttr = OpenMaya.MFnNumericAttribute() sineNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) # output nAttr = OpenMaya.MFnNumericAttribute() sineNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) nAttr.setWritable(1) # add attributes sineNode.addAttribute( sineNode.input ) sineNode.addAttribute( sineNode.output ) sineNode.attributeAffects( sineNode.input, sineNode.output ) # initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, sineNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( sineNodeId ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise
nodeInitializer() 関数は、initializePlugin() 関数内で registerNode() に渡されます。プラグインのロード時、Maya では nodeInitializer() 関数がコールされてノードのアトリビュートが作成されます。
Maya Python APIでは、スクリプトの状態の照会と設定に Python の例外を使用します。ほとんとのケースでは、あるメソッドに戻り値があるとクラスのマニュアルに示されていても、例外が使用されます。例外が発生しうる状況にはいろいろあります。
def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( sineNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise
この例では、deregisterNode() コールが失敗した場合、uninitializePlugin() コールは Maya に例外を返してプラグインのアンロードが失敗します。
このコードを修正してエラーをキャッチし、deregisterNode() コールが失敗した場合でもプラグインのアンロードを許可することができます。
def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( sineNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) pass
唯一の違いは、raise キーワードが pass に変更されたことです。この技法は、正しくないオブジェクトを審査した場合に失敗するイテレータ コードを作成する場合に便利です。
Maya Python API では、不明なパラメータ戻り値を使用してメソッドが特定のケースを処理できないことを示します。この操作を処理するかどうかは、コール元が決定します。このようなメソッドのひとつに MPxNode::compute() があります。この状況では、Python コードは OpenMaya.kUnknownParameter を返します。
前のセクションで説明したとおり、Maya Python API では、ステータス情報をやり取りするために、MStatus の値ではなく例外が使用されます。C++ ドキュメントから API メソッドの Python 的な動作を推測する場合、下記のルールが適用されます。
C++ API メソッドが MStatus 値を返す方法には、メソッドの返り値として返す方法と、
MStatus someMethod(Type arg1, Type arg2, ...)
パラメータ リストの MStatus 変数(通常、最後のパラメータ)へのオプション ポインタとして返す方法の 2 通りがあります。
Type someMethod(Type arg1, Type arg2, ..., MStatus* ReturnStatus = NULL)
メソッドが関数値として MStatus を返す場合、この戻り値は Python で次のように処理されます。
MS::kUnknownParameter を特別に処理するのは、MPxNode::compute() に対応するためです。
API 固有の特別な例外はありません。Maya は単に Python の標準 RuntimeError を使用し、エラー文字列を引数として渡します。
API メソッドがパラメータ リストのポインタ変数を通じて MStatus を返す場合、この MStatus は次のように処理されます。
つまり、C++ 言語でプラグインを記述する場合に、コードを呼び出しているのが C++ であるか Python であるかに関係なく、これまでどおり MStatus コードを返すことができます。Maya は必要に応じて、これらのコードを Python 例外に変換します。
Python でプラグインを記述する場合は、MStatus 値を返すのではなく例外を発生させる必要があります。ただし、compute() メソッドでプラグを処理しないことを指示する場合を除きます。この場合、このメソッドは maya.OpenMaya.kUnknownParameter を返します。
すべての番号配列(MIntA ray、MUintArray、MUint64Array、MFloatArray、および MDoubleArray)は Python スタイルのスライシングをサポート。 たとえば、次のようになります。
import maya.OpenMaya as OpenMaya array = OpenMaya.MUintArray() for i in range(0,9): array.append( i ) array[2:8:2]
プロキシ クラスは、開発者に対し、使用されているノードについての標準的な情報を提供します。これには、ノードの定義に使用するアトリビュート オブジェクトが含まれます。Maya Python API でスタティック クラス MObject にアクセスするためには、類似のコードを使用できます。
envelope = OpenMayaMPx.cvar.MPxDeformerNode_envelope
このコール後、エンベロープは MPxDeformerNode::envelope の MObject になります。
Maya Python API では、メッセージ クラスをサポートしています。Python の関数が、コールバック用に渡されます。この関数は、コールバック メッセージが必要とするのとちょうど同じ数のパラメータを持つ必要があります。そうでない場合、メッセージ起動時に例外が発生し、コンソールに情報が書き出されます。ほとんどのメッセージと一緒に、Python オブジェクトの形式のクライアント データを渡すことができます。次はメッセージのサンプルです。
# Message callback def dagParentAddedCallback( child, parent, clientData ): print "dagParentAddedCallback..." print "\tchild %s" % child.fullPathName() print "\tparent %s" % parent.fullPathName() print "\tclient data %s" % clientData # Create the mesage def createParentAddedCallback(stringData): try: id = OpenMaya.MDagMessage.addParentAddedCallback( dagParentAddedCallback, stringData ) except: sys.stderr.write( "Failed to install dag parent added callback\n" ) messageIdSet = False else: messageIdSet = True return id # Call the message creator messageId = createParentAddedCallback( "_noData_" )
Python では、割り当てを使用する代わりにパラメータを修正するほうが適切です。 次のコードには割り当てが含まれており、その場合にどのようにエラーが発生しうるかを示します。
import maya.OpenMaya as OpenMaya def vectorTest(v): lv = OpenMaya.MVector(1,5,9) v = lv print "%g %g %g" % (v.x,v.y,v.z) v = OpenMaya.MVector() vectorTest(v) print "%g %g %g" % (v.x,v.y,v.z)
2 番目の print コマンドは(0,0,0)を出力します。Python で、パラメータ値を修正するかコードを作成して、新しい値が返されるようにします。次のように vectorTest() 関数を書き換えます。
def vectorTest(v): lv = OpenMaya.MVector(1,5,9) v.x = lv.x v.y = lv.y v.z = lv.z print "%g %g %g" % (v.x,v.y,v.z)
Maya Python API には、int&、char&、float& など、基本型へのリファレンスとなる値またはパラメータを返すコールがたくさんあります。Maya Python API では、すべてのリファレンスはポインタとして扱われます。結果として、これらの項目の値を作成、設定、アクセスするには、特別なコールが必要になります。
OpenMaya.py モジュールにあるMScriptUtil というユーティリティ クラスは、これらのタイプのパラメータで動作して値を返す手段を提供します。このクラスでは、データを作成してからそのデータへのポインタを取得してリファレンスを必要とするクラス メソッドに情報を渡すことができます。API Reference マニュアルの MScriptUtil を参照してください。
MScriptUtil の使用法については、以下の例を参考にしてください。MFnLattice.getDivisions() へのコールから x、y、z の値を取得する方法を示します。
import maya.OpenMaya as OpenMaya import maya.OpenMayaAnim as Anim xutil = OpenMaya.MScriptUtil() xutil.createFromInt(0) xptr = xutil.asUintPtr() yutil = OpenMaya.MScriptUtil() yutil.createFromInt(0) yptr = yutil.asUintPtr() zutil = OpenMaya.MScriptUtil() zutil.createFromInt(0) zptr = zutil.asUintPtr() it = OpenMaya.MItDependencyNodes(OpenMaya.MFn.kFFD) while not it.isDone(): latDefFn = Anim.MFnLatticeDeformer( it.thisNode() ) latFn = Anim.MFnLattice( latDefFn.deformLattice() ) latFn.getDivisions(xptr, yptr, zptr) x = xutil.getUint(xptr) y = yutil.getUint(yptr) z = zutil.getUint(zptr) doSomethingUseful(x, y, z) it.next()
getUint() は MScriptUtil のスタティック メソッドであるため、クラスから直接コールしても最終値を取得できます。たとえば、次のようになります。
x = OpenMaya.MScriptUtil.getUint(xptr)
フラグ付きコマンドは、MSyntax オブジェクトを使用して構文を指定し、MArgParser クラスまたは MArgDatabase クラスを使用してフラグを解析する必要があります。そうしないと、Python からコマンドを使用するときにフラグにアクセスできません。これは、Python と C++ のどちらで記述されたかに関係なく同じです。次は、フラグ付きコマンドを実装したプラグインの記述例です。
import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys, math kPluginCmdName="spHelix" kPitchFlag = "-p" kPitchLongFlag = "-pitch" kRadiusFlag = "-r" kRadiusLongFlag = "-radius" # command class scriptedCommand(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self, args): deg = 3 ncvs = 20 spans = ncvs - deg nknots = spans+2*deg-1 radius = 4.0 pitch = 0.5 # Parse the arguments. argData = OpenMaya.MArgDatabase(self.syntax(), args) if argData.isFlagSet(kPitchFlag): pitch = argData.flagArgumentDouble(kPitchFlag, 0) if argData.isFlagSet(kRadiusFlag): radius = argData.flagArgumentDouble(kRadiusFlag, 0) controlVertices = OpenMaya.MPointArray() knotSequences = OpenMaya.MDoubleArray() # Set up cvs and knots for the helix for i in range(0, ncvs): controlVertices.append( OpenMaya.MPoint( radius * math.cos(i), pitch * i, radius * math.sin(i) ) ) for i in range(0, nknots): knotSequences.append( i ) # Now create the curve curveFn = OpenMaya.MFnNurbsCurve() nullObj = OpenMaya.MObject() try: # This plugin normally creates the curve by passing in the # cv's. A function to create curves by passing in the ep's # has been added. Set this to False to get that behaviour. if True: curveFn.create( controlVertices, knotSequences, deg, OpenMaya.MFnNurbsCurve.kOpen, 0, 0, nullObj ) else: curveFn.createWithEditPoints(controlVertices, 3, OpenMaya.MFnNurbsCurve.kOpen, False, False, False) except: sys.stderr.write( "Error creating curve.\n" ) raise # Creator def cmdCreator(): # Create the command return OpenMayaMPx.asMPxPtr( scriptedCommand() ) # Syntax creator def syntaxCreator(): syntax = OpenMaya.MSyntax() syntax.addFlag(kPitchFlag, kPitchLongFlag, OpenMaya.MSyntax.kDouble) syntax.addFlag(kRadiusFlag, kRadiusLongFlag, OpenMaya.MSyntax.kDouble) return syntax # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject, "Autodesk", "1.0", "Any") try: mplugin.registerCommand( kPluginCmdName, cmdCreator, syntaxCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) raise
Maya Python API には、メソッドが所属するクラスからのみコールされるメソッドがいくつか含まれています。Maya では、この保護がメソッドに適用されることを示すため、Python の指定に従って _ を付加しています。MPxNode クラスに、このようなメソッドのサンプルがいくつかあります。
_forceCache() _setMPSafe()
API メソッドによっては、カスタム オブジェクトを派生クラスのインスタンスではなく、MPx ベース クラスのインスタンスとして返します。たとえば、MPxContext。_newToolCommand() はカスタム ツール コマンドを MPxToolCommand オブジェクトとして、MPxSurfaceShapeUI.surfaceShape() はカスタム サーフェス シェイプを MPxSurfaceShape オブジェクトとして返します。これらのベース インスタンスはオリジナルの派生インスタンスと同じ内部 Maya オブジェクトを参照しますが、派生インスタンスに設定されたメンバー変数の値をまったく保持しない個別の Python オブジェクトです。このため、返されたオブジェクトのメンバー変数をコールまたはアクセスすると、不正な結果が生じることがあります。
この問題は、OpenMayaMPx.asHashable() 関数のプロパティを利用して解決できます。OpenMayaMPx.asHashable() は MPx オブジェクトを取り、Maya の基本オブジェクトを一意に識別するハッシュ値を返します。これは、オブジェクトが MPx ベース クラスのインスタンスであるか派生クラスのインスタンスであるかには関係ありません。両方が Maya の基本オブジェクトを参照していれば、同じハッシュ値を返します。これにより、ベース インスタンスを該当する派生インスタンスに翻訳できる辞書を設定することができます。
class MoveToolCmd(OpenMayaMPx.MPxToolCommand): kTrackingDictionary = {}
このクラスの __init__ メソッドで、辞書にエントリを追加し、新しいオブジェクトのハッシュ値をオブジェクト自体にマッピングします。
def __init__(self): OpenMayaMPx.MPxToolCommand.__init__(self) MoveToolCmd.kTrackingDictionary[OpenMayaMPx.asHashable(self)] = self
クラスの __del__ メソッドで、ディクショナリから削除されたオブジェクトを除去します。
def __del__(self): del MoveToolCmd.kTrackingDictionary[OpenMayaMPx.asHashable(self)]
これでトラッキング ディクショナリができたので、これを利用して該当するベース オブジェクトから派生したオブジェクトを読み出すことができます。
class MoveContext(OpenMayaMPx.MPxSelectionContext): ... def doPress(self, event): # Create an instance of the move tool command. baseCmd = self._newToolCommand() derivedCmd = MoveToolCmd.kTrackingDictionary.get( OpenMayaMPx.asHashable(baseCmd), None ) # Call its methods. derivedCmd.setVector(0.0, 0.0, 0.0)
カスタム ノード タイプ(MPxNode、MPxSurfaceShape など)の定義には、追加作業が必要です。Maya でファイルを開く、または新規ファイルの操作を行うと、各ノードで __del__ method を実行しなければシーンが破損します。つまり、これらのノードのエントリはトラッキング ディクショナリからは削除されないということです。これを回避するには、initializePlugin メソッドでコールバックをセットアップし、ファイルのオープンと新規ファイルの作成のトラッキング ディクショナリをクリアする必要があります。
fileOpenCB = 0 fileNewCB = 0 def clearTrackingDictionaries(unused): MyNode.kTrackingDictionary = {} MySurfaceShape.kTrackingDictionary = {} def initializePlugin(plugin): ... fileOpenCB = OpenMaya.MSceneMessage.addCallback( OpenMaya.MSceneMessage.kBeforeOpen, clearTrackingDictionaries ) fileNewCB = OpenMaya.MSceneMessage.addCallback( OpenMaya.MSceneMessage.kBeforeNew, clearTrackingDictionaries ) ... } def uninitializePlugin(plugin): ... if fileOpenCB != 0: OpenMaya.MSceneMessage.removeCallback(fileOpenCB) fileOpenCB = 0 if fileNewCB != 0: OpenMaya.MSceneMessage.removeCallback(fileNewCB) fileNewCB = 0
Maya Python API の一部のメソッドでは、<iosteam> オペレーティング システム タイプが必要です。これは Python に含まれていないので、このようなタイプのオブジェクトの作成と使用を行うための MStreamUtils クラスが使用可能です。このクラスの使用法を示すサンプルについては、Developer Kit を参照してください。
サポートするすべてのプラットフォームで、OpenGL 機能をスクリプトで使用するためのラッパ(wrapper)クラス MGLFunctionTable を提供しています。このクラスへのリファレンスを取得するには、次のコードを使用します。
glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() glFT = glRenderer.glFunctionTable()
ネストされたイテレータを記述する場合、通常、外側のループで現在選択されている項目は、内側のループに渡されます。たとえば、MItSelectionList で現在選択されている項目は MItSurfaceCV イテレータに渡されます。内側のイテレータに、無効になった情報が保持されている場合には、ガベージ コレクションの問題が発生する可能性があります。この問題を回避するには、内側のループが完了したら、内側のイテレータをなし(None)にリセットします。この結果、外側のループを継続する前に、内側のイテレータの情報がリリースされます。現在選択されている項目をリビルドまたは更新している場合にはこれが重要です。
ラッパ クラスと関数セットを使用して Maya モデルを修正するためのスタンドアローン型スクリプトを作成できます。このスクリプトはコマンドラインから実行します。単純なスタンドアローン型「hello world」スクリプトは次のとおりです。
import maya.standalone import maya.OpenMaya as OpenMaya import sys def main( argv = None ): try: maya.standalone.initialize( name='python' ) except: sys.stderr.write( "Failed in initialize standalone application" ) raise sys.stderr.write( "Hello world! (script output)\n" ) OpenMaya.MGlobal().executeCommand( "print \"Hello world! (command script output)\\n\"" ) maya.standalone.uninitialize() if __name__ == "__main__": main()
スタンドアローン型スクリプトが初期化された後、Maya コマンドと API クラスを使用して Maya モデルの作成や修正をすることができます。終了後、スタンドアローンは非初期化され、その後に Maya がクリーンアップできるようになります。initialize()を呼び出す前、または uninitialize()を呼び出した後に Maya コマンドまたは API クラスの使用を試みないでください。その場合、動作が不安定になる可能性があります。
スタンドアローン スクリプトの実行では、Maya と共に提供される Python 実行可能ファイルを使用する必要があります。たとえば、次のようになります。