Houdini 18.5 基本

Radialメニュー

Radialメニューは、ビューア内で使用頻度の高い機能に簡単にアクセスすることができます。

On this page

概要

ホットキーを押すとRadialメニューがポップアップ表示されます。 よく使用する項目をこのメニューに割り当てることができます。 さらに、サブメニューを特定の位置に割り当てて、Radialメニューの階層を作成することができます。 これによって、ビューア内で作業する時に指先で多数のツールにアクセスすることができます。

Radialメニューはマウスポインタ下に出現し、大きな標的を用意し、マウスをあまり動かすことがないようにマウスポインタから等距離にすべてのオプションを配置します。 このRadialメニューを使用すれば、ツールに到達する"方向"を学習すれば、最終的にはラベルを読まなくても迅速にそのツールに到達することができます。

Houdiniには、3Dビューアで作業する際に利用可能なデフォルトのRadialメニューが用意されています。 他にも、Radial Menu Editorで独自のRadialメニューを作成して、3DビューアまたはネットワークエディタでのホットキーにそのRadialメニューを割り当てることができます。

現在のところ、Radialメニューは 3Dビューアネットワークエディタ で対応しています。

Radialメニューの使い方

3つの方法でメニューを操作することができます。人によってはインタラクティブスタイルの方が快適なこともあったり、入力デバイスによっては別のスタイルが適切なこともあります。

  • キーを押したまま にするとメニューが表示され、マウスを動かしてメニューアイテムを選択しから キーを離します

  • キーをタップ するとメニューが表示され、マウスを動かしてメニューアイテムを選択してから クリック します。

  • キーを押してマウスドラッグを開始 して、マウスを動かしてメニューアイテムを選択してから マウスボタンを離します

    このスタイルは、今までマーキングメニューを使ってきた場合やタブレットを使用している場合にうまく動作します。

  • その円の中をクリックするか、 ⎋ Escを押してメニューをキャンセルします。

  • メニューが開いている時に テンキー (1-9)を使用することで、マウスを使わずに現在のメニューから別の指示を"選択"することができます。

    メニュー作成者は、各メニューアイテムの"ショートカット"キーを指定することもできます。 メニューが表示されている時にそのキーを押すことで、そのメニューからそのメニューアイテムを選択することができます。

デフォルトメニュー

Houdiniには事前に定義されたRadialメニューがいくつか用意されています。

以下のキーを使用することで、 3Dビューア 内で既製のRadialメニューにアクセスすることができます:

キー

メニュータイプ

X

スナップコントロール。

C

"Current"メニュー。 メインインターフェースの上部にある Radialスイッチメニューを使用することで、このキーに対するメニューを選択することができます。

V

ビューコントロール。

以下のキーを使用することで、 ネットワークエディタ 内で既製のRadialメニューにアクセスすることができます:

キー

メニュータイプ

N

ナビゲーションコントロール。

ホットキーエディタRadialメニューを他のホットキーに割り当てることができます。

"Current"メニュー

デフォルトで、3Dビューア内でCキーを押すと、"Current" Radialメニューが表示されます。

  • このCキーにCurrentメニューを設定するには、メインインターフェスの上部にある Radial切り替えメニューをクリックします。

    ここには、カーブモデリング用、ポリゴンモデリング用、UV編集用、他のワークフロー用に特別に事前に構築されたメニューが用意されています。

  • 通常ではHoudiniにはデスクトップ毎に別々の"Current"メニューを持っています。

    例えば、Modelingデスクトップに切り替えると、そのCキーはモデリングツールを含んだメニューを表示します。 汎用的なBuildデスクトップは、全般的に役立つツールをたくさん含んだメニューを持っています。

  • 通常ではデスクトップを切り替えると、Houdiniは、そのCキーを、そのデスクトップに関連した独自のRadialメニューに切り替えます。 Radial切り替えメニューを開いて下部にある Pin Current Menu を有効にすることで、デスクトップと連動しないようにCurrent Radialメニューを"ピン留め"することができます。

Radialメニューを管理する方法

To...Do this

Radial Menu Editorを開く

  • メインメニューから Edit ▸ Radial Menus を選択します。

新しいカスタムメニューを作成する

  1. Radial Menu Editorを開きます。

  2. 左側にある Panes 下で、Radialメニューを編集したいペインタイプをクリックします。

  3. メニューのリストの下にあるAdd ボタンをクリックして、 Regular Menu または Script Menu のどちらかを選択します。

    • (スクリプトを使ってメニューを生成するのではなく)トップレベルのメニューをデザインしたいのであれば、 Regular Menu をクリックします。 以下のRadialメニューの編集を参照してください。

    • スクリプトを使って動的にRadialメニューを生成したいのであれば、 Script Menu をクリックします。 以下のスクリプト制御のメニューの生成を参照してください。

  4. 右側にある Name にそのメニュー用の短い内部名を設定します。この文字列にスペースを含めることはできません。この名前は、スクリプトで使用され、メニューが保存された時のファイル名の構築に使用されます。

  5. Label にそのメニュー用の"人が解読可能な"名前を設定します。このラベルは、Radial切り替えメニューなどのユーザーインターフェースに表示されます。

  6. Apply をクリックしてメニューを更新するか、または、 Accept をクリックしてメニューを更新してエディタを閉じます。

