Deleting then recreating elements on each frame

Hello !

I’m currently working on a 3D version of John Conway’s life game on three.js.

Here’s the code I’ve done so far:

import * as THREE from 'three';

const scene = new THREE.Scene();

const createCube = (newCube, scene) => {
    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
    const cube = new THREE.Mesh( geometry, material );
    cube.position.set(newCube.x, newCube.y, newCube.z);
    scene.add( cube );
}

const deleteCubes = (scene) => {
    return new Promise((resolve) => {
        while (scene.children.length > 0) {
            scene.remove(scene.children[0]);
        }
        resolve();
    });
} 

const updateDisplay = async (cubes, scene) => {
    // clear
    await deleteCubes(scene)

    // create cubes
    cubes.map((cube) => createCube(cube, scene));

    // replacing lights
    scene.add(new THREE.AmbientLight(0xffffff, .5))
    const dir = new THREE.DirectionalLight(0xff0000, 1)
    dir.position.set(-1, 1, 1)
    scene.add(dir)

    console.log(scene.children)
}

const isEqual = (a, b) => a.x === b.x && a.y === b.y && a.z === b.z;
const offsets = [-1, 0, 1];
const lookNeighbors = (cube, cubes) => {
    // code that look to all the cubes around and counts the "living" ones
};

const generateNextCubes = (cubes) => {
    // code that generates the cube array to be displayed in the next frame 
}

let cubes = [
    {x:0, y:0, z:0}, 
    {x:0, y:0, z:1},
    {x:0, y:0, z:-1},
    {x:0, y:1, z:0},
    {x:0, y:1, z:1},
    {x:0, y:1, z:-1},
    {x:0, y:-1, z:1},
    {x:0, y:-1, z:-1},
    {x:0, y:-1, z:0},
] // initial situation

let nextCubes = []

const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

scene.add(new THREE.AmbientLight(0xffffff, .5))
const dir = new THREE.DirectionalLight(0xffffff, 1)
dir.position.set(-1, 1, 1)
scene.add(dir)

camera.position.z = 25;

let lastUpdateTime = 0;
const updateTimeInterval = 5000;
function animate(currentTime) {
    requestAnimationFrame(animate);

    const deltaTime = currentTime - lastUpdateTime;

    if (deltaTime >= updateTimeInterval) {
        lastUpdateTime = currentTime;

        updateDisplay(cubes, scene)

        nextCubes = generateNextCubes(cubes);
        cubes = nextCubes;

        renderer.render(scene, camera);

        console.log("frame");
    }
}

animate(0); 

I have a real problem with the way to erase the content of the 3D render. The basic idea is: at each “frame” of the animation, the scene content is erased and then recreated.

Currently there are 4 functions that seem important to me for this problem.

  • createCube(newCube, scene) takes a cube as parameter, creates it and adds it to the scene. I call it using cubes.map, cubes being an array of cubes (with coordinates).

  • deleteCubes(scene) deletes all children in the scene, i.e. all cubes and lights.

  • updateDisplay(cubes, scene) calls the first two functions, then recreates the lights.

  • animate() contains a deltaTime so that the animation generates a frame every 5 seconds. and calls updateDisplay before calculating the next frame.

When I run it in its current state, the canvas remains black and nothing is displayed. But if I comment on the deleteCubes in updateDisplay, then it works correctly, if we omit the fact that the cubes in the previous frames are not deleted.

My first thought was that the cube creation code ended before the delete function, which explains the use of a promise, but that wasn’t it. Then I realized that the delete function also deletes the lights, so I said to myself that I couldn’t see anything because there were no more lights, so I added the lights in updateDisplay and it’s still the same.

I don’t know what to do now, I can’t see what the problem is and I hope you can help me - thanks in advance!

imo this is inherently troubled and before you sink too much time into this consider this: The Big List of three.js Tips and Tricks! | Discover three.js , especially

Object creation in JavaScript is expensive, so don’t create objects in a loop.

Avoid adding and removing lights from your scene since this requires the WebGLRenderer to recompile all shader programs.

better look into instancing, this way you can render the whole scene in a single drawcall no matter how and where the cubes are placed. the lights, if i was you i wouldn’t add/remove them but use intensity 0/1.

1 Like

No, don’t do this, unless you want to punish your hardware.

It would be much better to do this:

  • when a cube is deleted, it is only made invisible and registered in a list of deleted cubes
  • when a cube must be created, take one from the list of deleted cubes (just remove it from the list, make it visible and move it to desired location), and only when this list is empty, then create a new cube
  • you do not need all those promises, asyncs and awaits
  • when a cube is created, do not create a new geometry and material for it, have one box geometry, one material … and reuse them for all cubes

When you are ready to explore larger boards with more cubes, you might consider instancing, as @drcmda mentioned. It will lead to a significant performance improvement, but you have to make some changes in the code.

As for the posted code, it is hard to guess what is the problem. It would be much better to create minimal live demo that can be debugged (CodePen, JSFiddle, CodeSandBox, etc).

As for the end of your post, I often reply with this link.