Qt3d Sceneloader: замените компонент материала сущности на мой собственный материал во время выполнения - PullRequest
0 голосов
/ 04 марта 2019

У меня есть следующий код для загрузки сцены Collada с помощью SceneLoader:

SceneLoader{
    id: sceneLoader
    source: "file:///home/rui/projects/cad/bodyplacement_lm36_v2.dae"


    MetalRoughMaterial {

        id:metal_mat
        objectName: "MetalRoughMaterial"

        metalness: 0
        roughness: 0.9
    }


    onStatusChanged: {
        console.log("SceneLoader status: " + status);
        if (status == SceneLoader.Ready) {
            console.log("Scene is ready");

            var entitynames=sceneLoader.entityNames();
            for (var i = 0; i < entitynames.length; ++i) {

                var entityname=entitynames[i];
                var entityvar=sceneLoader.entity(entityname);

                for (var j = 0; j< entityvar.components.length; ++j) {


                    var cmp=entityvar.components[j]
                    if(cmp){
                        var cmp_class=cmp.toString();
                        if(cmp_class.indexOf("QPhongMaterial")>=0){
                            entityvar.components[j]=metal_mat;
                        }

                    }



                }



            }



        }
    }




}

Как указано в документации (https://doc.qt.io/qt-5/qt3drender-qsceneloader.html#details):

Загрузчик попытается определитьлучший материал для использования на основе свойств файла модели. Если вы хотите использовать пользовательский материал, вам придется пройтись по дереву и заменить связанные материалы по умолчанию вашими.

После того, как яитерируйте все сущности, которые я пытаюсь заменить компонентом материала с кодом:

entityvar.components[j]=metal_mat;

, но он не работает. После отладки я вижу, что загруженный материал не заменяется.

Как я могу заменить компонент материала своим собственным материалом во время выполнения?

1 Ответ

0 голосов
/ 25 апреля 2019

Я работаю над решением этой проблемы.У вашего кода есть пара проблем.

entityvar.components[j]=metal_mat;

это не будет работать, потому что qml хочет, чтобы вы заменили весь массив, вы не можете изменить его на месте

var entitynames=sceneLoader.entityNames();
    for (var i = 0; i < entitynames.length; ++i) {
        var entityname=entitynames[i];
        var entityvar=sceneLoader.entity(entityname);

Это не будет работатьдля файлов, которые имеют сущности или подмодели с одинаковыми именами, например, вообще без имени.

Вот как я решил эти проблемы: SceneLoader загружает сцену из файла fbx или obj и помещает ее как childNodes в родительский объект,Таким образом, единственный способ пройтись по дереву - посмотреть массив childNodes родительского объекта.

import Qt3D.Render 2.12
import Qt3D.Extras 2.12
import Qt3D.Core 2.12

Entity {
    id: rootEntity

    property alias source: loader.source
    property Transform transform: Transform{}
    components:[ loader, transform ]

    SceneLoader {
        id: loader

        Component {
            id: pbrMatTemplate
            MetalRoughMaterial { }
        }

        onStatusChanged: {
            if(status == SceneLoader.Ready) {
                instantiateMaterials();
            }
        }
    }


    function instantiateMaterials() {
        // TODO create as many materials as you need here
        var newmat = pbrMatTemplate.createObject(loader);

        function traverseNodes(node) {
            if(node.components) {
                var comps = [];
                for (var j = 0; j< node.components.length; ++j) {
                    var cmp = node.components[j];
                    var cmp_class = cmp.toString();
                    if(cmp_class.indexOf("QPhongMaterial")>=0) {
                        // TODO: look up material from list of materials you created instead of just using one
                        comps.push(newMat);
                    } else {
                        comps.push(cmp);
                    }
                }
                // replace whole list of components
                node.components = comps;
            }

            if(node.childNodes) {
                for(var i=0; i<node.childNodes.length; i++) {
                    if(node.childNodes[i] == null) continue;
                    traverseNodes(node.childNodes[i]);
                }
            }
        } // traverseNodes()

        traverseNodes(rootEntity);
    }
}
...