Radialメニューをホットキーに割り当てる

Radialメニューをホットキーに割り当てる方法を参照してください。

既存のメニューを編集する

  1. Radial Menu Editorを開きます。

  2. 左側にある Panes 下で、Radialメニューを編集したいペインタイプをクリックします。

  3. Menus 下で、編集したいメニューをクリックします。

  4. 編集用インターフェースを使用して、そのメニュー内のアイテムを編集します。

  5. Apply をクリックしてメニューを更新するか、または、 Accept をクリックしてメニューを更新してエディタを閉じます。

Tip

エディタ内で"Current"メニューをすぐに開きたいのであれば、メインインターフェースの上部にある Radial切り替えメニューを開いてから、 Edit Current をクリックします。

Radialメニューを編集する方法

To...Do this

シェルフツールを呼び出すメニュー項目を作成する

  1. Shelf tools タブをクリックして、そのシェルフツリーからメニューに追加したいシェルフツールを検索します。

  2. 左側のペインからそのシェルフツールを右側のRadialメニュー周辺の8個のポジションのどれかにドラッグします。

ノードを作成するメニュー項目を作成する

  1. Nodes タブをクリックして、ノードタイプとカテゴリツリーからメニューに追加したいノードを検索します。

  2. 左側のペインからそのノードを右側のRadialメニュー周辺の8個のポジションのどれかにドラッグします。

任意のPythonスクリプトを実行するメニュー項目を作成する

  1. Utilities タブをクリックして、"Script"項目を右側のRadialメニュー周辺の8個のポジションのどれかにドラッグします。

  2. そのメニュースロットに表示させるテキストを Label に設定します。

  3. Icon を指定することができます。このアイコンフィールドを空っぽのままにすると、そのメニューは小さいドットを使用します。

  4. Script タブで、ユーザがそのメニュー項目を選択した時に実行するスクリプトを入力します。

    このスクリプトは、accessグローバル辞書にアクセスすることができます。 現在のところ、その辞書の項目はkwargs["pane"]のみとなっています。この項目は、ユーザがメニューを開いたビューアペインを表現したhou.SceneViewerオブジェクトを返します。

    hou.SceneViewer.curViewport()を使用することで、マウスが乗っているビューポート(分割ビュー)を表現したオブジェクトを取得することができます。

メニュー項目をオン/オフのトグルにしたい場合、 Check on/off タブをクリックして、そのメニュー項目がオンならTrueを返すPythonエクスプレッションを入力します。

例えば、hou.session.mytoggleという名前のsessionモジュールにグローバルブーリアン変数があれば、以下のように Script タブを設定することができます:

# ユーザがこのメニュー項目を呼び出した時に、
# そのトグル状態を反転します。
hou.session.mytoggle = not hou.session.mytoggle

…そして、以下のように Check on/off タブを設定します:

hou.session.mytoggle is True

または単に

hou.session.mytoggle

Pythonスクリプトの詳細は、PythonによるHoudiniのスクリプティングを参照してください。

サブメニューを作成する

  1. Utilities タブをクリックして、"Submenu"項目を右側のRadialメニュー周辺の8個のポジションのどれかにドラッグします。

  2. そのサブメニュー項目をダブルクリックして、そのサブメニューにジャンプします。

  3. そのサブメニューを編集します。

    そのサブメニューには、その親メニューのサブメニュー項目の 反対側にある メニュースロットは、"go back"項目専用( "rewind"アイコンでマークされています)になっており、ユーザがサブメニューから戻ることができます。 このスロットを編集することはできません。

  4. 親メニューへ"上に"戻るには、"go back"項目をダブルクリックするか、そのメニューの上にあるパスをクリックします。

スクリプト制御のサブメニューを作成する

  1. Utilities タブをクリックして、"Script Submenu"アイテムを左側にあるRadialメニュー周辺の8個の位置のどれかの上にドラッグします。

  2. そのアイテムの Label を設定します。

  3. Script タブで、サブメニューの内容を生成するスクリプトを入力します。

スクリプト制御のRadialメニューの生成方法

