我目前正在2018年和2019年开发自定义视口。目前,我正在实施我的材料解析器,以将Maya材料解析为我自己的Framework的材料。
但是,我很努力地创建回调。我已经设法将初始回调起作用,可以在下面的代码段中看到。这只是将网格和材料添加到场景时加载网格和材料的回调。
MCallbackId material_added_id = MDGMessage::addNodeAddedCallback(
MaterialAddedCallback,
"mesh",
m_material_parser.get(),
&status
);
在此回调函数中,我得到了连接到此网格的所有着色器,然后尝试将回调附加到对着色器对象的任何更改(请参阅下面的代码片段)。
void wmr::MaterialParser::Parse(const MFnMesh& mesh)
{
// ...
MObjectArray shaders; // References to the shaders used on the meshes
MIntArray material_indices; // Indices to the materials in the object array
// Get all attached shaders for this instance
mesh.getConnectedShaders(instance_index, shaders, material_indices);
switch (shaders.length())
{
// No shaders applied to this mesh instance
case 0:
{
}
break;
// All faces use the same material
case 1:
{
MPlug surface_shader = GetSurfaceShader(shaders[0]);
// Invalid surface shader
if (!surface_shader.has_value())
return;
// Find all plugs that are connected to this shader
MPlugArray connected_plugs;
surface_shader.value().connectedTo(connected_plugs, true, false);
// Could not find a valid connected plug
if (connected_plugs.length() != 1)
return;
auto shader_type = GetShaderType(connected_plugs[0].node());
// Shader type not supported by this plug-in
if (shader_type == detail::SurfaceShaderType::UNSUPPORTED)
return;
// Found a Lambert shader
if (shader_type == detail::SurfaceShaderType::LAMBERT)
{
MGlobal::displayInfo("Found a Lambert shader!");
MPlug color_plug = GetPlugByName(connected_plugs[0].node(), "color");
// Retrieve the texture associated with this plug
auto texture_path = GetPlugTexture(color_plug);
// Print the texture location
MGlobal::displayInfo(texture_path.asChar());
// Add callback that filters on material changes
MStatus status;
MCallbackId attributeId = MNodeMessage::addAttributeChangedCallback(
shaders[0],
MaterialCallback,
this,
&status
);
CallbackManager::GetInstance().RegisterCallback(attributeId);
}
}
break;
// Two or more materials are used
default:
{
// ...
break;
}
}
}
void MaterialCallback(MNodeMessage::AttributeMessage msg, MPlug &plug, MPlug &otherPlug, void *clientData)
{
MGlobal::displayInfo("Hey! Im a material callback!");
}
注意开关案例。尤其是发现一个着色器时的case 1:
。当发现兰伯特着色器时,将"Found Lambert"
打印在输出中。之后,我将回调addAttributeChangedCallback
连接到着色器对象。但是,这永远不会触发。
输出如下所示(有时更改透明度和颜色值之后)。如您所见,"Hey! Im a material callback!"
在任何地方都没有打印出来,但是当我从材料中更改属性时,应该称呼它。
// Found a Lambert shader!
//
select -r pCylinder1 ;
setAttr "lambert1.transparency" -type double3 0.0779221 0.0779221 0.0779221 ;
setAttr "lambert1.transparency" -type double3 0.194805 0.194805 0.194805 ;
setAttr "lambert1.color" -type double3 0.0779221 0.0779221 0.0779221 ;
所以,我不确定我在这里做错了什么,因为据我所知,关于这个问题的样本不多。
一些帮助将不胜感激。预先感谢!
我自己解决了问题。为了感到沮丧,答案没有由发问者给出,我会说出问题是什么:)
因此,实施有两个问题。首先,我将回调绑定到不正确的对象。我将回调绑定到shader[0]
。此连接的着色器是一个具有表面着色器,位移着色器等的着色器组。当我更改Lambert着色器的属性时,该shader[0]
的属性不会更改。因此,我必须将回调绑定到connected_plug[0]
(这是连接到shader[0]
的插头)。connected_plug[0]
是已收到Eralier的着色器组的表面着色器节点。
其次,我使用了错误的回调函数。addAttributeChangedCallback
原来是错误的工厂功能。相反,我必须使用addNodeDirtyCallback
,因为我将回调绑定到的对象是节点/插头。
MObjectArray shaders;
mesh.getConnectedShaders(instance_index, shaders, material_indices);
// ...
MPlugArray connected_plugs;
surface_shader.value().connectedTo(connected_plugs, true, false);
// ...
MObject connected_plug = connected_plugs[0].node();
// ...
// Add callback that filters on material changes
MStatus status;
MCallbackId attributeId = MNodeMessage::addNodeDirtyCallback(
connected_plug,
DirtyNodeCallback,
this,
&status
);