【MotionBuilder】Python SDK 入門 第9回 『UI・ツール開発 - 実践』

2025/01/25に公開

この記事は、Python SDK 入門 の第9回目の記事です。

https://zenn.dev/nadegata_memo/articles/77a0fbce3b3387

この記事が Python SDK 入門の最終回となります。今回は、第7回・8回で扱ってきたUI・ツール開発の実践編として、Qt(PySide)を用いた実際のツール開発の方法と応用例を説明します。


1. FBWidgetHolderクラス

1.1. クラス概要

Native Widget Holder (can be used to embed native Qt Widget inside MoBu UI elements) A Widget holder provides a bridge to instantiate a Native Qt widget into MB framework.
This will be used to allow user to create UI with QT designer and hook their created UI into MB. - FBWidgetHolder Class Reference


FBLabel型がテキストを表示する Visual Component[1]で、FBButton型がボタンの機能を果たす Visual Component なら、 FBWidgetHolder 型は「Qt で作成した Widget を保持する Visual Component」です。

ラベルやボタンと同様、FBVisualComponentクラスを継承しているので、FBLayout.SetControl() メソッドの引数となり、MotionBuilder のUIを構成する一部となります。

class ToolUsingQt(FBTool)
    def PopulateLayout(self):
        x = FBAddRegionParam(0, FBAttachType.kFBAttachLeft,"")
        y = FBAddRegionParam(0, FBAttachType.kFBAttachTop,"")
        w = FBAddRegionParam(0, FBAttachType.kFBAttachRight,"")
        h = FBAddRegionParam(0, FBAttachType.kFBAttachBottom,"")

        # 子Widgetの表示領域を確保
        self.AddRegion("ChildWidget", "For Qt Widget", x, y, w, h)

        # FBWidgetHolder型オブジェクトに対して、表示領域の制御を許可
        self.SetControl("ChildWidget", <FBWidgetHolder class obj>)

    def __init__(self, name):
        super().__init__(name)
        self.PopulateLayout()

AddRegion()SetControl()FBWidgetHolder型の Visual Component にUI領域を与え、その中に、Qt で作成した Widget(Qt製Widget)が展開されるのです。


1.2. 使い方

To allow a FBWidgetHolder to work properly, you need to specify a Creator function. This function will be called when needed to instantiate the native Widget. Or override WidgetCreate(QWidget* pParent) function in the subclass. - FBWidgetHolder Class Reference


Visual Component としての扱いは他と違いはなく、前節の通りです。FBVisualComponent型オブジェクトに Qt製Widget を保持させる処理については、FBWidgetHolder.WidgetCreate() を派生クラスにてオーバーライドすることで実現します。

from pyfbsdk import FBWidgetHolder
try:
    from PySide6.QtWidgets import QWidget
    from shiboken6 import wrapInstance, getCppPointer
except:
    from PySide2.QtWidgets import QWidget
    from shiboken2 import wrapInstance, getCppPointer

class WigHolder(FBWidgetHolder):
    # オーバーライドした関数
    def WidgetCreate(self, pParent):
        # wrapInstance() は、C++のポインタを不適切でない任意のPythonの型に変換する
        parentwidget = wrapInstance(pParent, QWidget)

        # Qt の Widget のクラスインスタンス作成
        self.childwidget = SomeQtWidgetClass(parentwidget) # example

        # 属性にした、Qt製Widget のC++ポインタを取得して返す
        return getCppPointer(self.childwidget)[0]


class ToolUsingQt(FBTool):
    def PopulateLayout(self):
        x = FBAddRegionParam(0, FBAttachType.kFBAttachLeft,"")
        y = FBAddRegionParam(0, FBAttachType.kFBAttachTop,"")
        w = FBAddRegionParam(0, FBAttachType.kFBAttachRight,"")
        h = FBAddRegionParam(0, FBAttachType.kFBAttachBottom,"")

        self.AddRegion("ChildWidget", "For Qt Widget", x, y, w, h)
        self.SetControl("ChildWidget", self.wigholder) # Visual Component としての処理

    def __init__(self, name):
        super().__init__(name)
        self.wigholder = WigHolder() # ツールクラスの属性として FBWidgetHolder型を追加
        self.PopulateLayout()


WidgetCreate() が受け取る pParent は、Qt の Parenting System において、今保持したい Qt製Widget を子に取ることになる親の Widget のポインタと思われます。あくまで私の予想ですが、SDK内部で QtWidgets.QWidget型を継承したであろう FBWidgetHolder型オブジェクト自身を指しているのだと解釈しています。


