カスタム プリミティブを作成する

 
 
 

カスタム プリミティブ オブジェクトは、作成する前に XSILoadPlugin コールバックで登録する必要があります。このコールバックは Softimage で自己インストール プラグインがロードされたときに呼び出されます。PluginRegistrar.RegisterPrimitive メソッドを使用してカスタム プリミティブを登録できます。

SICALLBACK XSILoadPlugin(PluginRegistrar& in_reg)
{

	in_reg.PutAuthor(L"SoftimageUser");
	in_reg.PutName(L"CustomPrimitives Plug-in");
	in_reg.PutVersion(1,0);
 
	// Register primitive types
	in_reg.RegisterPrimitive("Box");
 
	...

}

カスタム プリミティブ オブジェクトを登録した後、GetPrim および X3DObject::AddPrimitive のようなプリミティブの作成コマンドを使用して作成することができます。 登録されたカスタム プリミティブ タイプは、プリセット引数としてコマンドに渡すことができます。

GetPrim "Box"

パラメータを追加する

Define コールバックを使用してカスタム プリミティブ オブジェクトのパラメータを定義し、DefineLayout コールバックを使用してプロパティ ページに表示される位置を調整することができます。
SICALLBACK Box_Define(const CRef& in_ref)
{
	Context in_ctxt(in_ref);
	CustomPrimitive in_prim(in_ctxt.GetSource());
	if(in_prim.IsValid())
	 {
	  Application().LogMessage(CString("Box_Define: ") + in_prim.GetFullName());
	  Factory l_fact = Application().GetFactory();
	  double dMin = 0.01;
	  double dMax = 10.0;
	  CRef l_widthDef = l_fact.CreateParamDef(“Width”, CValue::siDouble, 1.0,   dMin, dMax);
	  CRef l_lengthDef = l_fact.CreateParamDef(“Length”, CValue::siDouble, 1.0, dMin, dMax);
	  CRef l_heightDef = l_fact.CreateParamDef(“Height”, CValue::siDouble, 1.0, dMin, dMax);
	  Parameter l_width, l_length, l_height;
	  in_prim.AddParameter(l_widthDef, l_width);
	  in_prim.AddParameter(l_lengthDef, l_length);
	  in_prim.AddParameter(l_heightDef, l_height);
	}
	return CStatus::OK;
}

SICALLBACK Box_DefineLayout(const CRef& in_ref)
{
	Context in_ctxt(in_ref);
	
	PPGLayout layout = in_ctxt.GetSource();
	layout.Clear();
	layout.AddGroup("Box Group");
	layout.AddItem(“Width”, "Half-Width");
	layout.AddItem(“Length”, "Half-Length");
	layout.AddItem(“Height”, "Half-Height");
	layout.AddButton("ConvertGeom", "Convert to PolygonMesh");	
	layout.AddButton("CloseTheInspector", "Close the Inspector");
	layout.EndGroup();
	return CStatus::OK;
}
PPGEvent コールバックは、siParameterChange イベント ID を使用して、パラメータの変更を追跡するのに使用できます。
SICALLBACK Box_PPGEvent(const CRef& in_ref)
{
	PPGEventContext in_ctxt(in_ref);

	switch (in_ctxt.GetEventID())
	  {
	    case siOnInit:
	      {
	        CustomPrimitive primitive = in_ctxt.GetSource();
	        Application().LogMessage(CString("Box_PPGEvent: OnInit: " + primitive.GetName()));
	        break;
	      }
	    case siOnClosed:
	      {
	        CustomPrimitive primitive = in_ctxt.GetSource();
	        Application().LogMessage(CString("Box_PPGEvent: siOnClosed: " +  primitive.GetName()));
	        break;
	      }
	    case siParameterChange:
	      {
	        Parameter changed = in_ctxt.GetSource();
	        CustomPrimitive primitive = changed.GetParent();
	        CString paramName = changed.GetScriptName();
	        // Show that it is possible to change a value in the callback.
	        // Note that the Draw() call might see the intermediary value before
	        // it is changed this way.
         
	        if (paramName == kWidthName)
	        {
	          primitive.PutParameterValue(kHeightName, changed.GetValue());
	        }
	          else if (paramName == kHeightName)
	        {
	          primitive.PutParameterValue(kWidthName, changed.GetValue());
	        }
	        Application().LogMessage(CString("Box_PPGEvent: siParameterChange: " + primitive.GetName() + CString("/") + paramName
	        + CString(" = ") + changed.GetValue().GetAsText()));
	        break;
	      }
	      ...
	  }

	return CStatus::OK;
}

カスタム プリミティブ オブジェクトを描画する

Draw コールバックは、シーン内のカスタム プリミティブ オブジェクトを描画します。カスタム プリミティブ オブジェクトは、OpenGL 呼び出しを使用してシーンで直接描画されます。
SICALLBACK Box_Draw(const CRef& in_ref)
{
	Context in_ctxt(in_ref);
	CustomPrimitive in_prim(in_ctxt.GetSource());
	if(!in_prim.IsValid())
	{
	  return CStatus::Fail;
	}

	// Keep a cache of primitive data.

	Box_CachedData& data = g_Cache.Get(in_prim);
	double boxHalfWidth  = data.halfWidth;
	double boxHalfLength = data.halfLength;
	double boxHalfHeight = data.halfHeight;

	// Draw Box
	::glBegin();

	...
 
	::glEnd();
 
	return CStatus::OK;

}
Draw コールバックでは、OpenGL API を呼び出してカスタム プリミティブを描画できます。Draw コールバックが呼び出されると、OpenGL の状態はカスタム プリミティブ オブジェクトのローカル座標に設定されます。OpenGL の状態は変更しないでください。シーン全体のレンダリングに影響します。このメソッドは各描画サイクルで呼び出されるため、最適な状態にしておくことをお勧めします。

