シングルスレッド カスタム ICENode

 
 
 

カスタム ICENodes は、デフォルトではマルチスレッドで処理されます。しかし、場合によっては、1 つのシングル スレッドでノードを処理する方法が必要になることもあります。 シングル スレッド処理では、マルチ スレッドのバッチ処理とは対照的に、入力データ セット全体に同時にアクセスできます。 シングル スレッド モードは、average、min、max などの単純な数学関数を実装する場合に便利です。 バウンディング ボックス ジェネレータやパーティクル衝突検出機能など、さらに高度なノードを実装するためにもこのモードを使用できます。 バウンディング ボックス ジェネレータはマルチスレッドでも実装できますが、マルチスレッド処理が終了した後で、収集された他の値の中から最小値と最大値を見つけるためにユーザが追加の操作を実行しなければなりません。

シングルスレッド処理を有効にするための最初の手順では、スレッド モデルを siICENodeSingleThreadingModel に設定します。この手順は、ICENodeDef::PutThreadingModel でのノード登録時に実行する必要があります。入力ポートと出力ポートは、以下のルールに従って定義する必要があります。

  1. すべての入力ポートは Singleton コンテキス(siICENodeContextSingleton)で設定する必要があります。Singleton コンテキストで設定しない場合、すべての入力ポートのコンテキストをそのコンテキスト タイプによって制限する必要があります。

  2. 出力ポートのコンテキスト タイプは問いません。

最初のルールに従わない場合、登録時にエラーが記録され、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;
}