1.3. 補足:Open Reality SDKの場合

Qt の Widgetクラスオブジェクトを作成する関数を用意し、FBWidgetHolder::SetCreator() でその関数を WidgetCreate() の代わりとして登録することで実現します。

class QtTestTool : public FBTool
{
    // (中略)

public:
    virtual bool FBCreate();
    virtual void FBDestroy();
    void ConfigureLayout();

private:
    FBWidgetHolder mQtHolder;
};

// (中略)

// Qt の Widgetクラスオブジェクトを作成する、オリジナルの関数
QWidget* SetChildWidget(QWidget* pParent) {
    QtTestWidget* lWidget = new QtTestWidget(pParent);
    return lWidget;
}

bool QtTestTool::FBCreate() {
    StartSize[0] = 400;
    StartSize[1] = 250;
    ConfigureLayout();
    return true;
}

void QtTestTool::FBDestroy() {}

void QtTestTool::ConfigureLayout() {
    AddRegion("ChildWidget", "QtTestTool",
        0, kFBAttachLeft,   "", 1.0,
        0, kFBAttachTop,    "", 1.0,
        0, kFBAttachRight,  "", 1.0,
        0, kFBAttachBottom, "", 1.0);

    // FBWidgetHolder::SetCreator() で Widget作成関数を登録
    mQtHolder.SetCreator(SetChildWidget);
    SetControl("ChildWidget", mQtHolder);
}


この SetCreator() は Python SDK から利用できないので、Python でツールを作る場合は FBWidgetHolderクラスの継承クラスにて WidgetCreate() をオーバーライドする他ありません。


2. Qt Widgets Designer による Widget作成

2.1. uiファイルと uic

Qt Widgets Designer(以下 Designer)は、コードによる記述ではなく、画面上の操作で Widget を配置してGUIを作成するアプリケーションです。PySide 導入時に「pyside6-designer.exe(PySide6の場合)」として同時にダウンロードされています。
alt text
Qt Designer の編集・プレビュー画面

画面右上「Object Inspector」では、各Widget のクラスとオブジェクト名、および親子関係を確認できます。また、その下の「Property Editor」では、各Widget の Property(オブジェクト名・サイズ・表示テキストなど)を編集することができます。

作成したUIのデータは、xml 形式のファイル(拡張子 .ui)に保存されます。ただし、実際にアプリケーションに用いるには、Designer と同じくダウンロードされる uic(User Interface Compiler) を用いてソースファイルに変換する必要があります[2]

pyside6-uic.exe <ui file>.ui -o <converted file>.py # Python
uic.exe <ui file>.ui -o <converted file>.h # C++

C++アプリケーションの場合は、CMake で set(CMAKE_AUTOUIC ON) と宣言すれば自動でこの変換が行われるので、uic による手動での変換は必要ありません。その際に生成されるヘッダファイルの名前は「ui_ + .uiファイルの名前 + .h」になるので、手動で行う場合もこの規則に従って変換後の名前を指定することをお勧めします。

3つ程のボタンしか無いような単純なUIであればコードによる記述で十分ですが、より複雑なUIを作成したい場合や MotionBuilder SDK での記述が苦手な場合は、Designer を使いましょう。


2.2. Designer製 Widgetの使用

uic により生成されたファイルを見てみましょう。説明のため、不要な部分は削除しています。

ui_test.py
# -*- coding: utf-8 -*-
from PySide6.QtCore import (QCoreApplication, QMetaObject)
from PySide6.QtWidgets import (QHBoxLayout, QPushButton)

class Ui_Form(object):
    def setupUi(self, Form):
        if not Form.objectName():
            Form.setObjectName(u"Form")
        Form.resize(400, 300)
        self.horizontalLayout = QHBoxLayout(Form)
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.pushButton = QPushButton(Form)
        self.pushButton.setObjectName(u"pushButton")

        self.horizontalLayout.addWidget(self.pushButton)
        self.retranslateUi(Form)
        QMetaObject.connectSlotsByName(Form)
    # setupUi

    def retranslateUi(self, Form):
        Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
        self.pushButton.setText(QCoreApplication.translate("Form", u"PushButton", None))
    # retranslateUi


