如何在STLLoader事件侦听器之外缓存STL几何

时间:2013-05-16 13:46:08

标签: javascript three.js webgl

我正在尝试使用Three.js STLLoader从STL文件中读取和缓存几何体。我正在使用事件循环回调来获取数据(类似于STLLoader示例)。我打算存储在外部变量“cgeom”中。但是,看起来几何体在事件CB之外是不可用的并且未定义cgeom(运行时错误:未定义cgeom)。有人可以告诉我我在那里做错了(代码如下):< / p>

<!DOCTYPE html>

<html>
<head>
    <title>Thee.js STL geometry caching test</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>

<body>

    <script src="js/three.min.js"></script>
    <script src="js/STLLoader.js"></script>
    <script>

        alert("We'are here");

        var cgeom;

        function load_geometry( stl_file ) {

            var loader = new THREE.STLLoader();     
            loader.addEventListener( 'load', function ( event ) {
            cgeom = event.content;
                alert('inside listener - vertices: ' + cgeom.vertices.length);
            } );
            loader.load(stl_file);
            alert('inside load_geometry - vertices: ' + cgeom.vertices.length); // error - cgeom is not defined
        }

        load_geometry('./data/a90.stl');     
        alert('inside load_geometry - vertices: ' + cgeom.vertices.length); // error - cgeom is not defined

    </script>

</body>
</html>

所有示例都从几何体创建网格并立即将其添加到场景中。那不是我想要的。我需要稍后添加它,以替换场景中的另一个网格。这就是为什么我要首先缓存它。

提前谢谢你, 西蒙

P.S。我不是JS专家,但有10年以上的c ++和java经验。

4 个答案:

答案 0 :(得分:0)

只有在执行了事件处理程序之后,

cgeom才会有值。您的所有代码都会立即运行,但不包括:

       loader.addEventListener( 'load', function ( event ) {
           cgeom = event.content;
            alert('inside listener - vertices: ' + cgeom.vertices.length);
        } );

因此,您需要等待几何体加载(此回调才能运行),然后才能尝试使用它。

答案 1 :(得分:0)

您不必立即添加到场景中,但可以将其添加到外部对象。所以在装载机之前你可以做到:

var geometriesToLoad = 2;
var geom1 = new THREE.Object3D ();
var geom2 = new THREE.Object3D ();

在回调中你会这样做:

geom.add (cgeom);
geometriesToLoad --;

其中geom是您传递到load_geometry()例程的附加值; geom1或geom2。

geometriesToLoad为0时,您的所有模型都已加载,您可以继续处理。您可以使用setTimeout调用来检查它。

答案 2 :(得分:0)

感谢gaitat和yaku,解决了这个难题。问题是加载是并行完成的,我在模型实际加载之前检查结果。这是工作代码(我正在等待模型在setTimeout回调中加载):

<script>

    var cgeom;
    var mt;

    function load_geometry( stl_file ) {

            var loader = new THREE.STLLoader();     
            loader.addEventListener( 'load', function ( event ) {
                cgeom = event.content;
                cgeom.dynamic = true;
                console.log('inside listener - vertices: ' + cgeom.vertices.length);
            } );
            loader.load(stl_file);

    }

    load_geometry('./data/a.stl');     

    // start waiting
    mt = setInterval(function () {
        if (cgeom == undefined )
            console.log('wating ...')
        else {
            console.log('cgeom is defined, loaded vertices: ' + cgeom.vertices.length);
            clearInterval(mt);
        }            
    }, 1000);

    if (cgeom == undefined )
            console.log('cgeom - UNDEFINED ...');

</script>

答案 3 :(得分:0)

迟到了,但从three.js R125开始,推荐的方法是使用loadAsync方法,它现在是three.js的原生方法:

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

该方法返回一个承诺。然后您可以使用“then”来获取 STL 的几何形状并创建网格。您也可以使用传统的回调或 async/await 结构,但我认为下面使用原生three.js 方法的示例是最简单的方法。该示例显示了如何在解析 promise 并加载 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...
}