ThreeJS:从场景中删除对象

时间:2013-08-21 12:32:50

标签: javascript three.js

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

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在{{1}}内工作得很好。但我仍然无法弄清楚如何在removeEntity(object)中使用它。

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

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

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

感谢。 :)

11 个答案:

答案 0 :(得分:41)

我认为看到你对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 Scene中的name。希望有所帮助

答案 1 :(得分:11)

clearScene: function() {
    var objsToRemove = _.rest(scene.children, 1);
    _.each(objsToRemove, function( object ) {
          scene.remove(object);
    });
},

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

此外,您不是按名称删除对象,只是按对象本身删除,因此调用

scene.remove(object); 

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

PS:_.eachunderscore.js

的函数

答案 2 :(得分:3)

这项工作很棒 - 我测试了它 所以,请为每个对象设置名称

在创建时为对象命名

    mesh.name = 'nameMeshObject';

并在必须删除对象时使用此

    delete3DOBJ('nameMeshObject');



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

打开一个新场景,添加对象 open new scene , add object

删除对象并创建新对象 delete object and create new

答案 3 :(得分: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); 

}

答案 4 :(得分:1)

我遇到了和你一样的问题。我尝试这个代码,它的工作正常: 在创建对象时,将此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在添加到场景后无法识别该对象。但有了这个技巧,它就可以了。

答案 5 :(得分:1)

如果你的元素没有直接在你的场景上,请回到Parent删除它

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

答案 6 :(得分:1)

我开始将其保存为一个函数,并根据需要对其进行调用:

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

现在可以调用Remove()了;适当的功能。

答案 7 :(得分:1)

this 示例可能会给你一个不同的方法。我试图在我的项目中也使用 scene.remove(mesh) 实现类似的功能。然而,网格的几何和材料属性的处理对我有用! source

答案 8 :(得分: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;
}

答案 9 :(得分:0)

我来晚了,但在阅读了答案后,需要进一步澄清。

你写的删除函数

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
    object.geometry.dispose();
    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();
    }
    object.removeFromParent(); // the parent might be the scene or another Object3D, but it is sure to be removed this way
    return true;
}

答案 10 :(得分:-8)

您可以使用此

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
  }