So it seems like the selectFromScreen causes flickering because it causes a refresh of the viewport. I don't know if there is a way to use that function and get around it.
I did do some testing of my own using the MfnMesh method and I was getting some good results using some optimization.
- Updating the maxParam whenever you find an intersection on a mesh, so the other meshes we check will only need to search a shorter distance.
- Get the list of meshes in ToolOnSetup and create MMeshIsectAccelParams for them
I did notice that the M3dView class has a beginSelect and endSelect which seems graphics-based? But I didn't really dig into it.
Sorry for the janky test code
#include <maya/MString.h>
#include <maya/MItSelectionList.h>
#include <maya/MPxContextCommand.h>
#include <maya/MPxContext.h>
#include <maya/MPxSelectionContext.h>
#include <maya/MEvent.h>
#include <maya/M3dView.h>
#include <maya/MObjectArray.h>
#include <maya/MDagPathArray.h>
#include <maya/MIntArray.h>
#include <maya/MGlobal.h>
#include <maya/MFnPlugin.h>
#include <maya/MPointArray.h>
#include <maya/MUIDrawManager.h>
#include <maya/MItDag.h>
#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnMesh.h>
#include <maya/M3dView.h>
#include <maya/MFnCamera.h>
#include <vector>
class clickTest : public MPxContext
{
public:
clickTest() {};
virtual ~clickTest() {};
void* creator() {};
void toolOnSetup(MEvent & event);
MStatus doPress(MEvent &event, MHWRender::MUIDrawManager &drawMgr, const MHWRender::MFrameContext &context) { return MS::kSuccess; }
MStatus doDrag(MEvent &event, MHWRender::MUIDrawManager &drawMgr, const MHWRender::MFrameContext &context) { return MS::kSuccess; }
MStatus doRelease(MEvent &event, MHWRender::MUIDrawManager &drawMgr, const MHWRender::MFrameContext &context) { return MS::kSuccess; }
MStatus doPtrMoved(MEvent &event, MHWRender::MUIDrawManager &drawMgr, const MHWRender::MFrameContext &context);
MPointArray ptArray;
MDagPathArray allMeshes;
std::vector<MMeshIsectAccelParams> accels;
};
// Command to create contexts
class meshReorderContextCmd : public MPxContextCommand
{
public:
meshReorderContextCmd() {};
virtual MPxContext* makeObj();
static void* creator();
};
MPxContext* meshReorderContextCmd::makeObj()
{
return new clickTest;
}
void* meshReorderContextCmd::creator()
{
return new meshReorderContextCmd;
}
bool isVisible(MFnDagNode dagNodee, MStatus status)
{
return true;
}
MStatus getAllMeshes(MDagPathArray& pathArray)
{
MStatus status;
//create an iterator for only the mesh components of the DAG
MItDag itDag(MItDag::kDepthFirst, MFn::kMesh, &status);
if (MStatus::kFailure == status) {
MGlobal::displayError("MItDag::MItDag");
return MS::kFailure;
}
pathArray.clear();
for (; !itDag.isDone(); itDag.next()) {
//get the current DAG path
//
MDagPath dagPath;
if (MStatus::kFailure == itDag.getPath(dagPath)) {
MGlobal::displayError("MDagPath::getPath");
return MS::kFailure;
}
pathArray.append(dagPath);
//if this node is visible, then process the poly mesh it represents
// IGNORE FOR NOW
}
return MStatus::kSuccess;
}
void clickTest::toolOnSetup(MEvent & event)
{
getAllMeshes(allMeshes);
accels.resize(allMeshes.length());
for (unsigned i = 0; i < allMeshes.length(); i++)
{
; accels[i] = MFnMesh(allMeshes[i]).autoUniformGridParams();
}
}
MStatus clickTest::doPtrMoved(MEvent &event, MHWRender::MUIDrawManager &drawMgr, const MHWRender::MFrameContext &context)
{
MStatus status;
M3dView view = M3dView::active3dView();
short x_pos;
short y_pos;
event.getPosition(x_pos, y_pos);
ptArray.clear();
ptArray.append(MPoint(0, 0, 0));
ptArray.append(MPoint(-10, 0, 0));
ptArray.append(MPoint(0, 0, -10));
int method = 1;
if (method == 0)
{
MSelectionList incomingList;
MGlobal::getActiveSelectionList(incomingList);
MGlobal::selectFromScreen(x_pos, y_pos, MGlobal::kReplaceList, MGlobal::kSurfaceSelectMethod);
MSelectionList screenMSel;
MGlobal::getActiveSelectionList(screenMSel);
// Restore the active selection
MGlobal::setActiveSelectionList(incomingList, MGlobal::kReplaceList);
}
else if (method == 1)
{
// Is having this in tool on setup an option?
// Sluggish at 1000 spheres
MDagPath dagPath;
view.getCamera(dagPath);
MFnCamera camFn(dagPath);
MPoint raySource;
MVector rayDirection;
view.viewToWorld(x_pos, y_pos, raySource, rayDirection);
float maxParam = camFn.farClippingPlane();
MFloatPoint nearestHit;
MFloatPoint hitPoint;
float minParam = maxParam;
float hitRayParam = maxParam;
for (unsigned i = 0; i < allMeshes.length(); i++)
{
MFnMesh mFnMesh(allMeshes[i]);
mFnMesh.closestIntersection(raySource,
rayDirection,
NULL,
NULL,
true,
MSpace::kWorld,
minParam,
false,
&accels[i],
hitPoint,
&hitRayParam,
NULL,
NULL,
NULL,
NULL,
status
);
if (status != MS::kSuccess)
{
continue;
}
if (hitRayParam < minParam)
{
minParam = hitRayParam;
nearestHit = hitPoint;
}
}
ptArray[2] = nearestHit;
}
else if (method == 2)
{
}
drawMgr.setPaintStyle(MUIDrawManager::kStippled);
drawMgr.beginDrawInXray();
drawMgr.mesh(MUIDrawManager::kTriangles, ptArray);
drawMgr.endDrawInXray();
return MStatus();
}
// plugin initialization
MStatus initializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj, PLUGIN_COMPANY, "12.0", "Any");
status = plugin.registerContextCommand(MString("marqueeToolContext"), meshReorderContextCmd::creator);
return status;
}
MStatus uninitializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj);
status = plugin.deregisterContextCommand("marqueeToolContext");
return status;
}
import maya.mel as mel
cmds.file(new = True, f= True)
for i in range(10000):
x = random.randint(-10, 10)
y = random.randint(-10, 10)
z = random.randint(-10, 10)
s = cmds.polySphere()[0]
cmds.setAttr(s + '.t', x,y,z)
cmds.loadPlugin('...')
x = cmds.marqueeToolContext()
mel.eval('setToolTo {}'.format(x))