はじめに
Mayaには標準のマテリアルが用意されていますが、自作シェーダーを使うと、標準機能だけでは難しい表現や、制作目的に合わせた独自の描画処理を実装できます。
この記事では、Mayaのソフトウェアレンダリングに対応した自作シェーダーを、Python Plug-inとして作成する手順を解説します。(この記事ではシェーダーの中身についてはほとんど触れません。)
「Mayaで自作シェーダーを使う」シリーズの他の記事はこちらです。
Pythonファイルの用意
拡張子を .py にしたPythonファイルを用意します。
以下は、デフォルト値が赤単色のシンプルなサンプルシェーダーです。
通常のノードプラグインを作成する場合とほぼ同じ構造です。主な違いは以下の2点です。
registerNodeの引数に"shader/surface:drawdb/shader/surface/..."を指定するoutColorアトリビュートを作成する必要がある
必要な情報をアトリビュートとして受け取り、compute メソッド内で自由に出力色を計算します。
パスを通す
任意のフォルダにプラグインパスを通します。たとえば、C:\Users\<ユーザー名>\Documents\maya\<バージョン>\Maya.env に以下を追記します。右辺にはパスを通したい任意のディレクトリを指定でき、セミコロンで区切って複数設定できます。
ファイル名: Maya.env
MAYA_PLUG_IN_PATH=C:\Users\<user名>\Documents\maya\2025\plug-ins;
他にも、.mod ファイル等を用意してパスを通す方法もあります。
パスを通したディレクトリの直下に、用意した .py ファイルを配置してください。
Plug-inの読み込み
Mayaを起動します。正しくパスが通っていれば、Plug-in Managerに sampleShader.py が追加されているので、「Loaded」にチェックを入れます。
※ パスを通さなくても、左下の「Browse」ボタンから任意のディレクトリのプラグインを読み込むことも可能です。

レンダリング
プラグインが正しく読み込まれていれば、ノード作成画面に自動で SampleShader が追加されています。作成してオブジェクトに割り当てます。

レンダービューを開き、Maya Softwareでレンダリングします。

inColor アトリビュートの値を変更すると、出力色が変わります。
補足: ライト情報の取得
MPxSurfaceShadingNodeOverride を使用することで、ビューポート2.0での表示にはHLSLやGLSLを使いつつ、Maya Softwareに対応するマテリアルを作成することもできます。
また、シーンのライト情報は以下のように取得できます。
light情報の取得(initialize内)
def initialize():
:
:
n_attr = om.MFnNumericAttribute()
SampleShader.light_dir = n_attr.createPoint('lightDirection', 'ld')
n_attr.storable = False
n_attr.writable = False
n_attr.hidden = True
n_attr.default = (1.0, 1.0, 1.0)
SampleShader.light_intensity = n_attr.createColor('lightIntensity', 'li')
n_attr.storable = False
n_attr.writable = False
n_attr.hidden = True
n_attr.default = (1.0, 1.0, 1.0)
SampleShader.light_ambient = n_attr.create('lightAmbient', 'la', om.MFnNumericData.kBoolean)
n_attr.storable = False
n_attr.writable = False
n_attr.hidden = True
SampleShader.light_diffuse = n_attr.create('lightDiffuse', 'ldf', om.MFnNumericData.kBoolean)
n_attr.storable = False
n_attr.writable = False
n_attr.hidden = True
SampleShader.light_specular = n_attr.create('lightSpecular', 'ls', om.MFnNumericData.kBoolean)
n_attr.storable = False
n_attr.writable = False
n_attr.hidden = True
SampleShader.light_sdw_fraction = n_attr.create('lightShadowFraction', 'lsf', om.MFnNumericData.kFloat)
n_attr.storable = False
n_attr.writable = False
n_attr.hidden = True
SampleShader.pre_sdw_intensity = n_attr.create('preShadowIntensity', 'psi', om.MFnNumericData.kFloat)
n_attr.storable = False
n_attr.writable = False
n_attr.hidden = True
SampleShader.light_blind_data = n_attr.createAddr('lightBlindData', 'lbld')
n_attr.storable = False
n_attr.writable = False
n_attr.hidden = True
l_attr = om.MFnLightDataAttribute()
SampleShader.light_data = l_attr.create(
'lightDataArray', 'ltd',
SampleShader.light_dir,
SampleShader.light_intensity,
SampleShader.light_ambient,
SampleShader.light_diffuse,
SampleShader.light_specular,
SampleShader.light_sdw_fraction,
SampleShader.pre_sdw_intensity,
SampleShader.light_blind_data
)
l_attr.array = True
l_attr.storable = False
l_attr.hidden = True
l_attr.default = ( (1.0, 0.0, 0.0), (0.0, 0.0, 0.0), True, True, False, 0.0, 1.0, 1)
om.MPxNode.addAttribute(SampleShader.light_data)
om.MPxNode.attributeAffects(SampleShader.light_dir, SampleShader.out_color)
om.MPxNode.attributeAffects(SampleShader.light_intensity, SampleShader.out_color)
om.MPxNode.attributeAffects(SampleShader.light_ambient, SampleShader.out_color)
om.MPxNode.attributeAffects(SampleShader.light_diffuse, SampleShader.out_color)
om.MPxNode.attributeAffects(SampleShader.light_specular, SampleShader.out_color)
om.MPxNode.attributeAffects(SampleShader.light_sdw_fraction, SampleShader.out_color)
om.MPxNode.attributeAffects(SampleShader.pre_sdw_intensity, SampleShader.out_color)
om.MPxNode.attributeAffects(SampleShader.light_blind_data, SampleShader.out_color)
om.MPxNode.attributeAffects(SampleShader.light_data, SampleShader.out_color)
light情報の使用(compute内)
def compute(self, plug, block):
:
:
light_data = block.inputArrayValue( SampleShader.light_data )
for _ in range(len(light_data)):
current_light = light_data.inputValue()
light_intensity = current_light.child( SampleShader.light_intensity ).asFloatVector()
light_dir = current_light.child( SampleShader.light_dir).asFloatVector()
is_diffuse = current_light.child(SampleShader.light_diffuse).asBool()
is_ambient = current_light.child(SampleShader.light_ambient).asBool()
is_specular = current_light.child(SampleShader.light_specular).asBool()
blind_data = current_light.child( SampleShader.light_blind_data ).asAddr()
if not light_data.next(): break
:
:
その他、既定のアトリビュート名にすることで、カメラ情報なども受け取ることができます。アトリビュート名の詳細は Mayaの開発者ヘルプ を参照してください。
まとめ
Python Plug-inとしてシェーダーを作成すれば、Maya Softwareレンダリングに対応した自作マテリアルを実装できます。通常のノードプラグインとの違いは registerNode の分類指定と outColor アトリビュートの追加だけなので、ノードプラグインの作成経験がある方ならスムーズに取り組めるはずです。
ビューポート2.0とMaya Softwareの両方に対応したい場合は、MPxSurfaceShadingNodeOverride と組み合わせることで、HLSLやGLSLのビューポート表示とソフトウェアレンダリングを同時にサポートできます。



コメント