【问题标题】:How can I load only one model at a time in three.js?如何在three.js中一次只加载一个模型?
【发布时间】:2017-04-15 00:07:41
【问题描述】:

我正在开发一个将项目添加到 three.js 场景的程序,根据场景中已经存在的项目数量将它们定位在坐标上。目前,我遇到的问题是,当用户选择“高空工作”时,场景中会添加两个人。这是两个独立的函数调用,但是当场景结束时,两个人都在同一个坐标上。当用户点击添加多人并且不等待每个人加载时也会发生这种情况。

有没有办法强制我的加载函数等待第一个对象完成加载,以便一次只加载一个模型?

This mention of the LoadingManager 让我开始思考,并尝试通过将加载的文件数和总数保存为变量来使用它,然后在 while 循环中比较它们,但是,正如预期的那样,这只会减慢脚本的速度,以至于我的浏览器要我阻止它们。

// adds objects to the basket with the appropriate rotation
      function createObjectBasket(filePath, scale, position, name, type) {
        // Load in the object and add it to the scene.
        var loader = new THREE.ObjectLoader(manager);
        /*while (gl_itemsLoaded < gl_itemsTotal) {
          
        }*/
        loader.load( filePath, function(object, materials){
          
          // rotate
          object.rotation.x = - ((Math.PI / 2) - (Math.PI / 18));
          object.rotation.y = - (Math.PI - (Math.PI / 5));
          object.rotation.z = 0; //- (Math.PI / 120);
          
          // scale
          object.scale.set(scale, scale, scale);
          
          // translate
          object.position.set(position.x, position.y, position.z);
          
          // set name for easy access
          object.name = name;
          
          // add to scene
          scene.add(object);
          
          if (type == "basket") {
            // add to object array for easy access
            basketContents["basket"].push(object);
          }
          else if (type == "person") {
            // add to object array for easy access
            basketContents["people"].push(object);
          }
          else if (type == "tool") {
            // add to object array for easy access
            basketContents["tools"].push(object);
          }
          else if (type == "attachment") {
            // add to object array for easy access
            basketContents["attachments"].push(object);
          }
        });
      }

如果我遇到问题,则通过以下两行(间接)调用此代码:

objectAddRemove("person", "CWM_A");
objectAddRemove("person", "CWM_B");

然后执行这个调用 createObjectBasket 的函数:

      // add/remove objects to/from basket on click
      function objectAddRemove(type, objectName) {
        // if adding items
        if (addRemove == "add") {
          
          // determine if there is still room to add more objects
          var room = true;
          // can have <= 3 people total, so if there are 3, can't add more
          if ((type == "person") && basketContents["people"].length >= 3) {
            room = false;
            return;
          }
          // no current restrictions on tools
          /*else if ((type == "tool")) {
            
          }*/
          // can only have 1 of each attachment
          else if ((type == "attachment") && (object[objectName]["contentsCount"] > 0)) {
            room = false;
            return;
          }
          
          if (room == true) {
            // if it's a person
            if (type == "person") {
              // if it's a man
              if (objectName.indexOf("M") >= 0) {
                // add model
                createObjectBasket(("models/" + objectName + ".json"), 1.5, personCoordsMan[basketContents["people"].length + 1], objectName, "person");
              }
              // if it's a woman
              else {
                // add model
                createObjectBasket(("models/" + objectName + ".json"), 1.5, personCoordsWoman[basketContents["people"].length + 1], objectName, "person");
              }
            }
            // if it's a tool
            else if (type == "tool") {
              /*createObjectBasket(("models/" + objectName + ".json"), 1.5, toolCoords[basketContents["tools"].length + 1], objectName, "tool");*/
              createObjectBasket(("models/" + objectName + ".json"), 1.5, toolCoords, objectName, "tool");
            }
            // if it's an attachment
            else if (type == "attachment") {
              createObjectBasket(("models/" + objectName + ".json"), .04, attachmentCoords[objectName], objectName, "attachment");
            }

            // increase count
            object[objectName]["contentsCount"] += 1;
            console.log(objectName);

            $('#' + objectName).children('.status').children('.checkMark').show();
          }
        }
        
        // if removing items
        else if (addRemove == "remove") {
          
          // remove objects from arrays
          if (type == "person") {
            removeObjectArray("people", objectName);
            
            // if person is found (and removed), rearrange all people to accommodate
            if (itemFound == true) {
              for (i = 0; i < basketContents["people"].length; ++i) {
                if (basketContents["people"][i].name.indexOf("M") >= 0) {
                  basketContents["people"][i].position.set(personCoordsMan[i+1].x, personCoordsMan[i+1].y, personCoordsMan[i+1].z);
                }
                else {
                  basketContents["people"][i].position.set(personCoordsWoman[i+1].x, personCoordsWoman[i+1].y, personCoordsWoman[i+1].z);
                }
              }
            }
          }
          else if (type == "tool") {
            removeObjectArray("tools", objectName);
            
            // if tool is found (and removed), rearrange all tools to accommodate
            /*if (itemFound == true) {
              
            }*/
          }
          else if (type == "attachment") {
            removeObjectArray("attachments", objectName);
          }
          
          // if all objects of that id have been removed, hide remove x mark
          if (object[objectName]["contentsCount"] <= 0) {
            $('#' + objectName).children('.status').children('.xMark').hide();
          }
          
          // if, after removing, person/object count is now 0, no remaining items can be removed, so switch to add
          if ((steps[currentStep] == "people") && (basketContents["people"].length <= 0)) {
            addItems();
          }
          else if ((steps[currentStep] == "objects") && ((basketContents["tools"].length + basketContents["attachments"].length) <= 0)) {
            addItems();
          }
        }
        // if no remaining items can be removed on this page
        else {
          addItems();
        }
      }

objectAddRemove 也会在用户单击代表所需对象的图像时被调用,因此我需要一种方法来等待先前单击的模型加载(除了通过代码自动加载的模型之外)。

要测试/查看更多代码,您可以访问this link。选择“高空作业”、重量单位,然后跳至“添加操作员”。它将显示篮子里有两个人(选中),但篮子里只有一个人可见。如果你点击“删除项目”然后可见的人删除可见的人,隐藏的将显示。

非常感谢!!!

【问题讨论】:

  • 谢谢@Andy Ray,但我想我是这样调用函数的。我正在调用 objectAddRemove("person", "CWM_A"); objectAddRemove(“人”,“CWM_B”);。 objectAddRemove 使用上面列出的函数 (createObjectBasket) 创建一个对象。根据您给我的链接,这意味着功能应该同步运行吗?那么第二个调用不应该在第一个调用完成之前执行?除非我读错了。
  • 没有。异步函数不会阻塞程序流。所有顶级语句按顺序执行,然后在稍后执行异步回调函数。

标签: javascript jquery three.js


【解决方案1】:

加载外部数据几乎总是异步进行,因此确保一个模型一个接一个地加载需要处理 onLoad 事件。

我不确定 LoadingManager 是否支持一个接一个地加载模型。

但是您可以自己实现一个简单的加载队列。类似的东西:

var myQueue = ['model1.dae', 'model2.dae'];

function loadFromQueue()
{
    if (myQueue.length == 0) return;

    // Takes the first name from array and remove it from the array
    var name = myQueue.shift(); 

    // Call the loader and provide an onLoad event handler
    loader.load(name, function(model){

         // Do what you need to do with the model,
         // usually it's scene.add(model) and some transformations.

         // Call the next item in the queue
         loadFromQueue();
    });
}

现在这是一个非常粗略的队列,有更好的方法可以做到这一点。但我用它来演示如何使用 onLoad 事件处理程序一个接一个地加载模型。

我认为您将遇到的下一个障碍将是如何将一些值传递给事件处理程序。那就回来吧!

【讨论】:

  • 谢谢@Matey,这真的很有帮助!!!我采用了这种方法并尝试将所有内容切换为从队列中加载(获取我需要的数据没有问题),但我遇到了问题。我的代码需要以 2 种方式加载模型 - 一些是由程序自动添加的(在这种情况下,您提供的解决方案很棒!),而另一些是在用户单击对象的拇指时加载的。如果用户快速连续单击两次,则模型会彼此重叠加载。在等待上一个模型时,我想不出任何方法可以添加到队列中并在点击时加载。想法?
  • 那么你应该添加一个计时器检查,如果它发生在计时器间隔内,则丢弃第二次点击。
【解决方案2】:

感谢@Matey 的建议,我最终只是使用超时来防止对象彼此重叠显示。我希望避免这种情况,因为所需的时间可能因型号和环境而异,但这是唯一对点击有效的方法。加载队列还在加载模型,因为我已经冒着超时的风险,所以实现它比修复它更容易。

我使用the accepted answer here 为我的点击事件添加了超时,然后只为我添加的第二个人添加了超时:

objectAddRemove("person", "CWM_A");
// add second person on timeout so people don't appear on top of each other
setTimeout(function() {
  objectAddRemove("person", "CWM_B");
},

这是唯一一个自动添加对象需要一些延迟的地方,所以希望这样做。我只是有点担心它将如何在不同的机器上运行。

【讨论】:

  • 延迟多长时间?
  • 目前添加单个对象需要 1/2 秒,初始加载需要整整一秒,但仍在优化这些值。
【解决方案3】:

我实际上最终通过采用不同的方法解决了这个问题 - 我需要变量来跟踪对象,所以我根据变量值(快速设置)而不是数量来检查对象是否已加载three.js 对象(加载时间更长)。与使用超时相比,这在整个系统中效果更好,并且更可靠。

【讨论】:

    猜你喜欢
    • 2023-03-18
    • 2016-12-23
    • 1970-01-01
    • 2021-12-05
    • 2012-05-21
    • 2022-09-30
    • 2017-01-28
    • 1970-01-01
    • 2018-08-16
    相关资源
    最近更新 更多