Ограничительная рамка объекта stl в three.js

Всем добрый день,

Я наткнулся на несколько сообщений по этой теме, но ни одно решение не сработало. У меня есть объект, который я загружаю с помощью STLLoader в three.js, для которого я хотел бы получить ограничительную рамку.

    // Add stl objects and a name
function addSTLObject(url, name) {
    var loader = new THREE.STLLoader();
    loader.load(url, function (geometry) {

        var material = new THREE.MeshPhongMaterial({ color: 0xff5533 });
        var mesh = new THREE.Mesh(geometry, material);
        // To scale element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Add a name to the object to find it if it needs to be removed
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        scene.add(mesh);
    });
}

и я загружаю этот объект следующим образом:

addSTLObject('model/cases/iphone5.stl', 'phone-model');
var phoneModelAdded = scene.getObjectByName('phone-model', true);

Теперь я попробовал решения, представленные здесь: https://github.com/mrdoob/three.js/issues/3471 и здесь Есть способ получить ограничивающую рамку из объекта three.js Object3D?

var bbox = new THREE.Box3().setFromObject(phoneModelAdded);

var geometry = phoneModel.children[0].children[0].geometry;
geometry.computeBoundingBox();

В то время как первое решение дает мне сообщение об ошибке «Невозможно прочитать свойство updateMatrixWorld из неопределенного», второе не дает мне никакой ошибки, но ничего не делает, и если я пытаюсь получить доступ к свойству «геометрия», оно говорит, что оно не существует.

У кого-нибудь есть рабочее решение? Любая помощь приветствуется.

Хорошего дня!

ИЗМЕНИТЬ:

        // Add stl objects and a name
function addSTLObject(url, name) {
    var bbox;
    var loader = new THREE.STLLoader();
    loader.load(url, function (geometry) {

        var material = new THREE.MeshPhongMaterial({ color: 0xff5533 });
        var mesh = new THREE.Mesh(geometry, material);
        // To scale element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Add a name to the object to find it if it needs to be removed
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        bbox = new THREE.Box3().setFromObject(mesh);

        scene.add(mesh);

        return bbox;
    });
}

и далее

var bbox = addSTLObject('model/cases/iphone5.stl', 'phone-model');
    scene.add(bbox);

Ошибка: «THREE.Object3D.add: объект не является экземпляром THREE.Object3D»

РЕДАКТИРОВАТЬ 2:

var bbox, bboxComputed = false;

    function addSTLObject(url, name) {
    var bbox;
    var loader = new THREE.STLLoader();
    loader.load(url, function (geometry) {

        var material = new THREE.MeshPhongMaterial({ color: 0xff5533 });
        var mesh = new THREE.Mesh(geometry, material);
        // To scale element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Add a name to the object to find it if it needs to be removed
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        bbox = new THREE.BoundingBoxHelper(mesh);
        bbox.update();
        bboxComputed = true;

        scene.add(mesh);
    });

}

addSTLObject('model/cases/iphone5.stl', 'phone-model');
    var myInterval = setInterval( function(){
        if( bboxComputed ) {
            alert( bbox.box.min, bbox.box.max, bbox.box.size() );
            scene.add(bbox);
            clearInterval( myInterval );
            bboxComputed = false;
        }
    }, 100 );

Это не сработает.

РЕДАКТИРОВАТЬ 3: я пытался настроить функцию, которая имела бы все, что мне нужно, и возвращала бы объект со всей рассчитанной информацией:

    function calculateSTLProperties(url, name) {
    var STLObject, STLbbox, STLComputed = false, STLGeometry;

    var loader = new THREE.STLLoader();
    loader.load(url, function (geometry) {

        var material = new THREE.MeshPhongMaterial({ color: 0xff5533 });
        var mesh = new THREE.Mesh(geometry, material);
        // To scale element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Add a name to the object to find it if it needs to be removed
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        // Compute a bounding box for the element
        STLbbox = new THREE.BoundingBoxHelper(mesh);
        STLbbox.update();

        // Get the geometry of the case
        STLGeometry = geometry;
        STLComputed = true;
    });

    // Set an interval to wait for the corresponding bounding box and geometry to be computed
    var myInterval = setInterval( function(){
        if( STLComputed ) {
        STLObject = {
            "geometry" : STLGeometry,
            "bbox" : STLbbox,
            "x" : STLbbox.box.size().x,
            "y" : STLbbox.box.size().y,
            "z" : STLbbox.box.size().z
        };

        clearInterval( myInterval );
        bboxComputed = false;

        }
    }, 100 );

    return STLObject;
}

К сожалению, каким-то образом объект не передается, и в конце я получаю «неопределенное» при попытке сохранить его:

var STLObjectLoaded = calculateSTLProperties('model/cases/iphone5.stl', 'phone-model');
    console.log(STLObjectLoaded);

Что мне не хватает?


person Sebastian    schedule 04.08.2015    source источник
comment
Откуда вы знаете, что объект действительно был загружен до того, как вы вызовете scene.getObjectByName(). Загрузка асинхронная.   -  person gaitat    schedule 04.08.2015