Ui_Formクラスは、Designer で作成した Widget のクラスです。名前には規則があり、「Ui_ + 最も上位の Widget のオブジェクト名」となります。

重要なのは、このクラスのメソッド setupUi() です。そもそも Qt の各Widget に対応するクラスのコンストラクタは、親にあたる Widget を引数に取ることができます。

QPushButton(QWidget *parent = nullptr)
QLayout(QWidget *parent = nullptr)

これを踏まえて処理内容を見ると、setupUi() は引数に取った何らかの Widget を親とし、そのWidget に対して Designer で配置した各Widget を作成するような関数であるとお分かりいただけるでしょう。

uicにより生成されたこの Ui_Formクラスは、QWidget型とともにUI全体を表すクラスへと継承されることになります。そして特殊メソッド __init__()内で self.setupUi(self)と呼び出されることにより、Designer製の Widget が展開されるのです。

from ui_test import Ui_Form
from PySide6.QtWidgets import QWidget

class MainWidget(QWidget, Ui_Form):
    def __init__(self):
        super().__init__()
        self.setupUi(self)        


あとは、配置した Widget の Signal に対応する Slot を設定すれば、実用的な Widget が完成します。

class MainWidget(QWidget, Ui_Form):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # Connect Signals and Slots
        # pushButton は Designer で配置した Widget のオブジェクト名
        self.pushButton.clicked.connect(self.ShowMessage)

    def ShowMessage(self):
        QMessageBox.question(self, "Message Title", "message", QMessageBox.Ok)


UI全体を表すこの MainWidgetクラスは Ui_Form型を継承しているので、Designer で配置した各Widget にそのままの名前でアクセスすることができるのです。C++の場合、この構成を The Multiple Inheritance Approach と呼びます[3]。このようにして作成した Widgetクラスは、あとは通常の Widgetクラスと同様に使えばokです。

main.py
from ui_test import Ui_Form
from PySide6.QtWidgets import QWidget, QMessageBox, QApplication

class MainWidget(QWidget, Ui_Form):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.pushButton.clicked.connect(self.ShowMessage)

    def ShowMessage(self):
        QMessageBox.question(self, "Message Title", "message", QMessageBox.Ok)

app = QApplication()
widget = MainWidget() # Widget 作成
widget.show()
app.exec()


2.3. 補足:Designer の使い方

Python SDK 入門の内容から大きく逸れる可能性があるので、Designer アプリケーションの使い方の説明は割愛させていただきます。その代わりとして、いくつかチュートリアル記事・動画のリンクを掲載いたします。


3. ツール開発の流れの概要

自分の場合、大まかに以下の流れで開発を行います。

  1. ツール作成の目的と要件の整理、UIレイアウト構成
  2. 開発用ディレクトリ作成と、Python Startup Folder への追加
  3. Qt Widgets Designer によるUI作成
  4. uicによる変換
  5. Widgetクラスの作成、Signal に対応する Slot の実装
  6. ツールクラスの作成・実装
  7. テスト・修正


4. 実際の開発の流れ

4.1. 開発前の準備

ツールを作成するにあたり、「なぜツールが必要なのか」「ツールを開発することで何を効率化するのか」などを明確にし、最低限どんな機能を持たせればよいかをまず把握するのが重要です。それからUIの構成を考えていきます。紙にペンを走らせてレイアウトを考えるのも良いでしょう。

以後説明に用いる例として、

  • Cube の作成・削除
  • 作成 Cube の拡大縮小

を行うツールを作るとします。

4.2. 開発環境の構築

まずは開発用ディレクトリを作成します。場所は分かりやすいパスであればどこでもokです。
ディレクトリを用意したら、仮想環境を作成します。使用する Python は MotionBuilder の Python Editor に表示されているバージョンと同じものを使用することをお勧めします。

python -m venv .venv
.venv/Scripts/activate


続いて PySide を導入しましょう。
以下 (.venv) は仮想環境が起動していることを表します。実行時は記載不要です。

(.venv) pip install PySide6  # MotionBuilder 2025
(.venv) pip install PySide2  # MotionBuilder -2024


最後に、MotionBuilder にこの開発用ディレクトリのパスを登録します。MotionBuilder 画面左上「Settings」→「Preferences」→「Python」→「Python startup folder」欄に、開発用のディレクトリを入力してください。

alt text
Python startup folder の登録

