#include <maya/MPxDeformerNode.h>
#include <maya/MItGeometry.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnData.h>
#include <maya/MFnMesh.h>
#include <maya/MFnMatrixData.h>
#include <maya/MFnGeometryData.h>
#include <maya/MFnPlugin.h>
#include <maya/MGlobal.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MArrayDataHandle.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>
#include <maya/MDagModifier.h>
#include <maya/MPxGPUDeformer.h>
#include <maya/MGPUDeformerRegistry.h>
#include <maya/MOpenCLInfo.h>
#include <maya/MViewport2Renderer.h>
#include <clew/clew.h>
#include <vector>
{
public:
basicMorph();
~basicMorph() override;
static void* creator();
unsigned int multiIndex) override;
public:
private:
};
MTypeId basicMorph::id(0x0008006E);
MObject basicMorph::targetGeometry;
basicMorph::basicMorph() {}
basicMorph::~basicMorph() {}
void* basicMorph::creator()
{
return new basicMorph();
}
{
addAttribute(targetGeometry);
attributeAffects(basicMorph::targetGeometry, basicMorph::outputGeom);
}
unsigned int multiIndex)
{
MStatus returnStatus = MS::kSuccess;
MFnMesh baseMesh(inputGeometry, &returnStatus);
if (targetMesh.numVertices() != baseMesh.numVertices()) {
returnStatus = MS::kFailure;
return returnStatus;
}
unsigned int ptIndex = iter.
index();
returnStatus = targetMesh.getPoint(ptIndex, tgt);
pt += (tgt - pt) * env;
}
return returnStatus;
}
{
public:
basicMorphGPUDeformer();
~basicMorphGPUDeformer() override;
private:
void extractAffectMap();
bool needsAffectMap() const;
unsigned int affectCount() const;
unsigned int fullCount() const;
unsigned int fNumElements;
unsigned int fAffectMapBufferSize;
float fEnvelope;
};
{
public:
basicMorphNodeGPUDeformerInfo() {}
~basicMorphNodeGPUDeformerInfo() override {}
{
return new basicMorphGPUDeformer();
}
{
return basicMorphGPUDeformer::validateNodeInGraph(block, evaluationNode, plug, messages);
}
{
return basicMorphGPUDeformer::validateNodeValues(block, evaluationNode, plug, messages);
}
{
iInputAttributes.
append(basicMorph::targetGeometry);
}
};
{
static basicMorphNodeGPUDeformerInfo theOne;
return &theOne;
}
basicMorphGPUDeformer::basicMorphGPUDeformer()
: fNumElements(0)
, fAffectMapBufferSize(0)
{
}
basicMorphGPUDeformer::~basicMorphGPUDeformer()
{
terminate();
}
{
return true;
}
{
return true;
}
cl_int basicMorphGPUDeformer::enqueueInitializeOutputPositions(
{
cl_int err = CL_SUCCESS;
if (!needsAffectMap())
return err;
eventList.
add(syncInputEvent);
const size_t fullVertBufSize = fNumElements * sizeof(float) * 3;
err = clEnqueueCopyBuffer(
0,
0,
fullVertBufSize,
return err;
}
cl_int basicMorphGPUDeformer::enqueueDeformation(
{
cl_int err = CL_SUCCESS;
unsigned int count = affectCount();
eventList.
add(syncInputEvent);
eventList.
add(syncTargetEvent);
unsigned int parameterId = 0;
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)outputPositions.buffer().getReadOnlyRef());
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)inputPositions.buffer().getReadOnlyRef());
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)targetPositions.buffer().getReadOnlyRef());
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_float), (void*)&fEnvelope);
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)fCLWeights.getReadOnlyRef());
if (needsAffectMap())
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)fCLAffectMap.getReadOnlyRef());
else
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), nullptr);
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_uint), (void*)&count);
size_t workGroupSize;
size_t retSize;
err = clGetKernelWorkGroupInfo(
fKernel.get(),
CL_KERNEL_WORK_GROUP_SIZE,
sizeof(size_t),
&workGroupSize,
&retSize);
size_t localWorkSize = 256;
if (retSize > 0) localWorkSize = workGroupSize;
size_t globalWorkSize = (localWorkSize - count % localWorkSize) + count;
err = clEnqueueNDRangeKernel(
fKernel.get(),
1,
NULL,
&globalWorkSize,
&localWorkSize,
eventList.size(),
eventList.array(),
syncEvent.getReferenceForAssignment());
return err;
}
)
{
if (inputPlugs.length() != 2)
return MPxGPUDeformer::kDeformerFailure;
MDataHandle envelopeData = block.inputValue(basicMorph::envelope, &status);
fEnvelope = (MS::kSuccess != status) ? 1.0 : envelopeData.
asFloat();
if (fEnvelope == 0.0) {
return MPxGPUDeformer::kDeformerPassThrough;
}
for (unsigned int i = 0; i < inputPlugs.length(); i++)
{
MPlug plug = inputPlugs[i];
if (plug.
attribute(&status) == basicMorph::inputGeom)
{
inputPlug = plug;
continue;
}
else if (plug.
attribute(&status) == basicMorph::targetGeometry)
{
targetPlug = plug;
continue;
}
}
if (MS::kSuccess != status)
return MPxGPUDeformer::kDeformerFailure;
return MPxGPUDeformer::kDeformerFailure;
return MPxGPUDeformer::kDeformerFailure;
return MPxGPUDeformer::kDeformerFailure;
extractAffectMap();
extractWeightArray(block, evaluationNode, outputPlug);
if (!fKernel.get())
{
MString openCLKernelFile = basicMorph::pluginPath +
"/basicMorph.cl";
MString openCLKernelName(
"basicMorph");
if (!fKernel) return MPxGPUDeformer::kDeformerFailure;
}
cl_int err = CL_SUCCESS;
err = enqueueInitializeOutputPositions(syncEvent, inputPositions, outputPositions);
if (err != CL_SUCCESS)
return MPxGPUDeformer::kDeformerFailure;
err = enqueueDeformation(syncEvent, inputPositions, outputPositions, targetPositions);
if (err != CL_SUCCESS)
return MPxGPUDeformer::kDeformerFailure;
outputData.setBuffer(outputPositions);
return MPxGPUDeformer::kDeformerSuccess;
}
void basicMorphGPUDeformer::terminate()
{
fCLWeights.reset();
fCLAffectMap.reset();
fKernel.reset();
}
void basicMorphGPUDeformer::extractAffectMap()
{
if (getIndexMapper(fIndexMapper)) {
if (!needsAffectMap()) {
fCLAffectMap.reset();
fAffectMapBufferSize = 0;
return;
}
cl_int err = CL_SUCCESS;
std::vector<unsigned int> temp;
temp.resize(affectCount());
unsigned int bufferSize = temp.size() * sizeof(unsigned int);
auto affectMap = fIndexMapper.affectMap();
for (size_t i = 0; i < affectMap.length(); ++i)
temp[i] = affectMap[i];
if (fAffectMapBufferSize < bufferSize) {
fCLAffectMap.reset();
fAffectMapBufferSize = 0;
}
if (!fCLAffectMap.get())
{
fAffectMapBufferSize = bufferSize;
fCLAffectMap.attach(clCreateBuffer(
MOpenCLInfo::getOpenCLContext(), CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, bufferSize, (
void*)&temp[0], &err));
}
else
{
}
}
}
bool basicMorphGPUDeformer::needsAffectMap() const
{
return (affectCount() < fullCount());
}
unsigned int basicMorphGPUDeformer::affectCount() const
{
return fIndexMapper.affectCount();
}
unsigned int basicMorphGPUDeformer::fullCount() const
{
return fIndexMapper.fullCount();
}
{
{
return;
}
std::vector<float> temp;
temp.reserve(fNumElements);
if (!status) return;
if (!status)
{
for (unsigned int i = 0; i < fNumElements; i++)
temp.push_back(1.0f);
}
else
{
if (!status) return;
if (!status) return;
if (!status) return;
unsigned int weightIndex = 0;
for (
unsigned int i = 0; i < numWeights; i++, weights.
next())
{
unsigned int weightsElementIndex = weights.
elementIndex(&status);
while (weightIndex < weightsElementIndex)
{
temp.push_back(1.0f);
weightIndex++;
}
weightIndex++;
}
while (weightIndex < fNumElements)
{
temp.push_back(1.0f);
weightIndex++;
}
}
cl_int err = CL_SUCCESS;
if (!fCLWeights.get())
{
fCLWeights.attach(clCreateBuffer(
MOpenCLInfo::getOpenCLContext(), CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, fNumElements *
sizeof(
float), (
void*)&temp[0], &err));
}
else
{
}
}
{
MFnPlugin plugin(obj, PLUGIN_COMPANY,
"1.0",
"Any");
result = plugin.registerNode("basicMorph", basicMorph::id, basicMorph::creator,
MString nodeClassName(
"basicMorph");
MString registrantId(
"mayaPluginExample");
nodeClassName,
registrantId,
basicMorphGPUDeformer::getGPUDeformerInfo());
nodeClassName,
registrantId,
basicMorph::pluginPath = plugin.loadPath();
return result;
}
{
MString nodeClassName(
"basicMorph");
MString registrantId(
"mayaPluginExample");
result = plugin.deregisterNode(basicMorph::id);
return result;
}