Ответы (2)


Загрузка модели является асинхронной, поэтому все ваши вычисления должны выполняться после загрузки модели. Добавьте callback, который вызывается при загрузке модели и добавьте туда вызов bbox. В вашем случае вызов scene.getObjectByName() выполняется с пустым объектом, который вы также проверяете («если я пытаюсь получить доступ к свойству «геометрия», он говорит, что он не существует»)

Обновление:

Использовать:

var bbox = new THREE.BoundingBoxHelper( mesh ); bbox.update();
scene.add( bbox );

изнутри функции loader.load().

Вызов setFromObject() создает только ограничивающую рамку, но не геометрию для bbox.

Обновление II

Если вы хотите, чтобы bbox была доступна за пределами вашей функции loader.load(), вам нужно будет использовать глобальную переменную

var bboxComputed = false;

которому вы устанавливаете значение true сразу после вычисления bbox внутри вашей функции loader.load():

scene.add( bbox );
bboxComputed = true;

Затем в вашем основном вместо использования:

console.log( bbox.box.min, bbox.box.max, bbox.box.size() );

вы бы использовали что-то вроде:

var myInterval = setInterval( function(){
    if( bboxComputed ) {
        console.log( bbox.box.min, bbox.box.max, bbox.box.size() );
        clearInterval( myInterval );
    }
}, 100 );

Я устанавливаю задержку 0,1 секунды, и когда bbox наконец вычислено, я очищаю интервал, чтобы он не работал вечно.

person gaitat    schedule 04.08.2015
comment
Не уверен, что вы имеете в виду. Я вызываю свою функцию, я вызываю .getObjectByName(), а затем я вызываю var bbox = new THREE.Box3().setFromObject(phoneModelAdded);. Так что это должен быть правильный порядок, не так ли? Как добавить «обратный вызов»? - person Sebastian; 04.08.2015
comment
Да, но вызывайте их внутри обратного вызова loader.load(). - person gaitat; 04.08.2015
comment
Я изменил свой пост с тем, что я изменил, и полученной ошибкой. Помоги пожалуйста! - person Sebastian; 04.08.2015
comment
return bbox возвращается из loader.load(), а не из addSTLObject() - person gaitat; 04.08.2015
comment
Все та же ошибка, к сожалению. Возможно, просмотр моих настроек прояснит ситуацию: sebastianjvf.github.io/index2.html - person Sebastian; 04.08.2015
comment
то, что вы делаете, по-прежнему становится жертвой асинхронной загрузки, поскольку return bbox внутри addSTLObject() будет нулевым объектом. Обновленный ответ. - person gaitat; 04.08.2015
comment
Спасибо, это работает! Последний вопрос: мне все равно нужно, чтобы bbox был доступен вне функции. Как я могу добиться этого, не впадая в асинхронную загрузку? - person Sebastian; 04.08.2015
comment
Спасибо за ответ, но я в замешательстве. Я понимаю идею, но я действительно не знаю, как я смогу получить доступ к информации о bbox? Если бы я поместил интервал в основной раздел, он бы не был известен основному, не так ли? Я отредактировал свой пост выше! - person Sebastian; 04.08.2015
comment
извините, вы бы сделали переменную bbox глобальной. - person gaitat; 04.08.2015
comment
Это отлично работает! Я думал, что это не сработает, но у меня была простая орфографическая ошибка в одной из моих переменных. Большое спасибо! - person Sebastian; 05.08.2015
comment
Я обновил свой пост в последний раз. Не могли бы вы взглянуть в последний раз, пожалуйста? Спасибо! (РЕДАКТИРОВАТЬ 3) - person Sebastian; 05.08.2015

Начиная с three.js R125, рекомендуемый способ сделать это — использовать метод loadAsync, который теперь встроен в three.js:

https://threejs.org/docs/#api/en/loaders/Loader.loadAsync

Этот метод возвращает обещание. Затем вы можете использовать «тогда», чтобы получить геометрию STL и создать сетку. Вы также можете использовать традиционный обратный вызов, как в предыдущих ответах, или структуру async/await, но я думаю, что приведенный ниже пример с использованием собственного метода three.js является самым простым способом. В примере показано, как вы можете получить геометрию в глобальную переменную после разрешения промиса и загрузки файла STL:

// Global variables for bounding boxes
let bbox;

const loader = new STLLoader();
const promise = loader.loadAsync('model1.stl');
promise.then(function ( geometry ) {
  const material = new THREE.MeshPhongMaterial();
  const mesh = new THREE.Mesh( geometry, material );
  mesh.geometry.computeBoundingBox();
  bbox = mesh.geometry.boundingBox;
  scene.add( mesh );
  buildScene();
  console.log('STL file loaded!');
}).catch(failureCallback);

function failureCallback(){
  console.log('Could not load STL file!');
}

function buildScene() {
  console.log('STL file is loaded, so now build the scene');
  // !VA bounding box of the STL mesh accessible now
  console.log(bbox);
  // Build the rest of your scene...
}
person VanAlbert    schedule 06.02.2021