ネイティブ配列の使用

 
 
 

各スクリプト言語は、それぞれ独自の配列の実装を使用していますが、すべてにいくつかの共通点があります。 たとえば、すべての言語の配列は、値またはオブジェクトのリストです。また、各言語には、項目を追加または削除するツールのセットが用意されています。

ほとんどのスクリプト開発者は、それぞれの目的に応じて配列を使用、作成、操作しますが、多くの Softimage 関数では、入力として配列を取るか、出力として配列を戻すかのどちらかであるため、Softimage で配列を使用してスムーズに作業する方法について理解することが重要です。 以下のセクションで、さまざまなスクリプト言語での配列の使い方を示します。

戻り値の配列を使用する

一部のコマンド、メソッド、およびプロパティは値の配列を戻します。 使用するスクリプト言語に応じて、Visual Basic のセーフ配列または配列の配列のいずれかを取得できます。 たとえば、VBScript または JScript でコマンド GetMarking()を実行すると、Visual Basic のセーフ配列が取得されます。PerlScript で GetMarking()を実行すると、ネストされた配列(配列の配列)が取得されます。Python の場合はタプルが取得されます。

VBScript では、ネイティブ配列は SafeArray と呼ばれ、Softimage オブジェクト モデルのように Variant 内部と Automation スクリプティング オブジェクトで使用される標準的な配列です。 以下のような VBScript 以外のスクリプト言語では、異なる方法が使用されます。

VBScript