こうすることで、開発用ディレクトリに存在する Python ファイルが MotionBuilder 起動時に実行されるようになります。ただし、ここで実行されるのは登録したパス「直下」に存在する Python ファイルであって、パス下の別のフォルダ内にあるモジュールは実行されません。


4.3. Designer によるUI作成

仮想環境に導入された Qt Widgets Designer を起動します。

(.venv) pyside6-designer  # MotionBuilder 2025
(.venv) pyside2-designer  # MotionBuilder -2024


alt text
Designer 起動画面

「templates/forms」は「Widget」を選択してください。空の Widget が作成されます。
忘れないうちに、最初に Ctrl + S でデータを保存しておいてください。

では早速 Widget作成に入ります。Cube の作成・削除はボタンで十分でしょう。拡大縮小については、スライダーを使うことにします。ということで、とりあえず必要な Widget を左の一覧よりドラッグアンドドロップしていきます。

ボタンは、ダブルクリックしてテキストを変更してください。また、右上の Object Inspector にて、どんな型のオブジェクトが作成されたのか、オブジェクト名はどうなっているか確認しておくとよいと思います。

alt text
必要な Widget を配置

配置した Widget を整列させましょう。
背面の Widget をクリックした後に上部のアイコン「垂直に並べる」をクリックすると、配置した Widget が垂直に揃います。

alt text
Widget の整列ボタン(垂直)

一度 Ctrl + R でプレビューを起動してみてください。表示されたウィンドウのサイズ変更に合わせて、中の Widget の大きさも変化するのが確認できるはずです。

alt text
整列した Widget とプレビュー表示



これでUIの外観は完成しました。続いて各Widget の Property を編集してきます。
自分が大抵行う編集は以下の通りです。

  • オブジェクト名を、分かりやすい名前に変更
  • sizePolicy(大きさを固定するか、どこまで広げるか)の変更
  • その他初期値の設定


まず、オブジェクト名を変更します。このオブジェクト名は、後のコードの記述の際に参照する可能性があるので、デフォルトの名前から変更して分かりやすい名前にすることをお勧めします。編集方法は、「Object Inspector で該当の Widget を選択 → Property Editor の "objectName" の値(名前)を変更」です。

alt text
変更したオブジェクト名

サイズ変更を担うスライダーの設定も行います。実用上、スライダーの初期位置は中心で、かつスライダーが送信する値は常に0より大きくあってほしいところです。今回は

  • 初期値:50
  • 値のきざみ:1
  • 値域:1 ~ 100

と設定し、スライダーの送信値の処理は後にコードで記述することにします。Property Editor にて該当の Property を変更します。

alt text
スライダーの Property 設定

ここで再度 Ctrl + R でプレビューを開き、動作を確認しておきましょう。
最後に忘れずにデータを保存します。


4.4. uic による変換

Designer で保存した、拡張子が .ui のファイルを Python ファイルに変換します。

(.venv) pyside6-uic <ui file>.ui -o ui_<ui file>.py  # MotionBuilder 2025
(.venv) pyside2-uic <ui file>.ui -o ui_<ui file>.py  # MotionBuilder -2024


ただし、このままでは特定のバージョンにしか対応できないので、生成された Pythonファイルの import 文を変更します。try-except 構文を用いて、PySide6 と PySide2 のどちらでも使用できるようにします。

try:
    from PySide6.QtCore import *
    from PySide6.QtGui import *
    from PySide6.QtWidgets import *
except:
    from PySide2.QtCore import *
    from PySide2.QtGui import *
    from PySide2.QtWidgets import *

上の記述はあくまで例です。自分の場合、ここで try-except を使う場合は import 文の記載内容をそのままコピーしてバージョン部分だけ変えています。


4.5. Widgetクラスの作成・UIの実装

4.2.節 で Python Startup Folder に登録したパス直下に各ソースファイルがある状態なので、ツールの Python ファイル以外は別ディレクトリにまとめておきます。

alt text
ディレクトリ構成

この Widget.py にて Widgetクラスの実装を、TestTool.py にてツールクラスの実装と MotionBuilder への登録処理を記述していきます。

スライダーが発する Signal を受け取る Slot の関数は、int値を引数に取りましょう。初期値を50としたため、その関数は引数が50の場合に Cube の拡大率を1にする必要があります。スライダーの Signal としては、valueChanged(int) がおすすめです。ただし、ツール起動時にも int値が送信される点に注意してください。

以上と 2.2.節 を踏まえると、Widgetクラスは以下のように実装できます。

