Обратный вызов изменения материала (C++)

В настоящее время я работаю над пользовательским окном просмотра в 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" печатается в выводе, когда шейдер Ламберта был найден. После этого я прикрепляю callback 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 ;

Итак, я не уверен, что я здесь делаю неправильно, поскольку, насколько я могу найти, не так много (или вообще) примеров по этой проблеме.

Некоторая помощь будет очень признательна. Заранее спасибо!


person M Zeinstra    schedule 18.03.2019    source источник
comment
Может быть, глупо, но вы проверяли переменную состояния после добавления обратного вызова?   -  person haggi krey    schedule 19.03.2019
comment
Да, обратный вызов возвращает статус MStatus::kSuccess.. Однако я уже исправил проблему и поделюсь ею как можно скорее :)   -  person M Zeinstra    schedule 21.03.2019


Ответы (1)


Я сам решил свою проблему. Ради разочарования, что вопрос не дал ответа, я скажу, в чем проблема :)

Итак, с реализацией было две проблемы. Прежде всего, я привязывал обратный вызов к неверному объекту. Я привязывал обратный вызов к shader[0]. Этот связанный шейдер представляет собой группу шейдеров с поверхностным шейдером, шейдером смещения и т. д. Атрибуты этого 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
);
person M Zeinstra    schedule 21.03.2019