バウンディング ボックス

バウンディング ボックスは、カスタム プリミティブ オブジェクトの簡易版に相当し、特定の処理でのパフォーマンスを向上させるために使用されます。BoundingBox コールバックは、カスタム プリミティブのバウンディング ボックスを返します。

SICALLBACK Box_BoundingBox(const CRef& in_ref)
{
	Context in_ctxt(in_ref);
	CustomPrimitive in_prim(in_ctxt.GetSource());
	if(!in_prim.IsValid())
	{
	  return CStatus::Fail;
	}

	// Keep a cache of primitive data.

	Box_CachedData& data = g_Cache.Get(in_prim);
	double boxHalfWidth  = data.halfWidth;
	double boxHalfHeight = data.halfHeight;
	double boxHalfLength = data.halfLength;

	in_ctxt.PutAttribute("LowerBoundX", -boxHalfWidth);
	in_ctxt.PutAttribute("LowerBoundY", -boxHalfHeight);
	in_ctxt.PutAttribute("LowerBoundZ", -boxHalfLength);
	in_ctxt.PutAttribute("UpperBoundX", boxHalfWidth);
	in_ctxt.PutAttribute("UpperBoundY", boxHalfHeight);
	in_ctxt.PutAttribute("UpperBoundZ", boxHalfLength);
 
	return CStatus::OK;

}
Draw コールバックと異なり、バウンディング ボックスの値は内部的にキャッシュされ、パラメータ値に対する変更などの更新がある場合にのみ呼び出されます。BoundingBox コールバックが常に、正しい寸法、またはカスタム プリミティブ オブジェクト全体を含むボックスを返すようにする必要があります。

ジオメトリに変換する

他のインプリシット プリミティブと同じように、カスタム プリミティブ オブジェクトは、SIConvert コマンドまたは CreatePrim コマンドのいずれかを使用してジオメトリに変換することができます。Softimage 2014 では、カスタム プリミティブ オブジェクトはポリゴンメッシュにのみ変換することができます。

SICALLBACK Box_ConvertToGeom(const CRef& in_ref)
//
// This callback is invoked when the SIConvert or CreatePrim commands are run
//	for a custom primitive object. 
//

{
	CustomPrimitiveContext in_ctxt(in_ref);
	CustomPrimitive in_prim(in_ctxt.GetSource());
	if(!in_prim.IsValid())
	{
	  return CStatus::Fail;
	}
 
	Box_CachedData& data = g_Cache.Get(in_prim);
	double boxHalfWidth  = data.halfWidth;
	double boxHalfHeight = data.halfHeight;
	double boxHalfLength = data.halfLength;
 
	double boxMinPt[3];
	double boxMaxPt[3];

	boxMinPt[0] = -boxHalfWidth;
	boxMinPt[1] = -boxHalfHeight;
	boxMinPt[2] = 0;

	boxMaxPt[0] = boxHalfWidth;
	boxMaxPt[1] = boxHalfHeight;
	boxMaxPt[2] = 0;

	Geometry out_geo = in_ctxt.GetGeometry();

	// PolygonMesh support
	
	PolygonMesh out_mesh(out_geo);
	if(out_mesh.IsValid())
	{
	  // Convert to polygon
	  MATH::CVector3Array out_verts;
	  CLongArray out_faces;

	  int index = 0;
	  for (int i = -boxHalfLength; i <= boxHalfLength; ++i)
	  {
	    MATH::CVector3 vMinXMinY(-boxHalfWidth, -boxHalfHeight, 1.0 * i);
	    MATH::CVector3 vMinXMaxY(-boxHalfWidth, boxHalfHeight, 1.0 * i);
	    MATH::CVector3 vMaxXMinY(boxHalfWidth, -boxHalfHeight, 1.0 * i);
	    MATH::CVector3 vMaxXMaxY(boxHalfWidth, boxHalfHeight, 1.0 * i);

	    out_verts.Add(vMinXMinY);
	    out_verts.Add(vMinXMaxY);
	    out_verts.Add(vMaxXMaxY);
	    out_verts.Add(vMaxXMinY);
   
	    out_faces.Add(4); // Vertex count for tri
	    out_faces.Add(index + 0);
	    out_faces.Add(index + 1);
	    out_faces.Add(index + 2);
	    out_faces.Add(index + 3);
	    index += 4;
	  }

	  return out_mesh.Set(out_verts, out_faces);
	}

}

ConvertToGeom コールバックでは、ジオメトリはコールバックのコンテキストにアタッチされます。変換の結果を使用してジオメトリを更新することができます。

詳細については、SDK ワークグループのカスタム プリミティブのサンプル(<your_installation_folder>¥Softimage2014¥XSISDK¥examples¥workgroup¥Addons¥CustomPrimitive)を参照してください。

カスタム プリミティブ ウィザードを使用して、カスタム プリミティブ オブジェクトを含む自己インストール プラグインのコードを作成することができます。 カスタム プリミティブ ウィザードにアクセスするには、[プラグイン マネージャ] [ファイル] [新規] [プリミティブ] を選択します。