Widget.py
from pyfbsdk import FBModelCube, FBMessageBox, FBVector3d
from src.ui_Widget import Ui_Form

try:
    from PySide6.QtWidgets import QWidget
except:
    from PySide2.QtWidgets import QWidget

class MainWidget(QWidget, Ui_Form):
    def __init__(self, pParent):
        super().__init__(pParent)
        self.setupUi(self)
        self.cube = None

        # Signal と Slot の接続
        # ここで各Widget のオブジェクト名が必要になる
        self.CreateButton.clicked.connect(self.CreateCube)
        self.SizeSlider.valueChanged.connect(self.ResizeCube)
        self.DeleteButton.clicked.connect(self.DeleteCube)
    
    def CreateCube(self):
        """Cubeの作成
        """
        if not self.cube:
            self.cube = FBModelCube("Cube")
            self.cube.Show = True
            self.cube.Scaling = FBVector3d(100, 100, 100)
        else:
            FBMessageBox("Caution", "You already created the cube.", "OK")

    
    def ResizeCube(self, value: int):
        """スライダー値変化時にCubeのサイズを変更\n
        Args:
            value: UIのスライダーの送信値(初期値:50)
        """
        if self.cube:
            self.cube.Scaling = FBVector3d(value/50 * 100, value/50 * 100, value/50 * 100)


    def DeleteCube(self):
        """Cubeの削除
        """
        if self.cube:
            self.cube.FBDelete()
            self.cube = None
        
            # スライダーの位置を元に戻す
            self.SizeSlider.setSliderPosition(50)


4.6. ツールクラスの作成、実装

Designer および ui_Widget.py を見ると、Widgetの初期サイズは 600*480 となっているので、FBTool.StartSizeX および FBTool.StartSizeY でツールの初期サイズを合わせます。

1.2.節、および 第7回 の内容を踏まえれば、ツールクラスの実装と MotionBuilder への登録処理は以下のように実装できます。

TestTool.py
from pyfbsdk import*
from pyfbsdk_additions import*
from src.Widget import MainWidget
try:
    from PySide6.QtWidgets import QWidget
    from shiboken6 import wrapInstance, getCppPointer
except:
    from PySide2.QtWidgets import QWidget
    from shiboken2 import wrapInstance, getCppPointer

class WigHolder(FBWidgetHolder):
    def WidgetCreate(self, pParent):
        parentwidget = wrapInstance(pParent, QWidget)

        # Designer製 Widgetの使用
        self.childwidget = MainWidget(parentwidget)
        return getCppPointer(self.childwidget)[0]

class TestTool(FBTool):
    def PopulateLayout(self):
        x = FBAddRegionParam(0, FBAttachType.kFBAttachLeft,"")
        y = FBAddRegionParam(0, FBAttachType.kFBAttachTop,"")
        w = FBAddRegionParam(0, FBAttachType.kFBAttachRight,"")
        h = FBAddRegionParam(0, FBAttachType.kFBAttachBottom,"")

        self.AddRegion("ChildWidget", "For Qt Widget", x, y, w, h)
        self.SetControl("ChildWidget", self.wigholder) 

    def __init__(self, name):
        super().__init__(name)
        self.wigholder = WigHolder()
        self.PopulateLayout()

        # 初期表示サイズの指定
        self.StartSizeX = 600
        self.StartSizeY = 480

toolName = "ToolSample"

if toolName in FBToolList:
    ShowToolByName(toolName)

else:
    tool = TestTool(toolName)
    FBAddTool(tool)


4.7. テスト

以下コマンドで、MotionBuilder をターミナルから起動します。

<path/to/motionbuilder.exe> -console -verbosePython 

表示された出力ウィンドウにて、ツールクラスを実装した TestTool.py が読み込まれていること、また特に何もエラーが表示されていないことを確認します。合わせて、Python Editor にもエラーが出ていないかチェックしてください。

エラーが起きていなければ、画面左上「Python Tools」よりが作成したツール名を選択します。

alt text
ツールの起動

ここに該当のツール名が表示されていなければ、コードの記述が誤っているか、作成したツールの Python ファイルが読み込まれていない可能性があります。

alt text
起動したツール

実際にツールを操作し、意図した通りの動作になっているかチェックします。その間、Python Editor にエラーが出ていないか確認してください。


以上が Designer製の Widgetを使用してツールを作成する手順になります。


