重大变更回调(C ++)

时间:2019-03-18 12:22:03

标签: c++ callback maya material maya-api

我目前正在研究Maya 2018和2019中的自定义视口。此刻,我正在实现我的材质解析器,以将Maya材质解析为自己框架的材质。

但是,我在创建回调方面很费力。我已经设法使初始回调起作用,可以在下面的代码片段中看到。这只是在将网格物体和材质添加到场景时加载它们的回调。

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 ;

所以,我不确定在这里做错了什么,因为据我所知,没有多少(或任何)有关此问题的样本。

一些帮助将不胜感激。预先感谢!

1 个答案:

答案 0 :(得分:0)

我已经解决了自己的问题。为了使提问者没有给出答案而感到沮丧,我将告诉问题出在什么地方:)

因此,实现存在两个问题。首先,我将回调绑定到了不正确的对象。我正在将回调绑定到shader[0]。此连接的着色器是具有表面着色器,置换着色器等的着色器组。当我更改Lambert着色器的属性时,此shader[0]的属性不会更改。因此,我必须将回调绑定到connected_plug[0](这是连接到shader[0]的插头)。 connected_plug[0]是来自着色器组的表面着色器节点,该节点已被更早地接收。

第二,我使用了不正确的回调函数。 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
);