スクリプト制御のメニュー/サブメニューは、ユーザがメニューを開いた瞬間に"その場で"メニューの内容を生成するPythonスクリプトを記述することができます。 これによって、現在の状況に応じて動的に変更されるRadialメニューを作成することができます。

  • このスクリプトは、kwargsという名前のdictオブジェクトにアクセスすることができます。現在のところ、この辞書には1個の項目が含まれています:

    • kwargs["pane"] ユーザがRadialメニューを開いたペインを表現したhou.PaneTabオブジェクト。

      3Dシーンビューアはhou.SceneViewerオブジェクトです。 このビューアペインは、1つ以上の ビューポート に分割されています。 hou.SceneViewer.curViewport()を使用することで現行ビューポートを取得することができます。

  • このスクリプトは、表示するメニューを表現したJSONライクな構造を生成します(以下参照)。

  • このスクリプトは、自動的にradialmenuモジュールにアクセスすることもできます。このスクリプトは、メニューの内容として設定したいメニューデータを使ってradialmenu.setRadialMenu()をコールします。

  • 別の方法だと、メニュー構造を構築せずに、メニューの内容を表示したい既存のRadialメニューの名前を使ってsetRadialMenu()をコールすることができます。 これによって、既存のメニューを表示するかどうかを動的に選択することができます。例:

    if someCondition:
        radialmenu.setRadialMenu("cloth")
    else:
        radialmenu.setRadialMenu("polymodel")
    
  • 基本的なメニュー構造は辞書になっていて、キーが径方向を示し、値がその方向でのアイテムまたはサブメニューを記述した辞書です。

    def openAnimationEditor(**kwargs):
        desk = hou.ui.curDesktop()
        desk.createFloatingPaneTab(hou.paneTabType.ChannelEditor)
    
    
    def openParmEditor(**kwargs):
        desk = hou.ui.curDesktop()
        desk.createFloatingPaneTab(hou.paneTabType.Parm)
    
    
    def makeSubMenu(**kwargs):
        menu = {
            "se": {"type": "script_action",
                   "script": "hou.ui.displayMessage('Hi!')"}
        }
        radialmenu.setRadialMenu(menu)
    
    
    menu = {
        "n": {
            "type": "script_action",
            "label": "Animation Editor",
            "script": openAnimationEditor,
        },
        "s": {
            "type": "script_action",
            "label": "Parameters",
            "script": openParmEditor,
        },
        "e": {
            "type": "link",
            "label": "Cloth",
            "name": "cloth",
        }
        "se": {
            "type": "script_submenu",
            "label": "Go To",
            "script": makeSubMenu,
        }
    }
    
    radialmenu.setRadialMenu(menu)
    

    (上記のサンプルは、辞書の構造を説明するために意図されたものですが、スクリプト制御のメニューの肝は、何かしらの条件に基づいて内容が変更できることなので、上記で記述しているような文字列どおりの辞書の代わりに、通常ではスクリプト内で辞書を構築することになります。以下のサンプルを参照してください。)

  • 径方向を示すキーを色々な方法で指定することができます:

    • 0から7までの数字を指定する方法。0は頂上(北)のアイテムで、数字が大きいほど時計回りです。

    • n, ne, e, se, s, sw, w, nwの文字列を指定する方法。

    • north, northeast, east, southeast, south, southwest, west, northwestの文字列を指定する方法。

  • 各アイテムの辞書には、以下のキーを格納します:

    type

    typeには、script_action, script_submenu, linkのどれかを指定することができます。以下参照。

    label

    アイテム/サブメニューの人が解読可能なラベルで、Radialメニューに表示されます。

    icon (任意)

    Radialメニュー内のこのアイテムの隣に表示するアイコンの名前またはファイルパス。

    shortcut (任意)

    Radialメニューが表示されている時にこのアイテムを発動するキーを指定します。

  • script_actionタイプアイテムは、ユーザがRadialメニュー内でアイテムを選択した時にスクリプトを実行します。 これは、以下の追加キーを持ちます:

    script

    ユーザがメニュー内でこのアイテムを選択した時に実行するコール可能な関数、または、Pythonコードを含んだ文字列。

    現在のところ、このスクリプトは1個のキーワード引数(pane, hou.PaneTabオブジェクト)でコールされます。 後で私どもがキーワード引数を追加しても関数が壊れないように、あなたの関数が**kwargs(任意の追加キーワード引数)を受け取るように記述しておくと良いでしょう。

    check

    このキーが存在すれば、そのアイテムのトグルを有効または無効にすることができます。

    ここには、コール可能な関数を指定してください。 この関数は、そのアイテムに現在チェックが付いていればTrue、チェックが付いてなければFalseを返すようにしてください。 これは、そのアイテムをRadialメニュー内に"オン"または"オフ"として表示するかどうかを制御します。

    ユーザインターフェースをすっきりさせるために、メニューアイテムが選択されるとトグルが有効または無効になるようにscriptはそのトグルの状態を変更します。

  • script_submenuタイプアイテムは、ユーザがRadialメニュー内でサブメニューを選択した時にスクリプト制御のサブメニューを生成します。 これは、以下の追加キーを持ちます:

    script

    コール可能な関数、または、Pythonコードを含んだ文字列。 これは、スクリプト制御のサブメニューの内容を生成します。

    現在のところ、このスクリプトは1個のキーワード引数(pane, hou.PaneTabオブジェクト)でコールされます。 後で私どもがキーワード引数を追加しても関数が壊れないように、あなたの関数が**kwargs(任意の追加キーワード引数)を受け取るように記述しておくと良いでしょう。

  • linkタイプアイテムは、ユーザがRadialメニュー内でサブメニューを選択した時に既存のRadialメニューをサブメニューとして表示します。 これは、以下の追加キーを持ちます:

    name

    サブメニューが選択された時に表示するそのサブメニューの内部名を含んだ文字列。

    Tip

    linkアイテム内にlabelキーを指定しなかった場合、リンク先のメニューのラベルが使用されます。 labelキーを指定した場合、そのラベルが代わりに表示されます。

