【问题标题】:canceling loading an object into a scene in THREE.js在 THREE.js 中取消将对象加载到场景中
【发布时间】:2023-03-03 09:54:02
【问题描述】:

所以我有一个 THREE.js 场景,我必须取消将文件上传到场景。在我的页面中,我可以上传多个可能的文件,但我正在尝试对其进行设置,以便您一次只能上传一个以在场景中查看。我使用 Angular 将我的三个 js 场景和画布实现为本质上是一个工厂,因为我一次只想要一个画布实例。这是那个工厂的基本代码(对于这个特定的问题)我顺便使用了 Angular,这是 app.factory 一开始和 PartLibrary 注入的原因,但这不相关。您需要知道的是 PartLibrary.load_part_stl() 只是一个函数,它进行 ajax 调用以获取要加载的 stl 文件的 url::

app.factory('ModelViewer', ['PartLibrary', function(QuoteLibrary){
    var modelViewer = {
        model_material: {},
        part_model: {},
        part: {}, 
        scene: {},
        camera: {},
        renderer: {},
        loader: {},
        manager: {},
        id: {}
    };

    modelViewer.destroy_old = function(canvas_selector){
        cancelAnimationFrame(this.id);
        this.scene = null;
        this.renderer = null;
        this.camera = null;
        this.part_edges = null;
        this.part_model = null;
        this.loader = null;
        this.manager = null;
        $('canvas').remove();
    }

    modelViewer.init = function(part, canvas_selector){
        var self = this;


        // distroy any old three js canvases
        self.destroy_old(canvas_selector);

        self.part = part;
        self.initiated = true;
        var container = $(canvas_selector)[0];
        self.scene = new THREE.Scene();
        self.camera = new THREE.PerspectiveCamera( 45, $(canvas_selector).width()/$(canvas_selector).height(), 1, 20000 );
        self.scene.add( new THREE.AmbientLight( 0x4F4F4F ) );


        self.renderer = new THREE.WebGLRenderer( { antialias: true } );
        container.appendChild( self.renderer.domElement );

        PartLibrary.load_part_stl(part.id)
            .success(function(url){
                loadModel(url, self);
            })
            .error(function(){
                console.log("Error loading STL file for 3D view");
            });

        function loadModel(url){

            self.manager = new THREE.LoadingManager();
            self.loader = new THREE.STLLoader(self.manager);

            self.manager.onLoad = function(item, loaded, total){
                $('.model-loading').hide();
            }

            self.loader.load(url, function(geometry){
                self.model_material = new THREE.MeshPhongMaterial();
                self.part_model = new THREE.Mesh( geometry, self.model_material );

                self.scene.add( self.part_model );
            });
        }

        function animate() {
            self.id = requestAnimationFrame( animate );
            render();
        }

        function render() {
            // var timer = Date.now() * 0.0005;
            self.renderer.render( self.scene, self.camera );

        }
        animate();
    }

    return modelViewer;
}]);

所以基本上它的工作原理是有多个可能的画布(取决于 canvas_selector),但只有一个活动画布,因为旧的画布/场景/渲染器/等......每次启动新模型时都会被销毁(因此 self.destroy_old 在 init 函数的开头)。

如果我在创建新场景之前等待对象加载,它会按预期工作,因此当启动新场景时,场景中只会出现一个部分。但是,如果启动一个场景,然后在旧场景仍在加载该部分时启动另一个场景,则新场景将同时加载到新部分和旧部分中。尽管在创建新的之前将 loader、loadermanager 和 part 设置为 null,但仍会发生这种情况。

那么有谁知道如何阻止加载器在加载时将文件加载到场景中?

我在文档中找不到任何似乎是加载器或 STLLoader(继承加载器)原生的函数。

【问题讨论】:

    标签: javascript angularjs three.js


    【解决方案1】:

    现在只是为了更新任何人,拉取请求已被合并,您实际上可以从 onprogress 回调中取消。

    var loader = new THREE.STLLoader();
    
    loader.load('test.stl', function ( geometry ) {
        //stuff here
    }, function(url) {
        //logic here
        url.currentTarget.abort()
    }) ;   
    

    【讨论】:

      【解决方案2】:

      好的,所以我不得不对three.js 和STLLoader 文件进行一些(非常简单的)更改,我从这里cancel download jsonLoader & ImageUtils.loadTexture 得到了这个想法。无论如何,这是我自己的解决方案:

      在 three.js 中,我必须对 THREE.XHRLoader 进行以下更改:

      THREE.XHRLoader.prototype = {
      
          constructor: THREE.XHRLoader,
      
          load: function ( url, onLoad, onProgress, onError ) {
      
              ...
      
              var request = new XMLHttpRequest();
      
              ...
      
              scope.manager.itemStart( url );
      
              return request; // I ADDED THIS
      
          },
          ...
      
      };
      

      然后我在 STLLoader.js 中添加了:

      THREE.STLLoader.prototype = {
      
      constructor: THREE.STLLoader,
      
      load: function ( url, onLoad, onProgress, onError ) {
      
          var scope = this;
      
          var loader = new THREE.XHRLoader( scope.manager );
          loader.setCrossOrigin( this.crossOrigin );
          loader.setResponseType('arraybuffer');
      
          // Here I added request to equal loader since i made load return the original xmlhttprequest
          var request = loader.load( url, function ( text ) {
      
              onLoad( scope.parse( text ) );
      
          }, onProgress, onError );
      
          // here I return the request further back to my own application
          return request;
      
      },
      

      最后在我自己的代码中:

      var modelViewer = {
          request: {},
          ...
      }
      
      modelViewer.destroy_old = function(canvas_selector){
          if (!$.isEmptyObject(this.request)){
              this.request.abort();
          }
          ...
      }
      
      modelViewer.init = function(part, canvas_selector){
          ...
          function loadModel(url){
              ...
              self.request = self.loader.load(url, function(geometry){
              ...
              }
          }
      }
      

      【讨论】:

      • 我已经为threejs创建了一个拉取请求,以便加载器默认返回request对象。因此,它有望在 ThreeJs 的下一个版本中可供所有人使用,任何想要此功能的人都不必编辑 three.js 文件。 link to related issue
      猜你喜欢
      • 2015-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-12
      • 1970-01-01
      • 1970-01-01
      • 2020-08-29
      • 2016-02-03
      相关资源
      最近更新 更多