Skip to content

Instantly share code, notes, and snippets.

@JohnOnSoftware
Last active February 22, 2024 09:45
Show Gist options
  • Save JohnOnSoftware/9ca01686525a368b765f3da247215a35 to your computer and use it in GitHub Desktop.
Save JohnOnSoftware/9ca01686525a368b765f3da247215a35 to your computer and use it in GitHub Desktop.
Core code to support XGen Interactive Grooming in Arnold
MFnDagNode fnDagNode(m_dagPath);
// Apply the render overrides
static const MString sApplyRenderOverrideCmd = "xgmSplineApplyRenderOverride ";
MGlobal::executeCommand(sApplyRenderOverrideCmd + fnDagNode.partialPathName());
// 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)
// 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);
// 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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment