最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Three.js won't render the scene after clearing it - Stack Overflow

programmeradmin6浏览0评论

I haven't found any post that describes exactly this issue but I've noticed it's kinda hard to delete elements from the scene.

I'm making a house editor, it allows to draw a 2D house and then it generates a 3d version.

If I use the next line or scene.clear() to clear the scene, it won´t render anything else afterwards:

build(layers) {
        let height = 0;

       this.scene.remove.apply(this.scene, this.scene.children);

        layers.forEach(layer => {
            for (let y = 0; y < GRID_SIZE; y++) {
                for (let x = 0; x < GRID_SIZE; x++) {
                    if (layer.grid[y][x] != null) {
                        this.scene.add(layer.grid[y][x].get3DVersion(x, y, height));
                    }
                }
            }
            height += layer.getTotalHeight();
        });        
    }

However, if I empty the scene like this, it continues rendering the scene but it won't remove all the elements that were deleted in the grid properlty, I have to call build(layers) several times for all of them to be gone:

 this.scene.children.forEach((child) => {
             if (child.isMesh && child !== this.plane) {
                 this.scene.remove(child);
                 child.geometry.dispose(); 
                 child.material.dispose(); 
             }
         });

This is all my Three.js related code:

class HouseBuilder {
    constructor() {
        const section = document.getElementById("threeSection");

        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(30, 400 / 300, 0.1, 5000);
        this.camera.position.set(25, 25, 50);
        this.camera.lookAt(0, 0, 2.5);

        this.renderer = new THREE.WebGLRenderer();
        this.renderer.setSize(400, 300);
        section.appendChild(this.renderer.domElement);

        const ambientLight = new THREE.AmbientLight(0x404040);
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        this.scene.add(ambientLight);
        directionalLight.position.set(5, 10, 5);
        this.scene.add(directionalLight);

        this.addFloor();
        this.animate();
    }

    addFloor() {
        const geometry = new THREE.PlaneGeometry(GRID_SIZE + 5, GRID_SIZE + 5);
        const material = new THREE.MeshStandardMaterial({ color: 0x228b22, side: THREE.DoubleSide });
        this.plane = new THREE.Mesh(geometry, material);
        this.plane.rotation.x = -Math.PI / 2;
        this.scene.add(this.plane);
    }

    animate() {
        requestAnimationFrame(() => this.animate());
        this.renderer.render(this.scene, this.camera);
    }

    build(layers) {
        let height = 0;

        // this.scene.children.forEach((child) => {
        //     if (child.isMesh && child !== this.plane) {
        //         this.scene.remove(child);
        //         child.geometry.dispose(); 
        //         child.material.dispose(); 
        //     }
        // });

       this.scene.remove.apply(this.scene, this.scene.children);

        layers.forEach(layer => {
            for (let y = 0; y < GRID_SIZE; y++) {
                for (let x = 0; x < GRID_SIZE; x++) {
                    if (layer.grid[y][x] != null) {
                        this.scene.add(layer.grid[y][x].get3DVersion(x, y, height));
                    }
                }
            }
            height += layer.getTotalHeight();
        });        
    }
}

I haven't found any post that describes exactly this issue but I've noticed it's kinda hard to delete elements from the scene.

I'm making a house editor, it allows to draw a 2D house and then it generates a 3d version.

If I use the next line or scene.clear() to clear the scene, it won´t render anything else afterwards:

build(layers) {
        let height = 0;

       this.scene.remove.apply(this.scene, this.scene.children);

        layers.forEach(layer => {
            for (let y = 0; y < GRID_SIZE; y++) {
                for (let x = 0; x < GRID_SIZE; x++) {
                    if (layer.grid[y][x] != null) {
                        this.scene.add(layer.grid[y][x].get3DVersion(x, y, height));
                    }
                }
            }
            height += layer.getTotalHeight();
        });        
    }

However, if I empty the scene like this, it continues rendering the scene but it won't remove all the elements that were deleted in the grid properlty, I have to call build(layers) several times for all of them to be gone:

 this.scene.children.forEach((child) => {
             if (child.isMesh && child !== this.plane) {
                 this.scene.remove(child);
                 child.geometry.dispose(); 
                 child.material.dispose(); 
             }
         });

This is all my Three.js related code:

class HouseBuilder {
    constructor() {
        const section = document.getElementById("threeSection");

        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(30, 400 / 300, 0.1, 5000);
        this.camera.position.set(25, 25, 50);
        this.camera.lookAt(0, 0, 2.5);

        this.renderer = new THREE.WebGLRenderer();
        this.renderer.setSize(400, 300);
        section.appendChild(this.renderer.domElement);

        const ambientLight = new THREE.AmbientLight(0x404040);
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        this.scene.add(ambientLight);
        directionalLight.position.set(5, 10, 5);
        this.scene.add(directionalLight);

        this.addFloor();
        this.animate();
    }

    addFloor() {
        const geometry = new THREE.PlaneGeometry(GRID_SIZE + 5, GRID_SIZE + 5);
        const material = new THREE.MeshStandardMaterial({ color: 0x228b22, side: THREE.DoubleSide });
        this.plane = new THREE.Mesh(geometry, material);
        this.plane.rotation.x = -Math.PI / 2;
        this.scene.add(this.plane);
    }

    animate() {
        requestAnimationFrame(() => this.animate());
        this.renderer.render(this.scene, this.camera);
    }

    build(layers) {
        let height = 0;

        // this.scene.children.forEach((child) => {
        //     if (child.isMesh && child !== this.plane) {
        //         this.scene.remove(child);
        //         child.geometry.dispose(); 
        //         child.material.dispose(); 
        //     }
        // });

       this.scene.remove.apply(this.scene, this.scene.children);

        layers.forEach(layer => {
            for (let y = 0; y < GRID_SIZE; y++) {
                for (let x = 0; x < GRID_SIZE; x++) {
                    if (layer.grid[y][x] != null) {
                        this.scene.add(layer.grid[y][x].get3DVersion(x, y, height));
                    }
                }
            }
            height += layer.getTotalHeight();
        });        
    }
}

Share Improve this question edited Mar 26 at 12:55 Carmen Sirgo López asked Mar 26 at 12:54 Carmen Sirgo LópezCarmen Sirgo López 213 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

As @Don McCurdy said, the problem was due to modifying an array while iterating over it. Here's the solution:

const objectsToRemove = this.scene.children.filter((child) => child !== this.plane);

    for (const child of objectsToRemove) {
        if (child.isMesh && child !== this.plane) {
            this.scene.remove(child);
            child.geometry.dispose();
            child.material.dispose();
        }
    }
发布评论

评论列表(0)

  1. 暂无评论