Porting selection functionality in your plug-ins can be seen as a separate task from porting drawing, depending on the interfaces used and the version of Maya used.
As of Maya 2016, native Viewport 2 selection is available.
Before the 2016 release, selection could only be performed using existing Viewport 1 interfaces. The Viewport 1 interface drawing must use OpenGL even if the draw code for Viewport 2 is using a different drawing API (such as DirectX11).
The Viewport 1 interfaces are dependent on OpenGL software pick buffers for selection. Software pick buffers are not available when you are using a core profile context. If a legacy OpenGL profile is available, then this functionality may be available.
A choice of OpenGL profiles is available on the Windows and Linux platforms. On certain configurations of Mac OS X, only core profile contexts can be instantiated.
The following is an overview of the Viewport 2.0 selection interfaces for various objects and components. For more information regarding these interfaces, see the sections below.
Objects/components | Interface for drawing | Interface for selection |
---|---|---|
Manipulators: | MUIDrawManager | Drawing done using MUIDrawManager is used for hit testing. MUIDrawManager::beginDrawable(unsigned int name, bool nameIsPickable )The bool nameIsPickable input parameter to this interface can be used to mark drawables as selectable. |
Locators: | MUIDrawManager | Drawing done using MUIDrawManager is used for hit testing. |
Shapes: | MPxSurfaceShape::getShapeSelectionMask() to specify the type of geometry, selection priority and filtering. MPxSubSceneOverride::getSelectionPath() for complex plug-ins to obtain the dag path from a render item. |
|
Components |
|
Tool contexts (MPxContext) cannot be selected and are thus not included in this list.
Manipulators are not selectable at the object level for both Viewport 1 and Viewport 2 as they do not exist as scene elements.
The selection level that is available for MPxManipulatorNode instances is defined at the "sub-object" level, also called the "handle level".
Manipulator containers (MPxManipContainer) that are composed from existing manipulators require no additional code to support selection as this support is defined at the manipulator level. This is true for both Viewport 1 and Viewport 2. It is possible to add additional draw (and hence selection) for a container as desired.
Draw Interface Used | Viewport 2 Selection Disabled | Viewport 2 Selection Enabled | SDK Examples |
---|---|---|---|
MUIDrawManager (without custom selection handles) | Uses Viewport 1 draw routine for hit testing. | All drawing done using MUIDrawManager during draw will be used for a single hit test. | footprintManip (MPxManipulatorNode) swissArmyManip (MPxManipContainer) |
MUIDrawManager (with custom selection handles) | Viewport 1 interfaces use OpenGL pick identifiers as the actual selection handles and explicitly relies on software pick buffers (which may not exist for all OpenGL context profiles). Interfaces that can be used: colorAndName() shouldDrawHandleAsSelected() glFirstHandle() glActiveName() | Specific drawables can be marked selectable using "handle" identifiers via arguments on the MUIDrawManager::beginDrawable() method: MUIDrawManager::beginDrawable(unsigned int name, bool nameIsPickable ) If nameIsPickable is set to be "true" then the subsequent draw code will be used for hit testing. This should apply for both 3D as well as 2D manipulators. | lineManip (MPxManipulatorNode) |
Locators (MPxLocatorNode) are only selectable at the object level.
For locators that draw very simple geometry, or when there will be very few occurrences of a given locator in a scene, it is acceptable to use the MUIDrawManager interface for drawing and selection.
For "click" or closest point single selection, there is no change in the interface logic used. The members MPxLocatorNode::useClosestPointForSelection() and MPxLocatorNode::closestPoint() should be implemented for Viewport 1 selection. For Viewport 2 selection, the closest point is computed automatically from the geometry data and hence the APIs are not used.
Anything that is more complicated or requires better performance falls into the category of "shapes", covered in the next section. They should be implemented using an MPxGeometryOverride or MPxSubSceneOverride
Draw Interface Used | Viewport 2 Selection Disabled | Viewport 2 Selection Enabled | Examples |
---|---|---|---|
MUIDrawManager | MPxLocatorNode::boundingBox() is used for hit testing. | All drawing using MUIDrawManager is used for hit testing. | 2016 version of footPrintNode |
MPxDrawOverride::prepareForDraw() | MPxLocatorNode::boundingBox() is used for hit testing. Position of the hit is the position of the origin of the
locator. For more precision, implement
MPxLocatorNode::closestPoint() (see above).
(Note: MPxDrawOverride::prepareForDraw() is not used, even if implemented). |
Raw draw code cannot be supported and therefore using MPxDrawOverride is not recommended. | 2015 or earlier version of footPrintNode, or 2016 version of rawFootPrintNode |
More complex object types such as MPxSurfaceShape and MPxComponentShape, (or MPxLocatorNodes that require more complex or persistent drawing) should use render item (MRenderItem) -based interfaces: MPxGeometryOverride or MPxSubSceneOverride.
Using MUIDrawManager for complex objects is not recommended, though Viewport 2 selection can still work.
Using MPxDrawOverride if Viewport 2 selection is required is not recommended as it does not support raw draw code.
Draw interface used | Viewport 2 Selection Disabled | Viewport 2 Selection Enabled | Examples |
---|---|---|---|
MPxGeometryOverride (object level) | Use Viewport 1 selection interfaces | Selection is performed per render item. For shapes, MPxSurfaceShape::getShapeSelectionMask() can be overridden to specify the type of geometry, selection priority and filtering. | footPrintNode_GeometryOverride: for usage with a locator apiMeshShape: for usage with a surface shape gpuCacheShapeNode: for an example of using getShapeSelectionMask() |
MPxGeometryOverride (component level) | Use Viewport 1 selection code | See Viewport 2 Selection Handling of Components section. | apiMeshShape |
Draw interface used | Viewport 2 Selection Disabled | Viewport 2 Selection Enabled | Examples |
---|---|---|---|
MPxSubSceneOverride | Use Viewport 1 selection interfaces or custom selection. | Complex plugins may require implementing getSelectionPath() to get back the proper dag path (MDagPath) from a render item. | gpuCache: gpuCacheSubSceneOverride.cpp |
MPxSubSceneOverride (component level) | Use Viewport 1 selection interfaces or custom selection. | See Viewport 2 Selection Handling of Components section. |
When Viewport 2 selection is enabled (as of Maya 2016) the selection interfaces on MPxSurfaceShapeUI are no longer called.
Functionality in the following Viewport 1 interfaces:
are handled by the following Viewport 2 interfaces:
Registered / deregistered on MDrawRegistry using registerComponentConverter() / deregisterComponentConverter()
A "selection" mode (DrawMode) allows indication of whether a render item should be used for selection.
There is the ability to set a selection mask (MSelectionMask) to indicate the selection type.
Render items marked for selection are added when the draw update code is called due to any change in rendering preferences (for example: a change in the highlight list, and so forth). Starting a selection should not dirty the render items of scene elements that are not in the selection region, so the plug-in should not expect MPxGeometryOverride::updateDG() to be called for all nodes each time a selection is done.
The following describes the steps by which selection is processed:
Selection interpretation stage:
Examples: apiMeshShape (MPxGeometryOverride, and MPxSubSceneOverride versions).
For hardware shaders that displace input geometry (for example, a mesh that is drawn at a different location, or with more details, such as tessellation), or that generate complex geometries at the shader level (for example, shaders that use a geometry stage to draw complex geometry such as a particle blob on a very basic geometry such as a point):
It is possible to reference or extract out the geometry used for render items (MRenderItems) and to use raw resource handle to draw with. This can help to avoid duplicating memory if using Viewport 2 draw and Viewport 1 selection.
In camera based selection mode, the scene is painted using a single plain color for each distinct scene element that can be selected. The shader should use the following formula to generate the plain color used for selection:
int colorID = [HWS_PrimitiveBase]; if (![HWS_ObjectLevel]) colorID += PrimitiveID; if ([HWS_InstancedDraw]) colorID += InstanceID * [HWS_PrimitiveCountPerInstance]; float4 color; color.x = float(colorID & 0x000000FF) / 255.0; color.y = float((colorID & 0x0000FF00) >> 8) / 255.0; color.z = float((colorID & 0x00FF0000) >> 16) / 255.0; color.w = 1.0;
PrimitiveID and InstanceID are system values that can be retrieved using the correct GLSL/HLSL API (SV_PrimitiveID and SV_InstanceID for DX11, and gl_PrimitiveID and gl_InstanceID for GLSL). Square brackets are used to indicate any variable that is declared using the aforementioned semantics.
Refer to the NormalView_Selection technique definition in the WaterSimulation shader example for a demonstration of how to select displaced geometry, and to draw vertex, edge, and face components at their correct displaced positions. For the GLSL version, see the WaterSimulation.ogsfx and PS_HWSelection.ogsfh files in the presets\GLSL\examples folder of the Maya installation directory. For the DX11 version, see the WaterSimulation.fx and PS_HWSelection.fxh files in the presets\HLSL11\examples folder.
MPxLocatorNode::getShapeSelectionMask() or MPxSurfaceShape::getShapeSelectionMask() can be overridden to return the desired selection mask for use in Viewport 2.0.
This can be either an existing internal mask or a custom one that is registered by using MSelectionMask::registerSelectionType(). For example, if a custom type called "my_selection_type" is registered, the getShapeSelectionMask() would return MSelectionMask("my_selection_type").
By default, custom selection types are disabled. To enable a custom selection type, do as follows:
"selectType -byName \"my_selection_type\" 1"
where "my_selection_type" is your custom type.
Also available with a custom selection type is the ability to set the priority via the selectPriority command. In this example, assume that the registration originally set the priority to be 2.
// Change it to be lower in priority selectPriority -byName "my_selection_type" 1; // Change it to be higher in priority selectPriority -byName "my_selection_type" 3;
An example use case is when an environment encompasses the scene. The user may either not be able to or accidentally select the environment instead of the objects in the scene. To mitigate this, the environment's selection priority can be lowered.
Selection of a particular type can also be disabled to disallow selection:
"selectType -byName "my_selection_type" 0;
See the footPrintNode geometry override implementation (footPrintNode_GeometryOverride Developer Kit example) for an example use of MPxLocatorNode and a custom selection type. See apiDirectionalLightShape and apiMeshShape for example use of internal masks.