スクリプト制御のメニューのサンプル

このスクリプトは、直近で編集された8個のLight LOPsを表示するメニューを生成します。 それらのLight LOPsのどれかを選択すると、そのLight LOPが選択されます。

# まず最初に基本方位(N, S, E, W)を入力してから、対角方位を入力します。
slots = ("n", "s", "e", "w", "ne", "se", "nw", "sw")
light_types = ("light", "distantlight", "domelight")
lop_category = hou.nodeTypeCategories()["Lop"]

lights = []
for light_type in light_types:
    # ノードタイプオブジェクトを取得します。
    nodetype = hou.nodeType(lop_category, light_type)
    # このノードタイプのインスタンスを検索して、それらのインスタンスをリストに追加します。
    lights.extend(nodetype.instances())

# 最後に編集された時間でLight LOPsのリストをソートします(直近で編集されたLOPが最初になるように並びを逆にします)。
lights.sort(key=lambda n: n.modificationTime(), reverse=True)

# 直近の8個のLight LOPsからメニューを構築します。
menu = {}
for slot, light in zip(slots, lights[:8]):
    menu[slot] = {
        "type": "script_action",
        "label": light.name(),
        "icon": light.type().icon(),
        "script": lambda n=light, **kwargs: n.setCurrent(True, clear_all_selected=True)
    }

radialmenu.setRadialMenu(menu)

Tip

Pythonの残念な"落とし穴"は、lambdaまたはローカル関数でループ変数の値を取得しようとすると、期待した値が得られないことです。例:

for i, light in enumerate(lights):
    menu[slot] = {"script": lambda **kwargs: light.setCurrent(True)}

あなたが期待していたのは、ループで定義された各lambdaがそのループの反復時点でのLight LOPの参照を持っていることだったのではないでしょうか。 しかし、Pythonが行っている事は そうではありません

代わりにlambdaはlightのLexical参照(字句参照)を取得します。 これは、ローカルコンテキストでの変数の 現行 値を常に指しています。 つまり、ループの最後では、生成されたlambdaのすべてのlight参照は、同じであり、light最終 値(リスト内の最後の値)を指します。 サンプルのスクリプトで言えば、すべてのアイテムがまったく同じノード(リスト内の最後のノード)を選択することを意味します。

下記のサンプルで示しているとおり、簡単な回避策は、取得したい変数をキーワード引数としてlambdaに渡すことです:

for i, light in enumerate(lights):
    menu[slot] = {"script": lambda n=light, **kwargs: n.setCurrent(True)}

別の方法としては、コール元のループとは別の独自のコンテキスト内で変数を取得する別の"ラッパー"関数をコールすることです:

def makeSelectFn(light):
    # コールされると、指定したライトを選択する関数を返します。
    def wrapper(**kwargs):
        light.setCurrent(True)
    return wrapper

for i, light in enumerate(lights):
    menu[slot] = {"script": makeSelectFn(light)}

Tipsとメモ

  • Radialメニューショートカットを使用することで、スクリプトを ホットキーシーケンス に割り当てることができます。

    例えば、Radialメニューを作成することができます。

  • メニューに8個未満の項目しかない場合、その"隙間"の隣の項目の"ヒット領域"が、その隙間を埋めるために大きくなります。つまり、項目の少ないメニューの方が、それらの項目をヒットしやすくなります。

  • hou.SceneViewer.displayRadialMenu()を使ってプログラム的にメニューを表示させることができます。このメニューはマウスポイント下で開かれます。

基本

はじめよう

次のステップ

カスタマイズ

導師レベル