#include <string.h>
#include <maya/MIOStream.h>
#include <maya/MStringArray.h>
#include <math.h>
#include <maya/MPxDeformerNode.h>
#include <maya/MItGeometry.h>
#include <maya/MPxLocatorNode.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFnMatrixData.h>
#include <maya/MFnFloatArrayData.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnDependencyNode.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 <maya/MFnMesh.h>
#include <clew/clew.h>
#include <vector>
{
public:
offset();
~offset() override;
static void* creator();
unsigned int multiIndex) override;
public:
private:
};
offset::offset() {}
offset::~offset() {}
void* offset::creator()
{
return new offset();
}
{
offsetMatrix=mAttr.
create(
"locateMatrix",
"lm");
addAttribute( offsetMatrix);
addAttribute( chunkEnvelope );
addAttribute( chunkCount );
attributeAffects( offset::offsetMatrix, offset::outputGeom );
attributeAffects( offset::chunkEnvelope, offset::outputGeom );
attributeAffects( offset::chunkCount, offset::outputGeom );
}
unsigned int multiIndex)
{
if (MS::kSuccess != returnStatus)
return returnStatus;
float chunkWeight = chunkEnvelopeData.
asFloat();
size_t numChunks = chunkCountData.
asInt();
if (numChunks != randomOffsetTable.length()) {
srand(numChunks*827);
randomOffsetTable.setLength(numChunks);
for (size_t i = 0; i < numChunks; ++i) {
float r = (rand() % 1001)/500.0 - 1.0;
randomOffsetTable.set(r, i);
}
}
if (MS::kSuccess != returnStatus) return returnStatus;
bool useRandomOffset = (numChunks > 0 && chunkWeight > 0.0);
pt *= omatinv;
float weight = weightValue(block,multiIndex,iter.
index());
if (useRandomOffset)
weight *= (1.0 + chunkWeight*randomOffsetTable[iter.
index()%numChunks]);
pt.
y = pt.
y + env*weight;
pt *= omat;
}
return returnStatus;
}
offset::accessoryAttribute() const
{
return offset::offsetMatrix;
}
{
&result);
if (MS::kSuccess == result) {
MObject attrMat = fnLoc.attribute(attrName);
result = cmd.
connect(objLoc,attrMat,this->thisMObject(),offset::offsetMatrix);
}
return result;
}
offset::getFixedSetupData(
const MString& name)
{
if (name == "randomOffsetTable") {
return fn.
create(randomOffsetTable);
}
}
{
public:
offsetGPUDeformer();
~offsetGPUDeformer() override;
private:
void extractAffectMap();
bool needsAffectMap() const;
unsigned int affectCount() const;
unsigned int fullCount() const;
unsigned int fNumElements;
unsigned int fAffectMapBufferSize;
unsigned int fRandomOffsetTableSize;
float fChunkEnvelope;
};
{
public:
offsetNodeGPUDeformerInfo() {}
~offsetNodeGPUDeformerInfo() override{}
{
return new offsetGPUDeformer();
}
{
return offsetGPUDeformer::validateNodeInGraph(block, evaluationNode, plug, messages);
}
{
return offsetGPUDeformer::validateNodeValues(block, evaluationNode, plug, messages);
}
};
{
static offsetNodeGPUDeformerInfo theOne;
return &theOne;
}
offsetGPUDeformer::offsetGPUDeformer()
: fNumElements(0)
, fAffectMapBufferSize(0)
{
}
offsetGPUDeformer::~offsetGPUDeformer()
{
terminate();
}
{
return true;
}
{
envelopePlug.getValue(envData);
{
MOpenCLInfo::appendMessage(messages,
"Offset %s not supported by deformer evaluator because envelope is not exactly 1.0.", fnNode.name().asChar());
return false;
}
return true;
}
cl_int offsetGPUDeformer::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 offsetGPUDeformer::enqueueDeformation(
{
cl_int err = CL_SUCCESS;
unsigned int count = affectCount();
eventList.
add(syncInputEvent);
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*)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_mem), (void*)fCLOffsetMatrix.getReadOnlyRef());
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_mem), (void*)fCLRandomOffsetTable.getReadOnlyRef());
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_uint), (void*)&fRandomOffsetTableSize);
err = clSetKernelArg(fKernel.get(), parameterId++, sizeof(cl_float), (void*)&fChunkEnvelope);
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() != 1)
return MPxGPUDeformer::kDeformerFailure;
const MPlug& inputPlug = inputPlugs[0];
return MPxGPUDeformer::kDeformerFailure;
extractAffectMap();
extractWeightArray(block, evaluationNode, plug);
extractOffsetMatrix(block, evaluationNode, plug);
extractRandomOffsetTable(block, evaluationNode, plug);
MDataHandle chunkEnvelopeData = block.inputValue(offset::chunkEnvelope, &status );
fChunkEnvelope = (MS::kSuccess != status) ? 1.0 : chunkEnvelopeData.
asFloat();
if (!fKernel.get())
{
MString openCLKernelFile = offset::pluginPath +
"/offset.cl";
MString openCLKernelName(
"offset");
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);
if ( err != CL_SUCCESS )
return MPxGPUDeformer::kDeformerFailure;
outputData.setBuffer(outputPositions);
return MPxGPUDeformer::kDeformerSuccess;
}
void offsetGPUDeformer::terminate()
{
fCLWeights.reset();
fCLAffectMap.reset();
fCLOffsetMatrix.reset();
fCLRandomOffsetTable.reset();
fKernel.reset();
}
void offsetGPUDeformer::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);
MIntArray 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 offsetGPUDeformer::needsAffectMap() const
{
return (affectCount() < fullCount());
}
unsigned int offsetGPUDeformer::affectCount() const
{
return fIndexMapper.affectCount();
}
unsigned int offsetGPUDeformer::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
{
}
}
{
{
return;
}
if (MS::kSuccess != status) return;
unsigned int numFloat = 32;
float* temp = new float[numFloat];
unsigned int curr = 0;
for(unsigned int row = 0; row<4; row++)
{
for(unsigned int column = 0; column<4; column++)
{
temp[curr++] = (float)omat(row, column);
}
}
for(unsigned int row = 0; row<4; row++)
{
for(unsigned int column = 0; column<4; column++)
{
temp[curr++] = (float)omatinv(row, column);
}
}
cl_int err = CL_SUCCESS;
if (!fCLOffsetMatrix.get())
{
fCLOffsetMatrix.attach(clCreateBuffer(
MOpenCLInfo::getOpenCLContext(), CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, numFloat *
sizeof(
float), (
void*) temp, &err));
}
else
{
}
delete [] temp;
}
{
{
return;
}
MObject arrOb = getFixedSetupData(
"randomOffsetTable");
{
fRandomOffsetTableSize = array.
length();
if (fRandomOffsetTableSize <= 0) return;
float& f = array[0];
cl_int err = CL_SUCCESS;
if (!fCLRandomOffsetTable.get())
{
fCLRandomOffsetTable.attach(clCreateBuffer(
MOpenCLInfo::getOpenCLContext(), CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, fRandomOffsetTableSize *
sizeof(
float), (
void*)&f, &err));
}
else
{
}
return;
}
}
fCLRandomOffsetTable.reset();
fRandomOffsetTableSize = 0;
}
{
MFnPlugin plugin( obj, PLUGIN_COMPANY,
"3.0",
"Any");
result = plugin.registerNode( "offset", offset::id, offset::creator,
MString registrantId(
"mayaPluginExample");
nodeClassName,
registrantId,
offsetGPUDeformer::getGPUDeformerInfo());
nodeClassName,
registrantId,
offset::pluginPath = plugin.loadPath();
return result;
}
{
MString registrantId(
"mayaPluginExample");
nodeClassName,
registrantId);
result = plugin.deregisterNode(offset::id);
return result;
}