5. 備考

  • print()関数による出力が表示されない場合がある

    MotionBuilder 2024 以前の場合、print() での出力内容が Python Editor に表示されない場合があります。2025版リリースノート記載[4]のバグによるものと思われます。2025版では修正されているようです。

  • FBToolクラスの一部 Property は 2023版では使えない
    FBToolクラスの「MinSizeX/MaxSizeX/MinSizeY/MaxSizeY」Property は、2024版リリースノート記載[5]のバグによりアプリケーションがクラッシュするため使用不可です。複数バージョンに対応させたい場合、例えば以下のようにして場合分けをするとよいでしょう。

    # 2023版のバグ MOBU-11676 への対応
    if FBSystem().Version != 23000.0:
        self.MinSizeX   = 200
        self.MinSizeY   = 175
        self.MaxSizeX   = 400
        self.MaxSizeY   = 375
    


  • モジュール名の重複を避ける
    MotionBuilder のモジュール探索パス下に同名のファイルを置くのは避けたいところです。ツールごとに固有の名前を付けた方がよいかと思います。

  • Referenicng Sample
    今回の内容に対応するサンプルとして、Referencing Sample があります。Resources Window内 Asset Browser にて「Scripts」→「Samples」→「Referencing」→「MBFileRefDemo.py」 がそのツールクラスの実装と MotionBuilder への登録を担うモジュールです。ただし、そのままではエラーが出てツールが正常に起動しないので、バージョンごとに以下のように修正する必要があります。

    バージョン 修正内容
    2024 Referencing/MBFileRefDemo/ReferencingSample.py において「is」を「==」に変更
    2025 Referencing/MBFileRefDemo/ReferencingSampleUI2.py において Ui_ReferencingSampleクラスの __init__()メソッド全体をコメントアウト




最後に

昨年から連載してきました「Python SDK 入門」は、今回をもって最終回となります。

「比較的新しい包括的なチュートリアル」の完成を目指し、同じく MotionBuilder に取り組む学生さんに向けて、また普段からお仕事で使われている現場の方に向けて、そして Python SDK の資料をお探しの方に向けて執筆を続けてきました。最後までお付き合いくださり、本当にありがとうございました。記事を共有してくださった皆様、コメントを寄せてくださった皆様、また執筆を応援してくれた所属サークルの皆に感謝いたします。一連の記事が少しでも多くの方の取組の一助となっていたのであれば幸いです。

この連載記事の執筆にあたり、GUNCY'S 様の MotionBuilderチュートリアル に触れずにはいられません。MotionBuilder を触り始めて右も左も分からなかった時に最初に継続して取り組めたチュートリアルでした。Zenn で Python SDK 入門の連載を始めたのもこのチュートリアルがあったからです。この場にて改めて感謝申し上げます。

昨年8月に開催された モーキャプフェス2024 では、想像以上に多くのユーザーの方々と直接お話ができ、自分にとって貴重な一日となりました。その後12月に立ち上げたユーザーコミュニティ「Mobu Japan Users Hub」は、現在50人近くの方がお越しくださり、学生さんも一般の方も含め質疑応答が行われておりました。このようにして、自分が MotionBuilder に取り組み始めた時と比べてユーザーの方々との繋がりを実感し、大変嬉しく思っております。今後もイベントへの参加や記事の執筆を続け、コミュニティを盛り上げられたらと思っております。何卒よろしくお願いいたします。


ご質問など

執筆内容に関するご質問は、各記事の Discussion 欄にてコメントをお寄せいただくか、執筆者Twitter のDMまでよろしくお願いいたします。Mobu Japan Users Hub でも随時質問を受け付けております。また、記事で取り上げる内容としてご希望の話題がありましたら、こちらもコメントをお寄せください。折に触れて今後も記事執筆を続けていきます。


脚注
  1. MotionBuilder におけるUIの構成単位の名称。第7回 を参照 ↩︎

  2. Python の場合は必ず「pyside6-uic.exe」を使用します。「uic.exe」は C++のソースを生成するので、拡張子を「.py」としたところで中身の記述は C++ になり、正常に処理できません ↩︎

  3. Using a Designer UI File in Your C++ Application を参照 ↩︎

  4. MotionBuilder 2025 リリース ノートの MOBU-11889 を参照 ↩︎

  5. MotionBuilder 2024 リリース ノートの MOBU-11676 を参照 ↩︎

Discussion