Houdini 21.0 キャラクタ KineFX

APEX Script言語リファレンス

On this page

このページでは、用意されている型、演算、ステートメントなどのAPEX Scriptの構文と言語要素について説明しています。

構文

APEX Scriptの構文は、Pythonから多くを借用していますが、主な違いは、APEX Scriptの変数の型が静的に型付けされていることです。つまり、変数が特定の型として定義されると、その変数の型を変更することはできません。

インデントは、コードのブロックを示します。forまたはifステートメントの後の行をインデントしない、あるいは、forまたはifブロックの外側で行をインデントした場合には、APEX Scriptでエラーが発生します。

コメント行は#で始まります。#に続くテキストは、すべてコメントアウトされます。コードブロックをコメント化するには、 Snippet パラメータ内のコードブロックを選択し、⌃ Ctrl + /を押します。

変数

変数は、データ値を格納するためのコンテナで、値を割り当てた時に作成されます。変数名は、大文字、小文字、数字、アンダースコア(_)で構成することができますが、数字で始めることはできません。変数名は大文字小文字の区別があります。

# Value<Float>ノードを作成し、1.5に初期化します
f = 1.5
変数の初期化から作成されたValueノード

データ型

変数は、様々な型のデータを格納できます。APEX Scriptで使用できるデータ型はNullノードのドキュメントに載せており、<type>()(例えば、Float()String()Dict()など)を使用して初期化することができます。

# デフォルト値0でfloatを作成します
f1 = Float()

# floatを作成し、1.5に初期化します
f2 = Float(1.5)

# グラフハンドルオブジェクトを作成します
g = ApexGraphHandle()

変数の型が明示的に指定されていない場合、最初に割り当てられた値からその型が推測されます:

# xはfloatです
x = 1.5

変数が特定の型で初期化された後で、型を変更することはできません:

x = 3

# 型を変更しようとすると、エラーが発生します
x = 'string'

特定のデータ型は、他の型に変換することができます。他の型に変換可能な型についての詳細は、Convertを参照してください:

# 浮動小数点型
a = 1.5

# 浮動小数点型を整数型に変換します
b = Int(a)

# 整数型をブール型に変換します
c = Bool(b)

ランプ

ランプとは、浮動小数点数の値またはやカラーがランプの長さに沿って変化する関数のことです。FloatRampおよびColorRampの値は、以下の構文を使用して設定することができます:

FloatRamp(basis=<StringArray or IntArray>, keys=<FloatArray>, values=<FloatArray>)

ColorRamp(basis=<StringArray or IntArray>, keys=<FloatArray>, values=<Vector3Array>, [colortype=<string>])

ここでは:

  • keys - ランプ上のキーの位置を格納した、0.0から1.0の間のfloat値。

  • values - 各キーに格納された値。

  • basis - キーとキーの間の補間タイプ。IntArrayを使用してbasisの値を指定する場合、整数値と補間タイプの関係は以下の表の通りです:

    整数値

    補間タイプ

    0

    Constant

    1

    Linear

    2

    Catmull-Rom

    3

    Monotone Cubic

    4

    Bezier

    5

    B-Spline

    6

    Hermite

  • colorType - ColorRampにおいて、補間に使用されるカラー空間です。このパラメータはオプションです。

詳細は、hou.Rampを参照してください。

FloatRamp:

r1 = FloatRamp(["Linear", "Linear"], [0.3, 1.0], [0.2, 0.8])

r2 = FloatRamp(basis=["MonotoneCubic", "Constant", "Bezier"], 
               keys=[0.2, 0.6, 0.8], 
               values=[0.1, 0.9, 0.3])
FloatRamp r1(上)、r2(下)

Note

basis配列の最後の値は関係ありません。なぜなら、その後に続くキーが存在しない場合、最後のキーの値がそのまま一定に保たれるためです。

ColorRamp:

