このトピックでは、xgenSplineArnoldExtension の例を使用して、Arnold for Maya レンダラなどのサードパーティ プラグイン用にインタラクティブ グルーミング スプライン データにアクセスする方法を説明します。この例は、plug-ins¥xgen ディレクトリの devkit フォルダにあります。たとえば、Maya インストール パッケージから次のファイルを参照します。
¥runTime¥plug-ins¥xgen¥devkit
XGen API を使用してインタラクティブなグルーミング スプライン データにアクセスする方法としては、主に次の 3 つの方法があります。
スプライン データ上での操作をサポートする XgFnSpline クラスを使用します。これは、ヘッダ ファイル XgSplineApi.h 内にあります。XgFnSpline クラスは、Maya上の xgmSplineDescription.outRenderData プラグインからデータをロードできます。トランスレータは、Maya の MPxData::writeBinary() メソッドを使用して、プラグ データを BLOB にシリアル化します。XgFnSpline は Maya なしでデータを解釈できます。
XgFnSpline のデータをロードします。
// Stream out the spline data std::string data; MPlug outPlug = fnDagNode.findPlug("outRenderData"); MObject outObj = outPlug.asMObject(); MPxData* outData = MFnPluginData(outObj).data(); if (outData) { std::ostringstream opaqueStrm; outData->writeBinary(opaqueStrm); data = opaqueStrm.str(); } // Load the sample for i-th motion step _splines.load(opaqueStrm, sampleSize, sampleTime)
データが XgFnSpline オブジェクトにロードされた後、データ用にメモリを割り当てる必要があります。XgItSpline を使用して XgFnSpline オブジェクト _splines を手順 1 から反復し、ポイント、カーブ、およびサンプルの数を計算する必要があります。その後、必要に応じて、これらのバッファにメモリを割り当てることができます。
次のコードは、Arnold レンダラをサポートするサンプル コードです。インラインで示されているとおり、いくつか特別な要件があります。また、特定のニーズに応じてこれを処理することができます。
// Count the number of curves and the number of points // Arnold's b-spline requires two phantom points. unsigned int curveCount = 0; unsigned int pointCount = 0; unsigned int pointInterpoCount = 0; for (XgItSpline splineIt = _splines.iterator(); !splineIt.isDone(); splineIt.next()) { curveCount += splineIt.primitiveCount(); pointCount += splineIt.vertexCount(); pointInterpoCount += splineIt.vertexCount() + splineIt.primitiveCount() * 2; } // Get the number of motion samples const unsigned int steps = _splines.sampleCount(); // Allocate buffers for the curves _numPoints = AiArrayAllocate(curveCount, 1, AI_TYPE_UINT); _points = AiArrayAllocate(pointInterpoCount, steps, AI_TYPE_POINT); _radius = AiArrayAllocate(pointCount, 1, AI_TYPE_FLOAT); _uCoord = AiArrayAllocate(curveCount, 1, AI_TYPE_FLOAT); _vCoord = AiArrayAllocate(curveCount, 1, AI_TYPE_FLOAT); _wCoord = AiArrayAllocate(pointInterpoCount, 1, AI_TYPE_FLOAT); unsigned int* numPoints = reinterpret_cast<unsigned int*>(_numPoints->data); SgVec3f* points = reinterpret_cast<SgVec3f*>(_points->data); float* radius = reinterpret_cast<float*>(_radius->data); float* uCoord = reinterpret_cast<float*>(_uCoord->data); float* vCoord = reinterpret_cast<float*>(_vCoord->data); float* wCoord = reinterpret_cast<float*>(_wCoord->data);
このステップでは、XgFnSpline オブジェクトから評価された正しい値で、これらのオブジェクトを塗り潰します。XGen は、XgItSpline と呼ばれるイテレータを提供しています。これは、XgSplineApi.h ファイル内にもあり、各スプラインの内部データへのアクセスをサポートする機能を提供します。いくつかの重要なメソッドが次のようにリストされ、すべてのジオメトリ情報が提供されます。
プリミティブ情報配列の歩幅
オフセットと長さは、可変配列内の各頂点の可変アトリビュートの場所を決定します。
プリミティブの数を返します。
頂点の数を返します。
バウンディング ボックスを返します。
モーション ベクトルのバウンディング ボックスを返します。
プリミティブ情報。上記の primitiveInfoStride() を参照してください。
可変(頂点ごとの)アトリビュート
頂点の位置。
ルートから先端までのテクスチャ座標。U は 0.0。V の範囲は 0.0 (ルート頂点) ~ 1.0 (先端頂点)。
パッチ上のルート頂点のテクスチャ座標。
幅を取得します。
上記のメソッドから取得された情報により、目的のものを取得して、要件に基づいてデータに入力できます。以下に、Arnold サンプル用にこの情報を取得するサンプル コードを示します。
// Fill the array buffers for motion step 0 for (XgItSpline splineIt = _splines.iterator(); !splineIt.isDone(); splineIt.next()) { const unsigned int stride = splineIt.primitiveInfoStride(); const unsigned int primitiveCount = splineIt.primitiveCount(); const unsigned int* primitiveInfos = splineIt.primitiveInfos(); const SgVec3f* positions = splineIt.positions(0); const float* width = splineIt.width(); const SgVec2f* texcoords = splineIt.texcoords(); const SgVec2f* patchUVs = splineIt.patchUVs(); for (unsigned int p = 0; p < primitiveCount; p++) { const unsigned int offset = primitiveInfos[p * stride]; const unsigned int length = primitiveInfos[p * stride + 1]; // Number of points *numPoints++ = length + 2; // Texcoord using the patch UV from the root point *uCoord++ = patchUVs[offset][0]; *vCoord++ = patchUVs[offset][1]; // Add phantom points at the beginning *points++ = phantomFirst(&positions[offset], length); *wCoord++ = phantomFirst(&texcoords[offset], length)[1]; // Copy varying data for (unsigned int i = 0; i < length; i++) { *points++ = positions[offset + i]; *radius++ = width[offset + i] * 0.5f; *wCoord++ = texcoords[offset + i][1]; } // Add phantom points at the end *points++ = phantomLast(&positions[offset], length); *wCoord++ = phantomLast(&texcoords[offset], length)[1]; } // for each primitive } // for each primitive batch // Fill the array buffers for motion step > 0 for (unsigned int key = 1; key < steps; key++) { for (XgItSpline splineIt = _splines.iterator(); !splineIt.isDone(); splineIt.next()) { const unsigned int stride = splineIt.primitiveInfoStride(); const unsigned int primitiveCount = splineIt.primitiveCount(); const unsigned int* primitiveInfos = splineIt.primitiveInfos(); const SgVec3f* positions = splineIt.positions(key); for (unsigned int p = 0; p < primitiveCount; p++) { const unsigned int offset = primitiveInfos[p * stride]; const unsigned int length = primitiveInfos[p * stride + 1]; // Add phantom points at the beginning *points++ = phantomFirst(&positions[offset], length); // Copy varying data for (unsigned int i = 0; i < length; i++) { *points++ = positions[offset + i]; } // Add phantom points at the end *points++ = phantomLast(&positions[offset], length); } // for each primitive } // for each primitive batch } // for each motion step // Set the buffers to the curves node AiNodeSetArray(_curves, "num_points", _numPoints); AiNodeSetArray(_curves, "points", _points); AiNodeSetArray(_curves, "radius", _radius); AiNodeSetArray(_curves, "uparamcoord", _uCoord); AiNodeSetArray(_curves, "vparamcoord", _vCoord); AiNodeSetArray(_curves, "wparamcoord", _wCoord);