Faking 3D in creative coding

1,645 reads

Building a 3D Starfield effect on the canvas in Javascript

We’ll be building this hyperspace star effect

I had a few requests to show how to build on the Math.sin() and Math.cos() examples from the previous article, to do something similar in 3D. But before we can get there, let’s get the basics covered in faking 3D.

Creating fake 3D on the canvas is pretty easy once you know how it works. We’ll start small and build on the tricks we learn.

The basic trick is to scale our objects to simulate the z-axis view, we use a field of view angle, which is simple the width of the angle of view. The wider the angle, the more 3D distortion you get. And the formula is:

scale = FOV/(z+FOV);

So let’s make a simple starfield to start…

Using our normal particle system code, we also need to give each particle a z-value, a z-speed, a scale value and a 3D x-value and a 3D y-value. We don’t need a x-speed or a y-speed as we’ll just be moving our particles forward.

function addParticle(){

var particle = {

x: random(-100,100),

y: random(-100,100),

z: 10,

x3d: 0,

y3d: 0,

scale: 1,

speed_z: 4

}

particles.push(particle);

}

We’ll then calculate our 3D positions, based on our formula. Note we subtract our z-position to move the balls forward and use our scale to calculate our new 3D x and y-positions:

function moveParticles(){

for (var i = 0; i < particles.length; i++) {

var p = particles[i];

p.z -= p.speed_z;

p.scale = fov/(p.z+FOV);

p.x3d = p.x * p.scale;

p.y3d = p.y * p.scale;

}

}

And you should be getting something like this:

So one thing you’ll notice is the particles eventually start moving backwards. Easy enough to fix, just check if they’ve reached past their negative FOV, remove them.

And the only other thing is to add a semi transparent background to get a trail effect.

The full code, to get the effect on the article header, will look like this:

var ctx = createCanvas("canvas1");

var particles = [];

var FOV = 250;

function addParticle(){

var particle = {

x: random(-100,100),

y: random(-100,100),

z: 10,

x3d: 0,

y3d: 0,

speed_z: 2,

scale: 1,

colour: rgb(0),

}

particles.push(particle);

}

function draw(){

ctx.background(0, 0.2);

addParticle();

moveParticles();

drawParticles();

}





function moveParticles(){

for (var i = 0; i < particles.length; i++) {

var p = particles[i];

p.z -= p.speed_z;

p.scale = FOV/(p.z+FOV);

p.x3d = p.x * p.scale;

p.y3d = p.y * p.scale;

if (p.z < -FOV) {

particles.splice(i,1);

}

}

}



function drawParticles(){

ctx.save();

ctx.translate(w/2, h/2);

for (var i = 0; i < particles.length; i++) {

var p = particles[i];

ctx.fillStyle = rgb(255);

ctx.fillEllipse(p.x3d, p.y3d, p.scale, p.scale);

}

ctx.restore();

}

And that’s it. We’re done. Happy coding.

As usual the full code is available on my github, this article is part 9 (be sure to do a pull every now and then, because I’m updating things often): https://github.com/GeorgeGally/creative_coding

Follow me on Instagram here: https://www.instagram.com/radarboy3000/

Follow me on Twitter here: https://twitter.com/radarboy_japan

And like my Facebook Page here: https://www.facebook.com/radarboy3000

Tags