c1 = ColorRamp(basis=["MonotoneCubic", "Linear", "Bezier"], 
               keys=[0.1, 0.4, 1.0], 
               values=Vector3Array((1,0,0), (0,1,0), (0,0,1)), 
               colortype='HSV')

# basisに整数配列を使用しても同じ結果になります
c2 = ColorRamp(basis=[3, 1, 4], 
               keys=[0.1, 0.4, 1.0], 
               values=[(1,0,0), (0,1,0), (0,0,1)], 
               colortype='HSV')
ColorRamp

basiskeysvaluesの配列は定数でなければなりません:

# エラー
x = [0.3, 1.0]
rr = FloatRamp(["Linear", "Linear"], x, [0.2, 0.8])

注釈(アノテーション)

Pythonスタイルの注釈を使用して、変数または関数の引数が特定の型であることを示すことができます。注釈は、辞書関数の引数を定義したり、グラフ入力タイプを指定するのに重要です。注釈の構文は以下の通りです:

<argument>: <annotation>

注釈付きの変数は、明示的に初期化されるまで初期化されません。したがって、注釈付きの変数は初期化されるまで使用することができません:

# 初期化されていない変数
a: Float

# 別の変数を初期化します
b = Float(1)

# 'a'は初期化されていないため、エラーが発生します
b = a + b

変数に注釈を付け、初期化します:

# 変数に注釈を付け、初期化します
a: Float = 1.5

# 別の変数を初期化します
b = Float(1)

# これは機能します
b = a + b

定数

定数とは、値が変更されない変数のことです。APEX Scriptでは、以下の定義済みの定数が利用可能です:

数学定数:

  • M_PI = 3.14159

  • M_E = 2.71828

  • M_SQRT2 = 1.41421

カラー:

  • RED

  • GREEN

  • BLUE

  • BLACK

  • WHITE

    例:

    a = int(2, __color=GREEN)
    

演算子

演算子は、値や変数に対して演算を実行するのに使用します。

算術演算子

算術演算子は、数学的演算を実行するのに使用します。

演算

演算子

加算

+

x = 1 + 2

減算

-

x = 2 - 1

乗算

*

x = 1 * 2

除算

/

x = 2 / 1

累乗

**

x = 2 ** 3

割り当て演算子

割り当て演算子は、値を変数に割り当てるのに使用します。

演算

演算子

加算

+=

# x = x + 2
x += 2

減算

-=

# x = x - 2
x -= 2

乗算

*=

# x = x * 2
x *= 2

除算

/=

# x = x / 2
x /= 2

累乗

**=

# x = x ** 2
x **= 2

比較演算子

比較演算子は、2つの値を比較するのに使用します。比較演算の結果はboolean値(TrueまたはFalse)です。

演算

演算子

等しい

==

x == 3

等しい(isを使用)

is

x is 3

等しくない

!=

x != 3

等しくない(is notを使用)

is not

x is not 3

より大きい

>

x > 3

未満

<

x < 3

以上

>

x >= 3

以下

<

x <= 3

論理演算子

論理演算子は、特定の条件が真であるかどうかを確認するのに使用します。

演算

演算子

説明

論理積

and

両方の条件が真である場合、Trueを返します。

x == 3 and y == 2

論理和

or

いずれかの条件が真である場合、Trueを返します。

x == 3 or y == 2

論理否定

not

条件が真でない場合に、Trueを返します。

not(x == 3)

メンバーシップ演算子

メンバーシップ演算子は、値が文字列または配列に含まれるかどうかをチェックするのに使用します。

演算子

説明

in

値が文字列または配列に含まれる場合、Trueを返します。

x in a

not in

値が文字列または配列に含まれない場合、Trueを返します。

x not in a

演算子の優先順位

以下に、様々な演算子の優先順位を高い順からリストします:

  • 括弧

  • 累乗

  • 乗算、除算

  • 加算、減算

  • 比較、メンバーシップ

  • 論理否定

  • 論理積

  • 論理和