SafeArray は、VBScript のネイティブ配列であるため、標準的な VBScript メソッドを使用して戻された配列を操作できます(詳細は、http://msdn.microsoft.com/を参照)。

VBScript の例: 戻された配列をループする

Dim arrMarkedParams, strItem, i
GetPrim "Null"
SetMarking "kine.local.pos,kine.global.pos"
AddToMarking "kine.local.ori"
arrMarkedParams = GetMarking()
for i=0 to UBound(arrMarkedParams)
   strItem = arrMarkedParams(i)
   LogMessage "Value of item at index " & i " = & strItem
next

' Expected result:
'INFO : Value of item at index 0 = kine.local.pos
'INFO : Value of item at index 1 = kine.global.pos
'INFO : Value of item at index 2 = kine.local.ori

JScript

JScript で戻された配列を操作するには、いくつかの制限があります。JScript にはネイティブの Array オブジェクトがありますが、そのオブジェクトは SafeArray ではないため、多次元をサポートしないからです。 ただし、Softimage インターフェイスの多くの部分で、SafeArray の代わりに JScript の配列を提供できます。 たとえば、ネイティブの JScript 配列を Envelope.SetDeformerWeights(Weights パラメータ)に渡すことができますが、Envelope.GetDeformerWeights は SafeArray を返します(Envelope.SetDeformerWeights の例を参照)。

さらに、JScript では、VBArray と呼ばれる特殊なオブジェクトも利用できます。 VBArray オブジェクトは、SafeArray から読み取る(たとえば、多次元の上限/下限値にアクセスする)ことができる関数を提供し、VBArray を JScript ネイティブの Array に変換する toArray()と呼ばれる便利なメソッドも提供します。

ほとんどのスクリプト開発者は、値を読み取るだけの場合でも JScript 配列で操作したがります。この理由は、VBArray を JScript 配列に変換するのは非常に簡単(var jsArray = vbArray.toArray();)で、JScript の Array オブジェクトには、操作に便利なメソッドが数多くあるためです(VBArray はデータへの基本的なアクセスを提供するためだけに設計されています)。

注:

これらの配列オブジェクトのいずれかで使用可能なメソッドについては、http://msdn.microsoft.com/en-us/library/k4h76zbx(VS.85).aspx を参照してください。

JScript と 1 次元(フラット)の SafeArray

JScript の Array オブジェクトは 1 次元であるため、1 次元の配列の読み書きは問題ありません。

  • 読み取る場合は、VBArray.toArray() メソッドを使用して、戻された SafeArray を JScript 配列に変換するだけです。

  • 書き込む場合は、VBArray から変換されたか、new Array() コンストラクタでゼロから作成された JScript 配列を使用します。 入力として 1 次元の SafeArray を取る関数は、JScript 配列を受け取ると自動的に変換します。

    ヒント:

    JScript で 1 次元の SafeArray を変換して読み取る方法については、「JScript の例: 戻された配列をループする(VBArray 経由)」の例を参照してください。

    1 次元の SafeArray を JScript 配列に変換し、変更を加えて、Envelope.GetDeformerWeights 経由で再度書き込む方法については、Envelope.SetDeformerWeights リファレンス ページの JScript の例を参照してください。

JScript と多次元

SafeArray では、多次元の概念をサポートしています。 一般的に、Softimage では、1 次元(フラット)の配列を使用しますが、テーブルまたはスプレッドシート グリッドという特徴がある 2 次元の配列を使用する場合もたまにあります。 第 1 次元は行、第 2 次元は列、各エントリはセルをそれぞれ示します。

たとえば、ClusterElementCollection を使用すると、ClusterProperty UV データを特定の Cluster にマッピングすることができます。これらのクラスタは、各行がクラスタのコンポーネント インデックスを表し、各列が該当するクラスタの RGBA 頂点カラー値を表す 2 次元配列として管理されます。

JScript(ネイティブ)配列は、常に 1 次元、つまり、値のテーブルまたはグリッドではなく 1 つの長い値のリストまたはリファレンスです。 戻り値を読み取るには、VBArray オブジェクトのメソッド(「JScript と 1 次元(フラット)の SafeArray」を参照)を使用してデータにアクセスできます。

注:

SafeArray を JScript 配列に変換する場合は、連続する各次元が第 1 次元に追加されることで、SafeArray の余分な次元がフラットの JScript 配列に折りたたまれることを認識しておく必要があります。

JScript では、Softimage コマンド、メソッド、およびプロパティは常に SafeArray を戻すため、次のいずれかの回避策を使用する必要があります。

  • GridData オブジェクトに保存します。このオブジェクトは 2 次元の SafeArray をシミュレートします。 詳細については、「GridData オブジェクトの使用」を参照してください。

  • 戻された SafeArray を VBArray オブジェクト内にカプセル化する。

JScript の例: 戻された配列をループする(VBArray 経由)

この例では、JScript で 1 次元の SafeArray を変換して読み取る方法を示します。

GetPrim( "Null" );
SetMarking( "kine.local.pos,kine.global.pos" );
AddToMarking( "kine.local.ori" );

// GetMarking() returns a VBArray, which you can 
// convert to a JS Array with the toArray() function
var vbaMarkings = new VBArray( GetMarking() );
var jsaMarkings = vbaMarkings.toArray();
for ( var i=0; i<jsaMarkings.length; i++ ) {
	LogMessage( jsaMarkings[i] );
}

// Expected result:
//INFO : kine.local.pos
//INFO : kine.global.pos
//INFO : kine.local.ori
ヒント:

上の例は、戻された SafeArray を段階的に JScript 配列に変換する方法を示しています。

var vbaMarkings = new VBArray( GetMarking() );
var jsaMarkings = vbaMarkings.toArray();

上の 2 行の代わりに、次のショートカットを使用することもできます。

var jsaMarkings = GetMarking().toArray();

JScript の例: 戻された 2 次元の VBArray を GridData オブジェクトで管理する

以下の例は、グリッドを作成し、頂点カラーを適用する例の一部(ClusterElementCollection.Array を参照)です。 次に、GridData を使用してクラスタ プロパティの値を表示します。ここでは GridData オブジェクトが検査されます。

このコードでは、最初に頂点カラー プロパティ上のクラスタ プロパティへのポインタを取得します。

// Returns a ClusterElementCollection
var cls_prop_elems = vertexcolor.Elements;

// Returns a VBArray
var vbValues = cls_prop_elems.Array;
Application.LogMessage( "# of dimensions: " + vbValues.dimensions() );
for ( var d=1; d<=vbValues.dimensions(); d++ ) {
   Application.LogMessage( "range of dimension " + d + ": " + vbValues.lbound(d) + ".." + vbValues.ubound(d) );
}

// Display info
var gridtable = MakeMeAPPG( vbValues );
InspectObj( gridtable, "", "", siModal, false );

// Change info
grid_mod = gridtable.Parameters("VertexColorChart").Value;
grid_mod.SetCell( 0, 0, 1.23 );
DeleteObj( gridtable );
gridtable = MakeMeAPPG( grid_mod.Data );

// Re-display modified info
InspectObj( gridtable, "", "", siModal, false );

このコードは、GridData パラメータでカスタム パラメータを作成する方法を示します。この場合、GridData は 2 次元の配列のように動作します。

// ***************************************
//
// 		Functions to support PPG
//
function MakeMeAPPG( in_SafeArray )
{
   var gprop = ActiveSceneRoot.AddProperty( "CustomProperty", false, "Visual2DArray" );			
   var gparam = gprop.AddGridParameter( "VertexColorChart" );
   var ugrid = gparam.Value;
	
   // Set bounds of this grid
   ugrid.ColumnCount = in_SafeArray.ubound(1)+1;
   ugrid.RowCount = in_SafeArray.ubound(2)+1;
   ugrid.Data = in_SafeArray;
	
   // Set up the labels
   var tmp = new Array( "R", "G", "B", "A" );
   for ( var c=0; c<ugrid.ColumnCount; c++ ) {
      ugrid.SetColumnLabel( c, tmp[c]) ;
   }
   for ( var r=0; r<ugrid.RowCount; r++ ) {
      ugrid.SetRowLabel( r, "Cluster " + r.toString() );
   }
	
   // Return the Property Set (not the Grid itself)
   return gprop;
}

PerlScript

PerlScript を使用している場合に取得するエレメントは、以下を含む配列へのリファレンスです。

  • 値(戻された配列が 1 次元の場合)

  • 値の配列へのリファレンス(戻された配列が 2 次元の場合)

  • 値の配列へのリファレンスの配列へのリファレンス(戻された配列が 3 次元の場合)

つまり、戻された配列内でネストされた配列を逆参照して、各次元を抽出する必要があります。 ほとんどの場合、SDK 関数は 1 次元の配列を戻します。したがって、ネストされた配列に含まれるエレメントは 1 つだけであると想定されるため、この配列を逆参照するだけで操作できます。 多次元配列の場合、ネストされた配列に複数のエレメントが含まれます。それぞれのエレメントは、「PerlScript の例: 戻された多次元配列をループする」に示す方法で逆参照することができます。

PerlScript の例: 戻された 1 次元配列をループする

$Application->GetPrim( "Null" );

# Mark some parameters on the null
$Application->ClearMarking();
$Application->SetMarking( "kine.local.pos,kine.global.pos" );
$Application->AddToMarking( "kine.local.ori" );

# The GetMarking command is supposed to return a 1-dimensional array...
my $array = GetMarking();
for $item (@$array) {
   $Application->LogMessage( "Marked parameters: $item" );
}

# Expected result:
#INFO : kine.local.pos
#INFO : kine.global.pos
#INFO : kine.local.ori

PerlScript の例: 戻された多次元配列をループする

このコード断片は、テクスチャ サポートを立方体に適用し、UVW 値を 2 次元配列として抽出する例の一部(ClusterElementCollection を参照)です。

my $uvw_prop = $object->Material->CurrentUV;
my @rtn = $uvw_prop->Elements->Array;

for my $array_ref (@nested_array) {
   for my $value_for_u_v_or_w (@{$array_ref}) {
      # ...
   }
}

Python

Python は ActiveX スクリプト エンジンを使用するため、すべての SafeArray をタプルに自動的に変換します。 タプルは、Python で利用できる次の 2 種類の配列の一つです。

  • タプル: 多くの場合、関数から複数の値を返すために使用される固定シーケンス。VBScript の静的配列とほぼ同じ。

  • リスト: 値の動的配列。VBScript の動的配列とほぼ同じ。

Python では、タプルやリストの操作にさまざまな種類の非常に強力な関数が利用できます。 詳細は、詳細情報の参照先 に記載されている Python サイトを参照してください。

注:

重要な配列操作(特に多次元配列や行列での作業)を行う必要がない場合は、Numerical Python 拡張子を使用してください。 詳細については、http://sourceforge.net/projects/numpy を参照してください。

Python の例: 戻された配列をループする

Application.GetPrim( "Null" )
Application.SetMarking( "kine.local.pos,kine.global.pos" )
Application.AddToMarking( "kine.local.ori" )
markings = Application.GetMarking()
i = 0
for mrk in markings
   Application.LogMessage( "Value of item at index " + str(i) + " = " + mrk )
   i = i + 1

# Expected result:
#INFO : Value of item at index 0 = kine.local.pos
#INFO : Value of item at index 1 = kine.global.pos
#INFO : Value of item at index 2 = kine.local.ori