本主题介绍了如何使用 xgenSplineArnoldExtension 示例访问 Arnold for Maya 渲染器等第三方插件的 XGen 交互式修饰样条线数据。您可以从 plug-ins\xgen 目录的 devkit 文件夹中访问此示例。例如,从 Maya 安装软件包浏览到以下位置:
\runTime\plug-ins\xgen\devkit。
使用 XGen API 访问交互式修饰样条线数据的过程可分为三个主要步骤。
使用 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 从步骤 1 开始迭代 XgFnSpline 对象 _splines,然后计算点、曲线和采样的数量。然后,可以根据需求为这些缓冲区分配内存。
以下是支持 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 文件中,并且提供的功能可帮助访问每条样条线的内部数据。一些重要的方法如下所示,应提供所有几何体信息:
基本体信息阵列的步幅,
“偏移”(Offset)和“长度”(Length)确定可变阵列中每个顶点的不同属性位置。
返回基本体的数量
返回顶点的数量。
返回边界框。
返回运动向量的边界框。
基本体信息。请参见上面的 primitiveInfoStride()。
多种(逐顶点)属性
顶点位置。
从根部到尖端的 Texcoord,U 方向为 0.0,V 方向介于 0.0(根部顶点)到 1.0(尖端顶点)之间。
面片上的根部顶点的 Texcoord。
获取宽度。
使用通过上述方法获取的信息,您可以获得所需的任何内容并根据要求填充到数据中。下面举例说明如何为 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);