文字列

文字列は、シングルクォートまたはダブルクォートで閉じることで指定することができます。

# 空っぽの文字列
s1 = ''

# 文字列を作成および初期化します
s2 = 'hello_world'
s3 = String("hello_world")

複数行にわたる文字列は、トリプルクォート('''または""")で囲みます。

multi_s = """This is the longest string
in the world."""

文字列を+で連結します:

a = 'Hello'
b = 'world'
c = a + ' ' + b

関数len()は、文字列内の文字数を返します:

s = 'hello world'

# s_len = 11
s_len = len(s)

APEX Scriptでは、Pythonスタイルの文字列の書式化がサポートされています。文字列の書式化を行なうには、文字列の前にfを追加し、中括弧{}を使用して文字列に対して実行する書式化を指定します。書式化の仕様についての詳細は、string::Formatを参照してください。

s = 'world'
a = 1.2
b = 2.3

# s2 = "hello world +3.50"
s2 = f"hello {s} {a+b:+.2f}"

APEX Scriptで利用可能な文字列の処理については、string::*ノードを参照してください。

配列

配列を使用すると、単一の変数に複数の同じ型のアイテムを格納することができます。配列は、大括弧[]を使用して定義します。配列内のエレメントはインデックス化され(最初のエレメントのインデックスは0、2番目のエレメントのインデックスは1など)、インデックス番号を参照してアクセスすることができます。配列エレメントの型は、Nullノードのドキュメント<type>Arrayとしてリストされたもののいずれかです。

APEX Scriptで利用可能な配列の処理については、array::*ノードを参照してください。

配列を作成および初期化します:

# 空っぽの配列
a1 = IntArray()
a2: IntArray = []
a3: IntArray = IntArray()

# デフォルト値で配列を初期化します
a4 = IntArray(1,2,3)

f = 1.5
a5 = [f,f]

# 文字列の配列
s = 'hi'
arr_of_str = [s,'bbb','ccc']

# ベクトルの配列
v = (1,2,3)
arr_of_vec = [v,v]

関数len()は、配列内のアイテム数を返します:

a = [2,4,6]

# a_len = 3
a_len = len(a)

配列エレメントを設定および取得します:

# 配列を作成します
a = ['x','y','z']

# 配列エレメントを設定します
a[0] = 'aaa'
a[1] = apex.string.fromInteger(3)

# 配列エレメントを取得します
elem = a[2]

マイナスのインデックスは、配列の最後から数えたエレメントを取得します:

# 配列を作成します
a = ['x','y','z']

# neg = 'z'
neg = a[-1]

エクスプレッションを使用して配列のインデックスを指定します:

a = IntArray(1,2,3)
x = 5

# a = [3,2,3]
a[Int(0.5)] = a[Int(x-3)]

# a = [0,2,3]
a[Int(x-5)] = 0

インデックスをネスト(入れ子)化します:

arr1 = [0,1,2]
arr2 = [5,10,15]

# arr_elem = 15
arr_elem = arr2[arr1[2]]

+および+=演算子を使用すると、配列を拡張することができます:

arr1 = [1,2]
arr2 = [3,4]
arr3 = [5,6]

arr4 = arr1
arr4 += arr2

arr5 = arr4 + arr3

# 結果: arr4 = [1,2,3,4], arr5 = [1,2,3,4,5,6]

辞書配列を使用します:

# 辞書の配列を作成します
dict1 = {'test': 1.0, 'c': 5}
dict2 = {'alpha': 'aaa', 'beta': 'bbb'}
dictarray = [dict1, dict2]

# 最初の配列エレメントで辞書を置換します
dictarray[0] = {'x': 'hello_world'}

ベクトル

ベクトルは、単一変数に同じ型の複数のアイテムを格納します。APEX Scriptでは、ベクトルの長さは2、3、または4です。ベクトルは括弧()を使用して定義し、括弧内のエレメントの数によって、ベクトルの型がVector2、Vector3、Vector4のいずれであるかが決まります。

例として、Vector3を使用してベクトルを初期化します:

# ゼロベクトルを作成します
v1 = Vector3()

# すべてのエレメントが5に初期化されたベクトルを作成します
v2 = Vector3(5)

# ベクトルを作成および初期化します
v3 = (1,2,3)
v4 = Vector3(1,2,3)

# 変数でベクトルを初期化します
a = Float(1)
v5 = Vector3(a*1,a+1,3)

ベクトルコンポーネントを取得および設定します:

# ベクトルを作成します
v = Vector4(5,10,15,20)

# ベクトルコンポーネントを取得します
v_1 = v[1]

v_x = v.x() # 1番目のベクトルコンポーネント
v_y = v.y() # 2番目のベクトルコンポーネント
v_z = v.z() # 3番目のベクトルコンポーネント
v_w = v.w() # 4番目のベクトルコンポーネント

# 定数ではないベクトルインデックスを使用します
i = 2
v_i = v[i+1]

# ベクトルコンポーネントを設定します
v[1] = 100

# ベクトルを作成し、コンポーネントを取得します
x = Vector3(2,4,6)[1]

マトリックス

マトリックスは基本的に2次元のベクトルで、マトリックス内のすべてのコンポーネントは同じ型です。マトリックスは括弧()を使用して定義し、括弧内のエレメントの数によって、マトリックスの型がMatrix3(9個のエレメントを持つ3×3マトリックス)であるか、またはMatrix4(16個のエレメントを持つ4×4マトリックス)であるかが決まります。

Matrix3を例に挙げると、マトリックスは3個のVector3のコレクション、つまり9個のコンポーネントを持つ“ベクトル”であると見なすこともできます。

例として、Matrix3を使用してマトリックスを初期化します:

# 単位行列を作成します
m1 = Matrix3()

# 対角線上の値が2に設定されたマトリックスを作成します
m2 = Matrix3(2)

# マトリックスを初期化します
m3 = (1,2,3,4,5,6,7,8,9)
m4 = Matrix3(1,2,3,4,5,6,7,8,9) 
m5 = Matrix3((1,2,3),(4,5,6),(7,8,9))

# 変数でマトリックスを初期化します
v = (1,2,3)
m6 = (v,(4,5,6),(7,8,9))

a = Float(1)
m7 = (a,2,3,4,5,6,7,8,9)
m8 = Matrix3(a+1,a+2,a+3,4,5,6,7,8,9)

マトリックスコンポーネントを取得および設定します:

# マトリックスを作成します
m = Matrix3(1,2,3,
            4,5,6,
            7,8,9)

# マトリックスコンポーネントを取得します
m_12 = m[1][2]

# マトリックスの行を取得します
m2 = m[2]

# 定数ではないマトリックスインデックスを使用します
i = 1
m_i = m[i+1][i]

# *** 定数ではないインデックスを使用することはできません 
# m_i = m[i]など、マトリックスの行を指定します

# マトリックスコンポーネントを設定します
m[2][1] = 20

# マトリックスの行を設定します
m[1] = (10,10,10)

辞書

辞書を使用すると、キーと値のペアでデータを格納することができます。辞書は中括弧{}を使用して定義し、その中括弧の中には<key>:<value>エントリのリストを入れます。キー名は文字列型である必要があり、値は任意の型で構いません。辞書には、同じキーで異なるエントリを含めることはできません。

APEX Scriptで利用可能な辞書の処理については、dict::*ノードを参照してください。

辞書を作成します(これらの辞書は後続の例で使用します):

# 空っぽの辞書
d1 = Dict()
d2: Dict = {}
d3: Dict = Dict()

dict = {
    'key1': 1.0, 
    'key2': 'hello_world'
}

# ネスト化された辞書
dict_nested = {
    'test1': 2, 
    'test2': [1,2,3],
    'test3': {
        '3a': 1.5,
        'say': 'hello_world'
    },
    'd_array': DictArray(
        {'a': 1}
    )
}

関数len()は、辞書内のエントリの数を返します:

d = {
    'a': 1,
    'b': 3.5,
    'c': 'test'
}

# d_len = 3
d_len = len(d)

辞書のエントリは、大括弧[]内のキー名によって参照されます。辞書にアイテムを追加するには:

# 辞書に定数を追加します
dict['key3'] = 5.0

# 変数から辞書に追加します
dict['key4'] = dict_nested

# 辞書に配列エレメントを追加します
test_tags = ['tag1', 'tag2', 'tag3']

dict['tag'] = test_tags[0]

# 辞書に別の辞書を追加します
dict['d_test'] = {
    'x': 10,
    'y': 20
}

# ネスト化された辞書にエントリを追加します
dict_nested['test3']['x'] = 'testing'
dict_nested['d_array'][0]['b'] = 2

既存の辞書のエントリに新しい値を設定します:

dict_nested['test3']['say']: String = 'hello_again'

辞書の値は任意の型であるため、辞書のエントリから変数を初期化する時は、型注釈を使用する必要があります:

s: String = dict['key2']
f: Float = dict_nested['test3']['3a']

注釈を使用した例:

# 2つのキーと値のペアで辞書を作成します
d1 = {'key1': Geometry(), 'key2': 1.2}

# もう1つ辞書を作成します
d2 = {'a': 2.2}

# 2つ目の辞書にエントリを追加します
d2['b']: Float = d1['key2']

条件

APEX Scriptは条件をサポートしており、ifステートメントに比較論理またはメンバーシップ演算子を組み合わせて使用します。ifelif (else if)およびelse部分はオプションです。ifステートメントの後のインデントされた行は、条件内で実行されるコードブロックです。

ifステートメントの構文は以下の通りです:

if <condition1>:
    <statement1>
elif <condition2>:
    <statement2>
else:
    <statement3>
  • <condition1>が真の場合、<statement1>が実行されます。

  • <condition1>が偽で、<condition2>が真の場合、<statement2>が実行されます。

  • <condition1>および<condition2>が両方とも偽の場合、<statement3>が実行されます。

比較演算子を使用したifステートメント:

x = 0

if x < 0:
    test = 'aaa'
elif x > 0:
    test = 'eee'
else:
    test = 'ccc'

メンバーシップ演算子を使用したifステートメント:

test_tags = ['aaa', 'bbb', 'ccc']
test = 'ccc'

# 配列にアイテムが含まれているかどうかをチェックします
if test in test_tags:
    test_tags.append('repeated_tag')

辞書のエントリが存在するかどうかをチェックするifステートメント:

d = {'a': 3}

if d['a']:
    x = 1

length関数のlen()を使用したifステートメント:

s = 'hello'

if len(s):
    x = 1

ネスト化されたifステートメント:

x = 10

if x >= 0:
    a = 'non-negative'

    if x > 0:
        b = 'positive'

ifステートメントの別の形式:

<statement1> if <condition> else <statement2>

a = 2
b = 3
cond = True

c = a if cond else b
d = (a+b) if (not cond) else (a*b)

# 結果: c = 2, d = 6

ループ

APEX Scriptはforループをサポートしており、配列のエレメントまたはintの範囲を反復します。forステートメントの後のインデントされた行は、実行されるコードブロックです。

forループの構文は以下の通りです:

for <element> in [<array>]:

h = 'hello'

for x in ['world', 'again']:
    h = h + ' ' + x

# forループ後の結果: h = 'hello world again'

rangeキーワードと括弧()内の反復回数を使用して、forループで特定の回数だけコードブロックを反復するように指定できます:

for <element> in range(<int>):

y = 0

for x in range(3):
    y = y + 1

配列エレメントを反復する時にインデックスにアクセスするには、enumerateキーワードを使用します:

for <index>, <element> in enumerate(<array>)

test_tags = ['aaa', 'bbb', 'ccc']

for t, test in enumerate(test_tags):
    test = (test + String(t))

# それぞれの反復の結果: aaa0、bbb1、ccc2

ネスト化されたforループ:

h = 'hello'
i: Int = 0

for x in range(3):
    for x in ['world', 'again']:
        h = h + ' ' + x
        i = i + 1

    i = i + 10

ジオメトリポイントおよびプリミティブをループさせます:

  • for <point_number> in geo.points()

  • for <primitive_number> in geo.prims()

geo = BindInput(Geometry())
transform = Matrix4()

for pt in geo.points():
    geo.transform(transform)

    for prim in geo.prims():
        geo.setPrimAttribValue(prim, 'name', 'test', valuetype=String)

Note

geo::SetPrimAttribValue<T>はテンプレート関数の例です。これらの特別なタイプの関数を指定する方法についての詳細は、テンプレート関数を参照してください。

グループ文字列を使用して、ジオメトリポイントおよびプリミティブをループします(geo::ForEachPointBegingroup 入力ポートの説明を参照してください):

geo: Geometry = BindInput()

for p in geo.points("0 1 2"):
    ...

for p in geo.points(group="0 1 2"):
    ...

g1 = "0 1 2"
for p in geo.prims(g1):
    ...

g2: String = BindInput("1 2 3")
for p in geo.prims(group=g2):
    ...

プリント、警告、エラーログ

APEX Scriptは、情報をプリントしたり、警告メッセージを出したり、エラーを発生させる機能に対応しています:

print('Hi there')

warning('Hi again')

raise error('This is a problem')

ログメッセージは、Log ViewerペインとAPEX Script SOPのNode Infoウィンドウに表示されます。Log Viewerペインを開くには:

  • ペインの上部にある New Tabアイコンをクリックして、 New Pane Tab Type ▸ Log Viewer を選択します。

    または

  • APEX Script SOPの View Logボタンをクリックします。

Log Viewerペインの上部のツールバーのをクリックして、 APEX がオンになっていることを確認します。APEX以外のメッセージをオフにするには、をクリックして、 Disable All を選択します。次に、再びをクリックして、 APEX をオンにします。

以下のログメッセージが表示されます:

/Log_message: Hi there

/Log_warning: Hi again

/Log_error: This is a problem

Note

print()warning()raise error()の関数は、LogノードをAPEXグラフに挿入します。APEXグラフは、部分評価の原理に基づいて動作します。つまり、グラフとその入力に変更がなかった場合、そのグラフは再び実行されることはなく、ログメッセージは再び出力されません。グラフが実行される度にログメッセージがプリントされるようにしたいのであれば、APEX Script SOPの Force Reload Graph パラメータをオンにします。

APEX Scriptは、ログに対して以下のフォーマットにも対応しています:

str = 'slept'
a = 1.0
b = 2.0

print('I', str, 'at', a*b)

# 文字列の頭に`f`または`F`を付けると、`{}`の中にエクスプレッションを入れることができます。
raise error(f'I stayed up til {a+b}')

BindOutput()

これは以下のように出力されます:

/Log_message: I slept at 2

/Log_error: I stayed up til 3

関数マッピング

APEX Scriptには、一部のビルトインのAPEX関数に対して便利な名前マッピングが用意されています。利用可能な関数マッピングのリストは、ここを参照してください。

KineFX

概要

キャラクタ要素の準備

APEXグラフを使用したリギング

APEXスクリプトを使用したリググラフの構築

リグコンポーネントを使用したリギング

ビューポート内でアニメーションを付ける

SOPベースのアニメーション

変形

アニメーションのリターゲット

H20以前

ペイン

別表