先日、昔から使われてきた配布スクリプトを新しい3ds Maxで動かそうとしたらエラーが出ました。中身は.mse(暗号化形式)なので直すこともできない。ひと昔前なら「諦めて手作業」でしたが、今は選択肢があります——AIに仕様を伝えて、自作してしまうことです。実際このツールは半日ほどのやり取りで自作版に置き換わりました。
とはいえ、バイブコーディング入門でも触れたとおり、MAXScriptはAIがいちばん苦手とする言語です。ありそうで存在しない関数を返す、他言語の文法を混ぜる——ということが体感で明らかに多い。それでも実務のツールを任せられているのは、やり方を変えたからです。結論から言うと「いかに正しい情報を渡すか」に尽きます。この記事では、私が実際にAIとMAXScriptツールを作ってきたやり取り(エラーも失敗もそのまま)を材料に、渡すべき情報と渡し方の型を整理します。
その前に:既存のスクリプトがないか探す
AIで自作する前に、まずやるべきことがあります。同じことをするスクリプトが、すでに世の中に無いかを探すことです。3ds Maxの繰り返し作業の多くは、すでに誰かが解決してツールにしています。無料スクリプトならScriptSpotが定番の集積地で、ほかにGumroadやArtStation、Autodesk App Storeなどでも配布されています。
既にあって問題なく動くなら、それを使うのが一番速いですし、作者がテストを重ねた分だけ安定しています。わざわざ車輪の再発明をする必要はありません。この「まず探す」は、他の制作者が作ったものへの敬意でもあります。
自作に踏み切るのは、探しても見つからない・見つかっても新しいバージョンで動かない・暗号化されていて直せないといったときです。冒頭のベイクツールがまさにそれで、配布物が.mse(暗号化形式)かつ新しいMaxでエラーになったので、自作に切り替えました。そして——たとえ動かない既存スクリプトでも、処理の流れが読めるなら、それ自体がAIに渡す良い材料になります。
渡すべき情報①:正確なAPI・言語仕様
使いたい関数やコマンドが決まっているなら、公式リファレンスの該当箇所をそのままプロンプトに貼り付けます。関数名・引数(渡す値)・戻り値(返ってくる値)の正確な仕様が手元にあれば、AIは存在しない関数をでっち上げる余地が減り、処理の組み立てに集中できます。
MAXScriptのリファレンスは、3ds Max本体のヘルプ(F1)と、オンラインのAutodesk 3ds Max Developer Helpで確認できます。あわせて、最初のプロンプトでMAXScript特有の癖を一言添えておくと、AIが他言語の常識のまま書いてくるのを防げます。たとえば「byやonは予約語なので変数名に使わない」「obj.a().b()のようなメソッドチェーンは書けない(一度変数に受ける)」といった注意書きです。
マクロレコーダーで「正解のMAXScript」を手に入れる
リファレンスを読むより手っ取り早く正しいコードを得る方法があります。3ds Maxのマクロレコーダーです。スクリプト作成 → マクロレコーダーをオンにして普段どおりに操作すると、その操作に対応するMAXScriptが自動で書き出されます。つまり、やりたい操作を一度手で実行すれば、Maxが「その操作の正解のコード」を教えてくれるわけです。
これがバイブコーディングと抜群に相性がいい。マクロレコーダーが吐いた1回分の正しいコードをAIに渡して、「これを選択オブジェクト全部にループで適用して」「エラー処理を足して」と頼めば、AIが命令(API)を推測する必要がなくなり、ハルシネーション(AIが実在しないものをそれらしく作り出してしまうこと)の余地が消えます。存在しない関数をでっち上げられる前に、こちらが本物のAPIを握って渡す——という考え方です。個別の命令よりも、処理の流れ(繰り返しや条件分岐)の方がAIは正確なので、この役割分担はとても噛み合います。
ちなみにMAXScript自体を覚えたい人にとっても、この出力を眺めて「この操作はこう書くのか」と逆引きするのが一番の近道です。リスナー(下部のピンクと白の枠)にエラーや結果が出るので、少しずつ実行して確認しながら進めると安全です。
showPropertiesでプロパティ名を実際に調べる
AIがMAXScriptで特にやりがちなのが、それらしいプロパティ名の捏造です。これを封じるのがshowPropertiesです。調べたいオブジェクトを1つ選択して次を実行すると、そのオブジェクトが実際に持つプロパティ名がリスナーに一覧で出ます。
-- 選択オブジェクトのプロパティ名を一覧表示
showProperties $
-- 配列で受け取りたいときは
getPropNames $
「このオブジェクトにはどんなプロパティがあるのか」を調べる小さなテスト用スクリプトとして手元に置いておくと便利です。出てきた本物のプロパティ名をそのままAIに渡せば、存在しないプロパティを書かれる事故が防げます。マクロレコーダーが「操作の正解」を、showPropertiesが「データ構造の正解」を教えてくれる——どちらもMax自身から正しい情報を引き出してAIに渡す、という同じ考え方です。
渡すべき情報②:バージョンと「どこから実行するか」
MAXScriptは3ds Maxのバージョンによって使える命令や挙動が変わるので、「3ds Max 2025で」のようにバージョンは必ず明示します。もうひとつ見落としがちなのが実行環境です。
たとえば、UIをカーソル位置に出したくてmouse.posを使うと、これはビューポート相対の座標なので、スクリプトエディタから評価するとウィンドウが画面のあらぬ位置に飛びます。「ショートカットキーでビューポート上から呼び出す」のか「エディタから評価してテストする」のかで前提が変わる——こういう文脈はAIからは見えないので、こちらから伝えるしかありません(スクリーン座標が要る場面ではdotNetのCursor.Positionを使う、といった逃げ方も含めて指定できます)。
渡すべき情報③:動いている自作コードと技術資料
すでに手元に動くMAXScriptがあるなら、それを丸ごと渡すのが強力です。頂点位置でメッシュをスライスする自作ツール(200行弱)を「最適化できる箇所ある?」と全文渡したときは、無駄なコマンドモードの出入りの除去、disableSceneRedrawの追加など、元のコードのスタイルと構造を保ったままの的確な提案が返ってきました。ゼロから仕様を説明するより、動く実例1つのほうがはるかに多くを伝えられます。
さらに一歩進めるなら、AIチャットのプロジェクト機能に、自作スクリプトと技術資料を常駐させておく方法があります。私はMAXScript用のプロジェクトを作って、過去に作ったツールのコードや、ハマりどころをまとめたメモを入れてあります。毎回同じ説明を貼らなくても、新しいチャットが最初からこちらの書き方と過去の失敗を知っている状態で始まる——「正しい情報を渡す」を仕組みにした形です。
渡すべき情報④:エラー全文とコールスタック
エラーが出たら、要約せずにリスナーの出力を全文そのまま貼るのが鉄則です。MAXScriptのエラーは実は情報の宝庫で、行番号どころか、その時点の変数の中身まで、エラーに至るまでの経過(コールスタックと呼びます)として全部出ます。
-- ランタイム エラー: undefined に対してプロパティが見つかりません: pos
-- [スタック レベル : 0]
-- イン myFunc(); 行番号 : 12
-- ローカル :
-- targetObj: undefined ← 変数の中身が空だと分かる
-- cnt: 0
この例なら「targetObj: undefined」の1行が原因の特定に直結します。「動きませんでした」とだけ伝えるのと、この全文を貼るのとでは、AIの次の一手の精度がまるで違います。
AIに任せるとき、こちらから指定したいMAXScriptの定番
私がツールを作るとき、ほぼ毎回入れているMAXScriptの定番パターンがいくつかあります。どれも完成度を左右する部分ですが、AIは頼まないと省いたり書き方を間違えたりしがちです。だから最初から「これを入れて」と指定するか、自分のひな形を渡してしまいます。
UIの多重起動をtry/catchで防ぐ
rolloutでUIを作るツールは、スクリプトを再実行すると古いダイアログが残って二重に開いたり、エラーになったりします。先頭にこの1行を置いて、既存のダイアログがあれば先に閉じておくのが定番です。
-- 既にダイアログがあれば閉じてから開く
try(DestroyDialog myRollout)catch()
AIはこのガードを忘れがちなので、「多重起動しないようにDestroyDialogのガードを入れて」と最初に頼んでおきます。
表・リストのUIは.NET(dotNet)で作る
MAXScript標準のUIコントロールは素朴で、行と列のある表や、並び替えできるリストは作れません。そこでdotNetのDataGridViewやListViewを使います。マテリアルIDの一覧や色チップの管理のように「表で見せて編集したい」ツールでは必須級です。
ひとつ注意点があって、dotNetのイベントハンドラ(ボタンやセルのクリック処理)の中からは、外側のローカル変数を参照できません。ハンドラはグローバル関数として外に出し、データもグローバルに持たせるのがMAXScript流です。AIはここを忘れて、ハンドラの外で用意した変数をそのままハンドラの中から使おうとするコードを書いてくるので、先に釘を刺しておくと往復が減ります。
操作をひとまとめにアンドゥできるようにする
ボタンの処理をwith undo onで囲むと、実行した一連の変更をCtrl+Z一発で戻せます。ツールを実戦投入するなら必須のマナーです。
on btnExecute pressed do with undo on
(
-- ここでの変更はまとめて1回のアンドゥで戻せる
)
重い処理はdisableSceneRedrawで囲む
大量のオブジェクトやフェイスを処理するループは、画面の再描画が毎回走ると極端に遅くなります。処理の前後をdisableSceneRedraw()/enableSceneRedraw()で挟むだけで、体感速度が大きく変わります(終わったら必ず戻すのを忘れずに)。
状態はグローバル変数で保持する
「対象を設定」→「実行」のように、ボタンをまたいで情報を覚えておきたいときは、グローバル変数に持たせます(例:global limitFaces = #{})。ローカル変数だと次のボタンを押した瞬間に消えてしまいます。
連番のゼロ埋めと保存先の選択もひな形に入れる
地味だけど毎回使うものとして、連番はformattedPrint i format:"03d"でゼロ埋めし、保存先やファイルはgetSavePathName/getOpenFileNameでユーザーに選ばせる、という2つも定番のひな形に入れています。パス文字列を自前で連結すると区切り文字やキャンセル時のundefined処理で事故りやすいので、標準関数に任せるのが安全です。
渡し方の型:認識合わせ→仕様の箇条書き→省略なし出力
個々の情報と同じくらい大事なのが、やり取りの手順を型にすることです。私は試行錯誤の末、いつもこの流れで進めています。
- やりたいことを文章で伝えて、AIの理解が合っているかを先に確認する(コードはまだ書かせない)
- AIに仕様を番号付きの箇条書きで確認させ、こちらは番号に答えるだけにする(エッジケースもここで拾う)
- 仕様が固まったら「コードを省略なしで出力」と明示してから書かせる
- 修正のときも同じ手順を繰り返す
冒頭で触れたベイクツールの自作も、この型で進みました。「UDIM(マルチタイルUV)ごとにテクスチャをベイクしたい」と文章で伝えると、AIから「タイル検出はUV重心で良いか」「非破壊方式で良いか」「解像度はスピナー指定か」といった確認が番号付きで返ってくる。こちらは「1. はい 2. はい 3. コンプリートです」のように答えるだけで、仕様が数往復で固まります。
この「コードの前に文章で合意する」段階には、思わぬ効果もありました。仕様を詰めている途中で、AI自身が「当初提案したやり方だと、元々0-1範囲にあるタイルと重なってベイクが崩れる。UV全体を一律シフトする方式に変えたい」と、自分の設計ミスを実装前に訂正してきたのです。コードになってから発覚すれば、原因の切り分けだけで1時間コースだったはずの不具合が、日本語の段階で消えました。
「省略なしで出力」の一言も欠かせません。AIは長いコードを「…(中略)…」で省略しがちで、それをそのまま貼って壊す事故が起きます。最初に釘を刺しておけば防げます。
逆方向も重要:AIの答えを見抜くのは自分のツール知識
「正しい情報を渡す」の裏面として、AIの出力の間違いに気づけるのは、結局こちらのツール知識だという話もしておきます。
スライスツールの最適化で、AIは「面リストの再計算がループ内で毎回走っているのは無駄」として事前計算への書き換えを提案してきました。一見正しそうですが、罠でした。スライスするたびに面の数は増えるので、面リストは毎回作り直さないと後半のスライスが対象漏れを起こします。再計算は無駄ではなく意図的な仕様だったわけです。指摘するとAIは正しく直しましたが、こちらがMaxの挙動を知らなければ、静かに壊れた「最適化済み」コードを使い続けていたはずです。
AIが書いたコードが「それらしく動く」ときほど、この種の見落としは静かに潜みます。バイブコーディングは「AIに任せて楽をする」というより、「AIに量を書かせて、自分は仕様の番人をやる」という分担だと考えるのが実態に近いと思います。
全部は勝てない:深追いをやめる判断
正しい情報を渡しても越えられない壁はあります。
ベイクツールでは、レンダリング結果ウィンドウの保存ボタンを自動で押させようと、Windowsメッセージ(windows.sendMessage)でボタンIDを総当たりする調査までやりましたが、対象のウィンドウが外部からの自動操作を受け付けない作りだったため、万策尽きました。ここは「保存だけ手動」と割り切って運用に入れています。
バイブコーディングでは、こういう「そこそこ調べても越えられない壁」にたまに当たります。無限に付き合わず、要件側を少し動かす(機能を落とす・手動と併用する)判断も、時間を守るうえでは立派なテクニックです。
それでも厳しいときの逃げ道:pymxs
どうしてもMAXScriptで安定しない処理は、Python(pymxs)に切り替える手があります。近年の3ds MaxはPythonが標準搭載されており、AIはPythonの学習量が桁違いに多いため、同じ処理でも精度が上がることがあります。MAXScriptの関数をpymxs経由で呼ぶ形になるので、APIの知識はそのまま活きます。「Python(pymxs)で書いて」と指定するだけなので、片方で詰まったらもう片方を試す、くらいの気軽さで使えます。
渡す前・実行前に気をつけること
- スクリプトはシーンを一括変更できてしまうので、必ず保存済み・テスト用シーンで試す(マテリアル系の操作などでは、スクリプトのエラーどころかMax本体ごと落ちることもあります)
- 削除・リセット系の命令が入っていないか、実行前に中身をAIに説明させて確認する
- うまく動いたスクリプトは、渡した情報とセットで残しておく(プロジェクト機能に入れておけば次回からの「正しい情報」になります)
管理人のひとこと
プログラミング経験がなくても、ここで書いた型――正しい情報を渡し、コードの前に文章で仕様を合意する――さえ守れば、実務で使えるツールをAIに任せられるようになります。エラーを貼るだけでどんどん直っていく過程は正直爽快なのですが、AIの提案が正しいかどうかを最後に見抜けるかどうかは、結局Maxを触ってきた年数がものを言うと感じています。



コメント