2 minute read

Final Live Code

Summary

WCCChallenge Blurb

Biz Biz Biz
Author Project Somedays
Title WCCChallenge 2025 Week 18 - Earth
📅 Started 2025-05-01
📅 Completed 2025-05-02
🕒 Taken ~4hrs
🤯 Concept A shattered voxel earth
🔎 Focus InstancedMesh/ThreeJS implementation of a Genuary p5js project

Made for Sableraph’s weekly creative coding challenges, reviewed weekly on https://www.twitch.tv/sableraph

See other submissions here: https://openprocessing.org/curation/78544

Join The Birb’s Nest Discord community! https://discord.gg/g5J6Ajx9Am

Resources

🎓Lessons Learned🎓

  • Using that dummy object to set up my biz
const geometry = new THREE.BoxGeometry(voxelSize, voxelSize, voxelSize);
    const material = new THREE.MeshStandardMaterial();
    
    voxelEarth = new THREE.InstancedMesh(geometry, material, resolution*resolution*resolution);
    scene.add(voxelEarth);
 
    for(let x = 0; x < resolution; x++){
        for(let y = 0; y < resolution; y++){
            for(let z = 0; z < resolution; z++){
                let index = z + y*resolution + x*resolution*resolution;
                let p = new THREE.Vector3(-span/2 + x * voxelSize, -span/2 + y*voxelSize, -span/2 + z*voxelSize);
                let normD = Math.sqrt(p.x*p.x + p.y*p.y + p.z*p.z)/(span/2);

                // update the position of each voxel
                dummy.position.set(p.x, p.y, p.z);

                // hide the voxels outside the bounds of the sphere
                dummy.scale.set(1,1,1); // dummy is being used everwhere, so by default, reset
                if(normD > 0.75 && normD < 0.85 || normD > 1) dummy.scale.set(0,0,0); // Put some space between earth and clouds
                dummy.updateMatrix();
                voxelEarth.setMatrixAt(index, dummy.matrix);

                // update the colour based on bands                 
                let col = getInstanceColor(normD);
                voxelEarth.setColorAt(index, col);
            }
        }
    }

    voxelEarth.instanceMatrix.needsUpdate = true;
    voxelEarth.instanceColor.needsUpdate = true;
  • Optimisation 2: cutting out a TON of the calculations by pre-computing starting positions
 for(let x = 0; x < resolution; x++){
        for(let y = 0; y < resolution; y++){
            for(let z = 0; z < resolution; z++){
                let position = new THREE.Vector3(-span/2 + x * voxelSize, -span/2 + y*voxelSize, -span/2 + z*voxelSize);
                let normD = Math.sqrt(position.x**2 + position.y**2 + position.z**2)/(span/2);
                if(isOutsideBounds(normD)) continue;
                startingPositions.push({p: position.clone(), col: getInstanceColor(normD), d: normD});
            }
        }
    }

Stretch Goals/Extension Ideas

  • Meteor strike 😲

TODO:

  • Make the globe
  • Colour mapping matrix
  • Grab simplex noise
  • Evolving 4D simplex noise with various thresholds at different bands
  • Map function
  • Increase gap between land and sky
  • Set noiseZoom differently for the clouds
  • Find the relevant ranges for biz
  • Optimise - ignore voxels that are outside our bounds
  • Optimise - use a lookup table rather than calculating normD over and over again - we really only need to do this once
  • Smooth-step the transitions

🪵Dev Log🪵

2025-05-01 8:00 - 9:30 Setting up the scene 🕒 1.5hrs

  • Worked out a couple of things about applying colours to instance mesh
  • Claude helped me with dummy.scale.set(1) before things

Basic scene setup

2025-05-01 20:30 - 22:00 🕒 1.5hrs

  • Claude helped me refactor to make the thresholds work better
  • lil-gui sliders
  • worked out a combination of settings I find pleasing
  • setting different noiseZoom for clouds
  • adjusted colour bands to make more mantle and a slighter transition from grey to white in the clouds

Getting closer

Closer still

Even closer still!

2025-05-02 21:00 - 21:30 🕒1hr

  • GREAT performance boost by a) cutting out calculating positions every time and b) dropping instances that are scaled to zero anyway.

Hooray! I think I'm done here!