今天弄了个检查模型点是否有重合的command,好久不用API都陌生了;带有一个flag——shreshold,简写sr,设置需要检查两点之间的最小距离,再小于这个距离就算是重合的点了,command会将这两个点同时返回。源代码如下:
checkOverlapPoint.h
#ifndef _CHECK_OVERLAP_POINT
#define _CHECK_OVERLAP_POINT
#include <maya/MSelectionList.h>
#include <maya/MDagPath.h>
#include <maya/MPxCommand.h>
#include <maya/MSyntax.h>
using namespace std;
class CheckOverlapPoint: MPxCommand
{
public:
CheckOverlapPoint();
virtual ~CheckOverlapPoint();
virtual MStatus doIt( const MArgList& );
static void *creator(){return new CheckOverlapPoint();}
static MSyntax newSyntax();
private:
double shreshold;
};
#endif
checkOverLapPointCmd.cpp
#include "checkOverlapPoint.h"
#include <maya/MArgDatabase.h>
#include <maya/MGlobal.h>
#include <maya/MItSelectionList.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnMesh.h>
#include <maya/MPointArray.h>
#include <maya/MIntArray.h>
#include <maya/MString.h>
const char *shresholdFlag = "-sr", *shresholdLongFlag = "shreshold";
CheckOverlapPoint::CheckOverlapPoint()
{
shreshold = 0.003;
}
CheckOverlapPoint::~CheckOverlapPoint()
{
shreshold = 0;
}
MSyntax CheckOverlapPoint::newSyntax()
{
MSyntax syntax;
syntax.addFlag( shresholdFlag, shresholdLongFlag, MSyntax::kDouble );
return syntax;
}
MStatus CheckOverlapPoint::doIt(const MArgList &args)
{
MStatus stat;
MArgDatabase argData( syntax(), args, &stat );
if( !stat )
return stat;
if( argData.isFlagSet( shresholdFlag ) ){
argData.getFlagArgument( shresholdFlag, 0, shreshold);
}
MSelectionList selection;
MDagPath objectPath;
MGlobal::getActiveSelectionList(selection);
MItSelectionList iter(selection);
MPointArray meshPoints, copyPoints;
double pointDistance;
MIntArray overlapPointIDs;
MStringArray meshOverlapPoints;
for(unsigned int j = 0; j < selection.length(); j++)
{
unsigned int index = 1;
meshPoints.clear();
copyPoints.clear();
overlapPointIDs.clear();
selection.getDagPath(j, objectPath);
MFnMesh objectMesh(objectPath);
objectMesh.getPoints(meshPoints, MSpace::kWorld);
CHECK_MSTATUS_AND_RETURN_IT(copyPoints.copy(meshPoints));
for (unsigned int k = 0; k < meshPoints.length(); k ++){
copyPoints.remove(0);
for (unsigned int l = 0; l < copyPoints.length(); l ++){
if (k == l){
continue;
}
pointDistance = meshPoints[k].distanceTo(copyPoints[l]);
if (pointDistance < shreshold){
overlapPointIDs.append(k);
overlapPointIDs.append(l + index);
}
}
index ++;
}
MString modelName = objectMesh.partialPathName();
for (unsigned int m = 0; m < overlapPointIDs.length(); m++){
MString pointName;
pointName = pointName + modelName.asChar() + ".vtx[" + overlapPointIDs[m] + "]";
meshOverlapPoints.append(pointName);
}
}
setResult(meshOverlapPoints);
return stat;
}
MStatus initializePlugin( MObject obj )
{
MFnPlugin plugin( obj, "Lulongfei", "1.0" );
MStatus stat;
stat = plugin.registerCommand( "checkOverlapPoint", CheckOverlapPoint::creator, CheckOverlapPoint::newSyntax );
if ( !stat )
stat.perror( "registerCommand failed" );
return stat;
}
MStatus uninitializePlugin( MObject obj )
{
MFnPlugin plugin( obj );
MStatus stat;
stat = plugin.deregisterCommand( "checkOverlapPoint" );
if ( !stat )
stat.perror( "deregisterCommand failed" );
return stat;
}
最开始采用的是这种遍历,计算的次数为n的n次方;
for (unsigned int k = 0; k < meshPoints.length(); k ++){
for (unsigned int l = 0; l < meshPoints.length(); l ++){
if (k == l){
continue;
}
pointDistance = meshPoints[k].distanceTo(meshPoints[l]);
if (pointDistance < shreshold){
overlapPointIDs.append(k);
}
}
}
发现这样的计算速度太慢于是改进了下,这样计算的次数是n的阶乘,不过内存开销是原来的两倍,以内存换速度了;
for (unsigned int k = 0; k < meshPoints.length(); k ++){
copyPoints.remove(0);
for (unsigned int l = 0; l < copyPoints.length(); l ++){
if (k == l){
continue;
}
pointDistance = meshPoints[k].distanceTo(copyPoints[l]);
if (pointDistance < shreshold){
overlapPointIDs.append(k);
overlapPointIDs.append(l + index);
}
}
index ++;
}
最后在maya里返回的是个列表或数组,用户可以根据这个结果做进一步的操作,是merge还是选择都行,性能上来说还可以,比python版的API能快至少100倍。
使用如下:
cmds.checkOverlapPoint(sr=0.003) # python
checkOverlapPoint -sr 0.003 // Mel
效果如下图: