59

我正在使用 ThreeJS 开发一个显示实体列表的 Web 应用程序,每个实体都有相应的“查看”和“隐藏”按钮;例如entityName View Hide。当用户单击查看按钮时,将调用以下函数并成功在屏幕上绘制实体。

function loadOBJFile(objFile){            
    /* material of OBJ model */                                          
    var OBJMaterial = new THREE.MeshPhongMaterial({color: 0x8888ff});
    var loader = new THREE.OBJLoader();
    loader.load(objFile, function (object){
        object.traverse (function (child){
            if (child instanceof THREE.Mesh) {
                child.material = OBJMaterial;
            }
        });
        object.position.y = 0.1;
        scene.add(object);
    });     
}

function addEntity(object) {
    loadOBJFile(object.name);
}

在单击隐藏按钮时,将调用以下函数:

function removeEntity(object){
    scene.remove(object.name);
}

问题是,当点击隐藏按钮时,实体不会从屏幕中删除。我该怎么做才能使隐藏按钮起作用?

我做了一个小实验。我在函数内添加scene.remove(object.name);scene.add(object);结果addEntity,当单击“查看”按钮时,没有绘制实体(如预期的那样),这意味着scene.remove(object.name);addEntity. 但我仍然无法弄清楚如何在 removeEntity(object) 中使用它。

另外,我检查了 scene.children 的内容,它显示:[object Object]、[object Object]、[object Object]、[object Object]、[object Object]、[object Object]

完整代码:http ://devplace.in/~harman/model_display1.php.html

请询问,如果需要更多详细信息。我用 ThreeJS 的 rev-59-dev 和 rev-60 进行了测试。

谢谢。:)

4

12 回答 12

55

我认为查看您对 addEntity 和 removeEntity 代码的使用会有所帮助,但我的第一个想法是您实际上是在设置 object.name 吗?在 scene.add(object); 之前尝试在你的加载器中 像这样的东西:

object.name = "test_name";
scene.add(object);

可能发生的情况是 Object3D 的默认“名称”是“”,因此当您调用 removeEntity 函数时,由于场景对象名称为“”,它会失败

另外,我注意到您将 object.name 传递给您的加载程序?这是您将 URL 存储到资源的地方吗?如果是这样,我建议使用 Object3D 的内置 .userData 方法来存储该信息并保留名称字段以用于场景识别。

编辑:对新添加的代码的响应

首先要注意的是,在您的对象名称中包含“/”并不是一个好主意,它似乎工作正常,但您永远不知道某些算法是否会决定转义该字符串并破坏您的项目。

第二项是现在我已经看到了您的代码,它实际上是直截了当的。您的删除功能正在尝试按名称删除,您需要一个 Object3D 来删除。尝试这个:

function removeEntity(object) {
    var selectedObject = scene.getObjectByName(object.name);
    scene.remove( selectedObject );
    animate();
}

在这里你看到我通过传入你的对象标签的属性Object3D在 Three.js 中查找你的。希望有帮助Scenename

于 2013-08-21T15:12:27.727 回答
10
clearScene: function() {
    var objsToRemove = _.rest(scene.children, 1);
    _.each(objsToRemove, function( object ) {
          scene.remove(object);
    });
},

这使用 undecore.js 迭代场景中的所有子项(第一个除外)(这是我用来清除场景的代码的一部分)。只需确保在删除后至少渲染一次场景,否则画布不会改变!不需要“特殊” obj 标志或类似的东西。

此外,您不会按名称删除对象,而只是按对象本身,所以调用

scene.remove(object); 

而不是scene.remove(object.name); 就足够了

PS:_.eachunderscore.js的一个函数

于 2013-12-24T01:34:19.797 回答
4

这很好用 - 我测试过,请为每个对象设置名称

在创建时为对象命名

    mesh.name = 'nameMeshObject';

如果您必须删除一个对象,请使用它

    delete3DOBJ('nameMeshObject');



    function delete3DOBJ(objName){
        var selectedObject = scene.getObjectByName(objName);
        scene.remove( selectedObject );
        animate();
    }

打开一个新场景,添加对象 打开新场景,添加对象

删除对象并创建新对象 删除对象并创建新对象

于 2017-05-17T12:42:39.467 回答
4

我来晚了,但在阅读了答案后,需要说更多的澄清。

你写的删除函数

function removeEntity(object) {
    // scene.remove(); it expects as a parameter a THREE.Object3D and not a string
    scene.remove(object.name); // you are giving it a string => it will not remove the object
}

从 Three.js 场景中移除 3D 对象的好习惯

function removeObject3D(object3D) {
    if (!(object3D instanceof THREE.Object3D)) return false;

    // for better memory management and performance
    object3D.geometry.dispose();
    if (object3D.material instanceof Array) {
        // for better memory management and performance
        object3D.material.forEach(material => material.dispose());
    } else {
        // for better memory management and performance
        object3D.material.dispose();
    }
    object3D.removeFromParent(); // the parent might be the scene or another Object3D, but it is sure to be removed this way
    return true;
}
于 2021-06-16T14:13:39.973 回答
4

如果您的元素不直接在您的场景中,请返回父级将其删除

  function removeEntity(object) {
        var selectedObject = scene.getObjectByName(object.name);
        selectedObject.parent.remove( selectedObject );
    }
于 2017-05-14T23:00:19.000 回答
2

我开始将它保存为一个函数,并根据需要在需要它的任何反应时调用它:

function Remove(){
    while(scene.children.length > 0){ 
    scene.remove(scene.children[0]); 
}
}

现在你可以调用 Remove(); 在适当的地方发挥作用。

于 2019-02-19T20:42:54.010 回答
2

当你使用:scene.remove(object); 物体已从场景中移除,但与它的碰撞仍处于启用状态!

要删除与对象的碰撞,您可以使用它(用于数组): objectsArray.splice(i, 1);

例子 :

for (var i = 0; i < objectsArray.length; i++) {
//::: each object ::://
var object = objectsArray[i]; 
//::: remove all objects from the scene ::://
scene.remove(object); 
//::: remove all objects from the array ::://
objectsArray.splice(i, 1); 

}

于 2020-03-08T17:45:38.183 回答
1

这个例子可能会给你一个不同的方法。我试图在我的项目中也使用scene.remove(mesh). 但是网格的几何形状和材质属性的处理对我有用! 资源

于 2021-03-30T08:48:51.020 回答
1

我改进了 removeObject3D 的 Ibrahim 代码,添加了一些几何或材料检查

removeObject3D(object) {
    if (!(object instanceof THREE.Object3D)) return false;
    // for better memory management and performance
    if (object.geometry) {
        object.geometry.dispose();
    }
    if (object.material) {
        if (object.material instanceof Array) {
            // for better memory management and performance
            object.material.forEach(material => material.dispose());
        } else {
            // for better memory management and performance
            object.material.dispose();
        }
    }
    if (object.parent) {
        object.parent.remove(object);
    }
    // the parent might be the scene or another Object3D, but it is sure to be removed this way
    return true;
}
于 2021-07-14T14:49:28.483 回答
1

使用 scene.remove(Object) 要从场景中移除的对象

于 2021-12-07T13:49:03.120 回答
0

我有和你一样的问题。我尝试了这段代码,它工作得很好:当你创建你的对象时,把这个 object.is_ob = true

function loadOBJFile(objFile){            
    /* material of OBJ model */                                          
    var OBJMaterial = new THREE.MeshPhongMaterial({color: 0x8888ff});
    var loader = new THREE.OBJLoader();
    loader.load(objFile, function (object){
        object.traverse (function (child){
            if (child instanceof THREE.Mesh) {
                child.material = OBJMaterial;
            }
        });
        object.position.y = 0.1;
      // add this code
        object.is_ob = true;

        scene.add(object);
    });     
}

function addEntity(object) {
    loadOBJFile(object.name);
}

然后你删除你的对象试试这个代码:

function removeEntity(object){
    var obj, i;
            for ( i = scene.children.length - 1; i >= 0 ; i -- ) {
                obj = scene.children[ i ];
                if ( obj.is_ob) {
                    scene.remove(obj);

                }
            }
}

试试看,告诉我是否可行,似乎三个js在添加到场景后无法识别对象。但是有了这个技巧,它就起作用了。

于 2013-09-09T01:19:51.337 回答
-9

你可以用这个

function removeEntity(object) {
    var scene = document.querySelectorAll("scene");                               //clear the objects from the scene
    for (var i = 0; i < scene.length; i++) {                                    //loop through to get all object in the scene
    var scene =document.getElementById("scene");                                  
    scene.removeChild(scene.childNodes[0]);                                        //remove all specified objects
  }   
于 2013-09-21T09:03:59.747 回答