如何使Maya C++ API中doRelease创建的MPxManipulatorNode可选中
问题:动态创建的MPxManipulatorNode无法选中
我自定义了一个MPxManipContainer,其中包含两个自定义MPxManipulatorNode实例:一个在容器的createChildren()函数内创建,另一个在鼠标按钮doRelease()事件触发时创建。目前遇到的问题是:createChildren()中创建的MPxManipulatorNode可被选中,但doRelease()中创建的实例无法被选中。
代码示例
struct LineManip : MPxManipulatorNode { static MTypeId id; ... }; MTypeId LineManip::id = 0x81047; struct ToyManipContainer : MPxManipContainer { static MTypeId id; ... MStatus addLineManip( const MString& name_, double y_ = 0.0 ) { MStatus status = MStatus::kSuccess; MPxManipulatorNode* proxyManip = 0; MString manipTypeName("LineManip"); status = addMPxManipulatorNode( manipTypeName, name_, proxyManip ); CHECK_STATUS_AND_RETURN_IF_FAIL( status, "Failed in addMPxManipulatorNode." ); // 定位新的线条操纵器到指定高度 LineManip* tmpManipPtr = (LineManip*) proxyManip; tmpManipPtr->start.y = y_; tmpManipPtr->end.y = y_; return status; } MStatus createChildren() override { MStatus status = MS::kSuccess; // 初始化阶段创建的操纵器,可正常选中 status = addLineManip( MString("foo"), 0.0 ); CHECK_STATUS_AND_RETURN_IF_FAIL( status, "Failed to create the temp LineManip." ); return status; } MStatus doRelease() override { MStatus status = MS::kSuccess; // 鼠标释放时创建的操纵器,无法被选中 status = addLineManip( MString("bar"), 0.5 ); CHECK_STATUS_AND_RETURN_IF_FAIL( status, "Failed to add LineManip in ToyManipContainer." ); return status; } }; MTypeId ToyManipContainer::id = 0x81559;
插件效果截图

原因解释
- Maya的
MPxManipContainer在初始化阶段(createChildren()执行期间),会自动完成子操纵器的选择注册流程:包括将操纵器的碰撞检测区域(hit test)纳入Maya的交互检测体系,确保鼠标能识别到操纵器的可选中状态。 - 而在
doRelease()这类运行时事件中调用addMPxManipulatorNode(),仅完成了操纵器的实例创建和添加,但Maya不会自动触发后续的选择注册逻辑,导致新创建的操纵器无法被鼠标检测到。
解决方法
在doRelease()中创建完新操纵器后,需要手动触发容器的更新和操纵器的注册操作,具体步骤:
- 调用
MPxManipContainer::refresh(),强制容器重新同步所有子操纵器的状态。 - 调用新创建的
MPxManipulatorNode::addToManipulatorManager(),将其手动注册到Maya的操纵器管理器中,确保碰撞检测区域被纳入交互体系。
修改后的核心代码
// 修改addLineManip方法,返回创建的操纵器指针 MStatus addLineManip( const MString& name_, double y_ = 0.0, LineManip*& outManip_ ) { MStatus status = MStatus::kSuccess; MPxManipulatorNode* proxyManip = 0; MString manipTypeName("LineManip"); status = addMPxManipulatorNode( manipTypeName, name_, proxyManip ); CHECK_STATUS_AND_RETURN_IF_FAIL( status, "Failed in addMPxManipulatorNode." ); outManip_ = (LineManip*) proxyManip; outManip_->start.y = y_; outManip_->end.y = y_; return status; } // 更新doRelease方法,添加手动注册逻辑 MStatus doRelease() override { MStatus status = MS::kSuccess; LineManip* newManip = nullptr; status = addLineManip( MString("bar"), 0.5, newManip ); CHECK_STATUS_AND_RETURN_IF_FAIL( status, "Failed to add LineManip in ToyManipContainer." ); // 手动注册操纵器并刷新容器 if (newManip) { newManip->addToManipulatorManager(); refresh(); } return status; }
内容的提问来源于stack exchange,提问作者Constantinos Glynos
相关产品推荐
相关产品推荐

