カスタム ICENodes は、デフォルトではマルチスレッドで処理されます。しかし、場合によっては、1 つのシングル スレッドでノードを処理する方法が必要になることもあります。 シングル スレッド処理では、マルチ スレッドのバッチ処理とは対照的に、入力データ セット全体に同時にアクセスできます。 シングル スレッド モードは、average、min、max などの単純な数学関数を実装する場合に便利です。 バウンディング ボックス ジェネレータやパーティクル衝突検出機能など、さらに高度なノードを実装するためにもこのモードを使用できます。 バウンディング ボックス ジェネレータはマルチスレッドでも実装できますが、マルチスレッド処理が終了した後で、収集された他の値の中から最小値と最大値を見つけるためにユーザが追加の操作を実行しなければなりません。
シングルスレッド処理を有効にするための最初の手順では、スレッド モデルを siICENodeSingleThreadingModel に設定します。この手順は、ICENodeDef::PutThreadingModel でのノード登録時に実行する必要があります。入力ポートと出力ポートは、以下のルールに従って定義する必要があります。
すべての入力ポートは Singleton コンテキス(siICENodeContextSingleton)で設定する必要があります。Singleton コンテキストで設定しない場合、すべての入力ポートのコンテキストをそのコンテキスト タイプによって制限する必要があります。
最初のルールに従わない場合、登録時にエラーが記録され、ICENode の登録が中止されます。
次の例では、シングルスレッド モデルを使用してジオメトリ頂点からバウンディング ボックスを生成する方法を示しています。
XSIPLUGINCALLBACK CStatus XSILoadPlugin( PluginRegistrar& in_reg )
{
in_reg.PutAuthor(L"Softimage");
in_reg.PutName(L"BBoxGenerator Plugin");
in_reg.PutVersion(1,0);
ICENodeDef nodeOpDef;
nodeOpDef = Application().GetFactory().CreateICENodeDef(L"BBoxGenerator");
// Set the threading model to single-thread
CStatus st;
st = nodeOpDef.PutThreadingModel(XSI::siICENodeSingleThreading);
st.AssertSucceeded( ) ;
// Add input ports and groups.
st = nodeOpDef.AddPortGroup(ID_G_100);
st.AssertSucceeded( ) ;
st = nodeOpDef.AddInputPort(
ID_IN_vector3, // port index
ID_G_100, // group index
siICENodeDataVector3, // data type
siICENodePortStructureSingle, // structure type
siICENodeEvaluationContextAny, // context type
L"vector3", // port name
L"vector3", // port scripting name
MATH::CVector3f(1.0,1.0,1.0)// default value
);
st.AssertSucceeded( ) ;
// Add output ports.
st = nodeOpDef.AddOutputPort(
ID_OUT_minPos, // port index
siICENodeDataVector3, // data type
siICENodePortStructureSingle, // structure type
siICENodeContextSingleton, // context type
L"minPos", // port name
L"minPos"// port scripting name
);
st.AssertSucceeded( ) ;
st = nodeOpDef.AddOutputPort(
ID_OUT_maxPos, // port index
siICENodeDataVector3, // data type
siICENodePortStructureSingle, // structure type
siICENodeContextSingleton, // context type
L"maxPos", // port name
L"maxPos"// port scripting name
);
st.AssertSucceeded( ) ;
PluginItem nodeItem = in_reg.RegisterICENode(nodeOpDef);
nodeItem.PutCategories(L"Custom ICENode");
return CStatus::OK;
}
XSIPLUGINCALLBACK CStatus BBoxGenerator_Evaluate( ICENodeContext& in_ctxt )
{
ULONG nPortID = in_ctxt.GetEvaluatedOutputPortID();
switch ( nPortID )
{
case ID_OUT_minPos:
case ID_OUT_maxPos:
{
Application xsi;
CDataArrayVector3f posArray( in_ctxt, ID_IN_vector3 );
CDataArrayVector3f outData( in_ctxt );
CVector3f v3fMin(FLT_MAX,FLT_MAX,FLT_MAX);
CVector3f v3fMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
CIndexSet indexSet( in_ctxt );
for ( CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next() )
{
CVector3f& v3f = posArray[ it ];
if ( v3fMin.GetX() > v3f.GetX() && v3fMin.GetY() > v3f.GetY() && v3fMin.GetZ() > v3f.GetZ() )
{
v3fMin = v3f;
}
else if ( v3fMax.GetX() < v3f.GetX() && v3fMax.GetY() < v3f.GetY() && v3fMax.GetZ() < v3f.GetZ() )
{
v3fMax = v3f;
}
}
if ( ID_OUT_minPos == nPortID )
{
xsi.LogMessage( L"BBox Min: " + CString( v3fMin ) );
outData[ 0 ] = v3fMin;
}
else
{
xsi.LogMessage( L"BBox Max: " + CString( v3fMax ) );
outData[ 0 ] = v3fMax;
}
}
break;
};
return CStatus::OK;
}