I love doing 3d stuff. Especially if I can do it without using any sort of libraries or WebGL. The math behind it is very simple.

One of the most pleasing effects to the eye is Parallax scrolling. Basically, Parallax scrolling is the effect, where things in the foreground move slower than the ones in the background, creating a 3d like effect. It's been around since ages, but it didn't change very much since then.

The implementation is usually the same, you have multiple layers, each of them having something drawn at it, and you move the furthest layer slower than the closest one. This works well, until you want to add stuff inbetween layers. You can just add another layers, but then you would need to calibrate how fast each moves again, which can be frustrating after some time.

In this tutorial I want to cover how you can create a star field with flexible parallax scrolling by imitating 3d.

First we initialize the canvas and the functions we will be using.

HTML:

` ````
<canvas id="canvas"></canvas>
```

CSS:

` ````
canvas {
position: absolute;
top: 0;
left: 0;
}
```

JavaScript:

` ````
var c = document.getElementById("canvas");
c.width = innerWidth; // This 2 line sets the canvas so it takes up
c.height = innerHeight; // the full page
var ctx = c.getContext("2d");
function loop() {
update();
render();
requestAnimationFrame(loop);
}
// Here I use the so-called update-method design pattern
// More about this pattern can be found here: http://gameprogrammingpatterns.com/update-method.html
function update() {
// Updater code
}
function render() {
// Renderer code
}
loop();
```

I love 2d canvas, but I must admit, it has it's limitations. It's not terribly fast. Thus small animations like this too can run at a low framerate on some machines (like phones). If we don't sort this out, we get the same effect which happened to the original Sonic Game.

Fortunately, there's a really easy solution to this: Instead of working with per-frame speeds, we need to use per-second ones, and scale them down based on how many milliseconds has elapsed between the 2 drawing frames:

` ````
var lastFrame = Date.now(); // This will store the last frame's timestamp
// ...
function loop() {
// In an ideal world this value would be 0.0166666666.... second, because
// 1 / 60 = 0.0166666666
update((Date.now() - lastFrame) / 1000);
render();
requestAnimationFrame(loop);
}
function update(time) {
// ...
}
```

Then when we need to update something's position later, we will multiply it's speed/second with the time variable.

Our star will be a basic JavaScript object (just for simplicity). It will have 3 properties:

- x: The x position of the star
- y: The y position of the star
- depth: The layer the star is in (can be any number, both integer and float)

So, let's create an array of randomly placed stars:

` ````
var stars = [];
var starCount = 50; // The amount of stars on the screen
var starSize = 10; // The default size of the star
var maxDepth = 50; // The maximum depth of a star
var minDepth = 15; // The minimum depth of a star
for (var i = 0; i < starCount; i++) {
stars.push({
x: (Math.random() - 0.5) * c.width * 2,
y: (Math.random() - 0.5) * c.height * 2,
depth: Math.random() * (maxDepth - minDepth) + minDepth
});
}
```

We will be using a simple `ctx.fillRectangle(...)`

to draw the stars, because 1.) It's faster and 2.) It simply looks cool.

Now the hard part. How do we convert a position with a depth to 2 dimension? We could use projection matrices, write a function to multiply vectors and matrices together...

...or we can just divide with `depth / maxDepth`

. Because that apparently works (and also what projection matrices are based on).

` ````
function render() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.fillStyle = "white";
for (var i = 0; i < starCount; i++) {
var star = stars[i];
var proj = star.depth / maxDepth;
var pos = {
x: star.x / proj,
y: star.y / proj
}
var size = starSize / proj; // This'll be the size of the projected star
ctx.fillRect(pos.x - size / 2, pos.y - size / 2, size, size);
}
}
```

If you take the current code and start it, you'll see that it works now, but it's not really an ... animation.

Because we're already imitating 3d, we should create the animation by imitating the use of a camera. We only need to store the current position of the camera, then when we render the scene, we simply subtract it's position from the star's position:

` ````
var camera = {
x: 0,
y: 0
}
// I use a mouse-control, because it's the easiest one to implement, and looks
// great.
var mouse = {
x: 0,
y: 0
};
c.addEventListener("mousemove", function (e) {
mouse.x = e.clientX - c.width / 2,
mouse.y = e.clientY - c.height / 2
});
// ...
function update(time) {
camera.x += mouse.x * time;
camera.y += mouse.y * time;
}
function render() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.fillStyle = "white";
for (var i = 0; i < stars.length; i++) {
var star = stars[i];
var proj = 1 / star.depth * maxDepth;
var pos = {
x: (star.x - camera.x) / proj,
y: (star.y - camera.y) / proj
};
var size = starSize / proj;
ctx.fillRect(pos.x - size / 2, pos.y - size / 2, size, size);
}
}
```

And now if you try running it, it'll move to a direction depending on where your mouse pointer is at.

We have 1 problem though. Our star field is not infinite, and if you go in a direction, you quickly reach the end of it. To sort this out, we could either generate new stars when we need to have new ones, or make the current stars wrap around. We're going to implement the last one, because it's easier, and this tutorial is already very long.

To make the stars wrap around, we need to check when their projected position is off-screen, and if it is, we need to place it on the other side to make it visible. We also need to make it so they don't instantly get teleported, instead they need to go completely off the screen before.

After some fiddling, this is what I came up

` ````
var pos = {
x: ((star.x - camera.x) / proj + size / 2) % (c.width + size) - size / 2,
y: ((star.y - camera.y) / proj + size / 2) % (c.height + size) - size / 2
};
if (pos.x < -size / 2)
pos.x += c.width + size;
if (pos.y < -size / 2)
pos.y += c.height + size;
```

Yeah, it's kind of long. The last 2 if statements are necessary, because in most of the languages, the modulo operator returns a negative value for negative values, so `-10 % 20 = -10`

. So, when the position becomes negative, we just put it at the other end of the canvas.

There you are, a good looking star field demo. The method of creating 3d by dividing with depth/z is very useful. I use it in countless of my pens. If you have time, check some of them out.

]]>This library allows you to add a callback function to any native or non-native function by using a single function (with 3 argument options):

` ````
ListenJS.addListener(callback = function, func = function); // func is the function you want to listen to
ListenJS.addListener(callback = function, func = string, object = string)
ListenJS.addListener(callback = function, func = string, object = string, prototype = boolean)
```

The first is used when you want to listen to a function which lies on the global scope, the second when your function is inside a multilevel object, the third when you want to listen for a prototype of an object.

The options are explained more detailed in the github repo.

]]>In this post I will tell you how to create lightning effects like this.

The lightning is a set of lines which start from a set point (the top of the lightning) and go towards a random point (The end of the lightning). To make the lightning less straight I used a noise.

If you've ever worked with algorithms like the diamond-square algorithm, then the following part will be familiar for you. First I start off with a straight line from the top of the lightning to a randomly chosen point close to the bottom of the canvas.

Then I get the middle of the segment, I add a random value to the x position of it and I insert it between the start end end of the segment.

I do the above method to each segment of the lightning, then I repeat it again lowering the maximum of the random value each time I go trough the whole lightning, so the lightning doesn't look too rough. This makes the lightning have a well defined shape (To see what would happen if I leave out this step go to the pen and change the "roughness" variable to 1).

Here's a poorly drawn image about what's happening:

The beauty about this is that this noise function can be used for many different things, most notably for terrain generation.

So, if you want to implement this yourself you need to define some values:

- Roughness: This value determines how rough the lightning will be. Smaller values will give you rougher curves. You shouldn't go below 1.5.
- Minimum segment height: The algorithm will divide the segments until every segment's height is less than or equal to this value. This also tells the algorithm how detailed the curve should be.
- Max difference: The starting value for the random function. This is the maximum distance a point can differ from the middle point of the segment it sits on.

In my pen I used the following values for this 3 variable:

` ````
var roughness = 2;
var maxDifference = size / 5; // "size" is the width and height of the canvas.
var minSegmentHeight = 5;
```

Next, the actual algorithm. The segments are simply defined by 2 points.

` ````
// If you're using this in your projects, then I'd recommend creating a separate object for this.
function createLightning() {
// The main segment's height
var y = groundHeight + (Math.random() - 0.9) * 50;
var segmentHeight = y - center.y;
var lightning = [];
// The start and the end position of the lightning.
lightning.push({x: center.x, y: center.y});
lightning.push({x: Math.random() * (size - 100) + 50, y: y});
// This is important so we don't change the global one.
var currDiff = maxDifference;
while (segmentHeight > minSegmentHeight) {
// This uses the double buffering pattern
var newSegments = [];
for (var i = 0; i < lightning.length - 1; i++) {
// The start and the end position of the current segment
var start = lightning[i];
var end = lightning[i + 1];
// "midX" is the average X position of the segment
var midX = (start.x + end.x) / 2;
var newX = midX + (Math.random() * 2 - 1) * currDiff;
// Add the start and the middle point to the new segment list
// Because the end position is going to be added again in the next iteration
// we don't need to add that here.
newSegments.push(start, {x: newX, y: (start.y + end.y) / 2});
}
// Add the last point of the lightning to the segments.
newSegments.push(lightning.pop());
lightning = newSegments;
currDiff /= roughness;
segmentHeight /= 2;
}
return lightning;
}
```

The lightning are drawn using the canvas' path functions. The lightning's color is a shade of electrical blue (`hsl(180, 80%, 80%)`

).

Drawing the ligthning involves few tricks. The first is a well known one with a twist. By setting the clear color's opacity to 0.2 the older lightnings instead of disappearing completely they fade out slowly. I only draw 1 new lightning every frame, but it looks like there's always 20 at least on the screen.

This trick has a problem though. The canvas never gets cleared completely and you could see where older lightnings were. There's however a quick way to solve this. I set the fill style to the color of the lightnings and I fill the canvas. This way the background color changes and the lightnings won't stay there. To see what would happen if I leave out this try to comment out the 20th line.

The next trick involves setting the context's `globalCompositeOperation`

property to "lighter". This makes the parts where multiple lightnings are drawn whiter, like the start of the lightning. You probably didn't notice this but you would miss it if it wasn't there. Again, to see what happens without this feature, comment out the 27th line.

The last trick is the slight gloom effect around the lightnings. This is done by simply setting the context's `shadowColor`

property to the color of the lightning and the `shadowBlur`

property to 15. To turn it off, comment out the 28th line.

*Link: http://yourjavascript.com/01666321507/math-min.js*

Link to part 2: Link Link to part 3: Link

If you use Three.js, you probably came across with one of the many geometry object (they tend to end with "Geometry", like `TubeGeometry`

or `IcosahedronGeometry`

. They are quite easy to use, you just create a new icosahedron, add it to a scene, and boom, you have an icosahedron.

But most of us don't know how these objects actually work. This post series is intended to make things about these objects clearer.

Let's start with an easy one, a plane. A plane consists of 4 vertices (points in 3d space). These 4 vertices create 2 triangles. Why triangles instead of a quad? Most GPUs don't like quads, they can only draw triangles on the screen, and when you give them a quad, then they need to slice it up into two triangles. This is however not as effective as if you'd do it on the CPU.

So, how do we create a plane? We create 4 vertices and an index array. The index array is used to tell in which order the vertices need to be used.

The vertices:

` ````
var width = 1;
var height = 1;
var vertices = [];
var indices = [];
vertices.push(new Vector3(0, 0, 0));
vertices.push(new Vector3(width, 0, 0));
vertices.push(new Vector3(width, 0, height));
vertices.push(new Vector3(0, 0, height));
indices = [
0, 1, 3,
3, 1, 2
];
```

This creates the vertices and indices for a plane. In the code above I use an object called Vector. Vectors are a way to represent a position in 3 dimensional space.

Now all the vertices are in place. If you actually render them with whatever technique you like, then you get this (I added animation and perspective to make it neater):

Circles are made of triangles too. How many triangles it consists of defines how smooth the edges are.

To create the points, we need to use trigonometry. Each side of the polygon should create a triangle with the middle point

` ````
var vertices = [];
var indices = [];
var radius = 100;
var detail = 20;
// Middle vertex
vertices.push(new Vector3(0, 0, 0));
// Create vertices
for (var i = 0; i < detail; i++) {
var angle = 2 * Math.PI / detail * i;
var x = Math.cos(angle) * radius;
var y = Math.sin(angle) * radius;
vertices.push(new Vector3(x, 0, y));
}
// Loop trough each edge (there's detail-1 edge)
for (var i = 1; i < detail; i++) {
// Each index trio defines a triangle
// We connect a vertex with the next vertex on the circle and the middle
indices.push(i, i + 1, 0);
}
// Last triangle to close the shape off
indices.push(detail, 1, 0);
```

If everything is okay, then this should look like this (I set the detail to 20. If you use a higher value, like 150-200, then you won't notice the difference between this and a circle):

To rotate shapes around the origin (0,0,0) you need to use matrix transformations. Each vertex should be multiplied by the rotation matrix.

` ````
// Vertices defined above
var deg = Math.PI / 180; // 1 degree in radian
var angle = [45 * deg, 30 * deg, -20 * deg]; // 45 degree around the x, 30 around the y and -20 around the z axis
// Matrices
var rotX = Matrix3.rotate(angle[0], 1, 0, 0); // This is the usual way to create a rotation matrix.
var rotY = Matrix3.rotate(angle[1], 0, 1, 0); // The first argument is the angle, the next three are
var rotZ = Matrix3.rotate(angle[2], 0, 0, 1); // used to tell on wich axis you need to apply the rotation.
// The complete rotation matrix.
var rot = rotZ.multiplyMatrix(rotY.multiplyMatrix(rotX));
for (var i = 0; i < vertices.length; i++) {
vertices[i] = rot.multiplyVectior(vertices[i]);
}
```

]]>
*Link: http://yourjavascript.com/01666321507/math-min.js*

Link to part 1: Link Link to part 3: Link

Now that you know how you can create 2 dimensional object, let's learn how to create 3 dimensional ones.

A cube consists of 8 vertices, 12 edges and 6 faces. Each of these faces needs to be constructed from 2-2 triangles, this means we need to create 12 triangles, and that means 36 indices. Let's look at a wireframe cube.

The 8 corners are marked with A, B, C, D, E, F, G and H respectively.

Let's create the vertices for this cube:

` ````
var width = 100;
var height = 100;
var depth = 100;
var vertices = [
// First layer
vertices.push(new Vector3(0, 0, 0)), // A
vertices.push(new Vector3(width, 0, 0)), // B
vertices.push(new Vector3(width, 0, depth)), // C
vertices.push(new Vector3(0, 0, depth)), // D
// Second layer
vertices.push(new Vector3(0, height, 0)), // E
vertices.push(new Vector3(width, height, 0)), // F
vertices.push(new Vector3(width, height, depth)), // G
vertices.push(new Vector3(0, height, depth)) // H
];
```

Now that every vertex is in place, we need to create the indices. The faces of the cube are:

` ````
ADCB
HEFG
EABF
FBCG
GCDH
HDAE
```

The vertices' order do matter, because most rendering APIs (OpenGL, DirectX) are sensitive to the it. They determine the front and back of a face by the order of the vertices.

Now we can create the indices for every face separately as if it were a simple plane and not part of a cube. For the `ADCB`

face it would be `ADBBDC`

, so if we change every letter to numbers based on the

` ````
A: 0, B: 1, C: 2, ...
```

list, then we get `0, 1, 3, 3, 1, 2`

. This is the same pattern we used to create a plane.

If you create the indices for every side, then you will get

` ````
var indices = [
0, 3, 1, 1, 3, 2,
7, 4, 6, 6, 4, 5,
4, 0, 5, 5, 0, 1,
5, 1, 6, 6, 1, 2,
6, 2, 7, 7, 2, 3,
7, 3, 4, 4, 3, 0
];
```

And you have a cube. Now let's render it (I render only the wireframe of it, so you can see it more clearly):

Creating a tube is slightly harder than creating a cube, but it involves less hard coding the values.

To define a tube model, you need to have 4 values: A radius, a height, the amount segments the perimeter consists of and the amount of segments it consists of vertically.

If this is not clear to you, then look at the following image:

.

So, how de we create a tube? We can easily create the vertices by using trigonometry and creating a circle out of vertices in the place of each height segment. In code, this would look like this:

` ````
var vertices = [];
var height = 200;
var radius = 30;
var heightSegments = 50;
var perimeterSegments = 20;
for (var y = 0; y < heightSegments; y++) {
for (var a = 0; a < perimeterSegments; a++) {
// Angle of the current vertex
var angle = 2 * Math.PI / perimeterSegments * a;
// Position of vertex
var x = Math.cos(angle) * radius;
var y = height / heightSegments * y;
var z = Math.sin(angle) * radius;
vertices.push(new Vector3(x, y, z));
}
}
```

Generating the indices for these vertices is the same as generating the indices for a plane. The only difference is that you need to connect the last row of vertices with the first one. To connect vertices with indices you need to use their ids. To get their ids based on their position you need to use the

` ````
id = x + y * width
```

formula.

There are a total of (perimeterSegments - 1) * (heightSegments - 1) quads, thus we only need to loop trough those and not every vertex.

In code this looks like the following:

` ````
// Create the quads between the vertices
for (var x = 0; x < perimeterSegments - 1; x++) {
for (var y = 0; y < heightSegments - 1; y++) {
indices.push(
x + y * perimeterSegments, // vertex at (x; y)
x + (y + 1) * perimeterSegments, // vertex at (x; y + 1)
x + 1 + y * perimeterSegments, // vertex at (x + 1; y)
x + 1 + y * perimeterSegments, // vertex at (x + 1; y)
x + (y + 1) * perimeterSegments, // vertex at (x; y + 1)
x + 1 + (y + 1) * perimeterSegments // vertex at (x + 1; y + 1)
);
}
}
// Connect the last and first row
for (var y = 0; y < heightSegments - 1; y++) {
var x = widthSegments - 1;
indices.push(
x + y * perimeterSegments, // vertex at (x; y)
x + (y + 1) * perimeterSegments, // vertex at (x; y + 1)
y * perimeterSegments, // vertex at (0; y)
y * perimeterSegments, // vertex at (0; y)
x + (y + 1) * perimeterSegments, // vertex at (x; y + 1)
(y + 1) * perimeterSegments // vertex at (0; y + 1)
);
}
```

If you render it you get the following (I use wireframe rendering here too and I also made it horizontal so you can see trough it):

This concludes this tutorial. The next part will be about spheres.

]]>Link: http://yourjavascript.com/01666321507/math-min.js*

Link to part 1: Link Link to part 2: Link

If you're a 3d modeller, then you probably used spheres in your scenes. There are 2 main ways you can generate a sphere.

Don't let the name of this object throw you off, it's a hell on earth when you try to create a UV map for a sphere. This is true for both cases.

The UV sphere is useful, if you want simmetry or you want to make a cartographical globe. The sphere's surface is divided into rectangles with latitude and longitude lines.

To define a UV sphere you need to know the radius of the sphere and the amount of latitude and longitude segments. To create the vertices, you simply create a plane and wrap it around a sphere.

Additional information: We will be using 3d trigonometry for the sphere. To convert angles around a center point into 3d coordinates, you need to use the following formula:

` ````
x = r * sin(angleY) * cos(angleX)
y = r * sin(angleY) * sin(angleX)
z = r * cos(angleY)
```

` ````
var vertices = [];
var radius = 100;
var latitudeCount = 30;
var longitudeCount = 30;
for (var y = 0; y < longitudeCount; y++) {
for (var x = 0; x < latitudeCount; x++) {
var angleX = 2 * Math.PI / latitudeCount * x;
var angleY = 2 * Math.PI / longitudeCount * y;
var xx = radius * Math.sin(angleY) * Math.cos(angleX);
var yy = radius * Math.sin(angleY) * Math.sin(angleX);
var zz = radius * Math.cos(angleY);
vertices.push(new Vector3(xx, yy, zz));
}
}
```

To create the indices, you need to do the same thing as for the tube, except that you need to connect the last vertices vertically too.

` ````
// Create the quads between the vertices
for (var x = 0; x < longitudeCount; x++) {
for (var y = 0; y < latitudeCount; y++) {
var left = x;
var right = (x + 1) % longitudeCount;
var top = y;
var bottom = (y + 1) % latitudeCount;
indices.push(
left + top * longitudeCount, // vertex at (x; y)
left + bottom * longitudeCount, // vertex at (x; y + 1)
right + top * longitudeCount, // vertex at (x + 1; y)
right + top * longitudeCount, // vertex at (x + 1; y)
left + bottom * longitudeCount, // vertex at (x; y + 1)
right + bottom * longitudeCount // vertex at (x + 1; y + 1)
);
}
}
```

If you render it you get the following sphere:

The icosphere is a sphere wich consist of triangles. It's generated by subdividing an icosahedron. It's widely used in modelling as it provides a more natural shape and doesn't require preprocessing to use in rendering (like triangulation).

The vertices of an icosahedron are the corners of 3 ortoghonal rectangles:

If the rectangle's length is 1, then the height of it is the golden ratio (`(1 + sqrt(5)) / 2`

= 1.618...).

In code this look like:

` ````
var vertices = [];
var r = 100;
var ration = (1 + Math.sqrt(5)) / 2 * r;
vertices.push(new Vector3(-r, ration, 0));
vertices.push(new Vector3(r, ration, 0));
vertices.push(new Vector3(-r, -ration, 0));
vertices.push(new Vector3(r, -ration, 0));
vertices.push(new Vector3(0, -r, ration));
vertices.push(new Vector3(0, r, ration));
vertices.push(new Vector3(0, -r, -ration));
vertices.push(new Vector3(0, r, -ration));
vertices.push(new Vector3(ration, 0, -r));
vertices.push(new Vector3(ration, 0, r));
vertices.push(new Vector3(-ration, 0, -r));
vertices.push(new Vector3(-ration, 0, r));
```

Creating the indices is again a very hard-code-y process. The indices for an icosahedron are:

` ````
var indices = [
0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
3, 9, 4, 3, 4, 23, 2, 6, 3, 6, 8, 3, 8, 9,
4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
];
```

If you render the vertices above, then you get an icosahedron, but it's still not an icosphere. To get an icosphere you need to subdivide it. To subdivide th triangles of the icosahedron you need to divide them into 4 equal triangles, normalize the new vertices and multiply it with the radius.

In code

` ````
function subdivide() {
var newVertices = [];
var newIndices = [];
for (var i = 0; i < indices; i += 3) {
var v1 = vertices[indices[i]];
var v2 = vertices[indices[i + 1]];
var v3 = vertices[indices[i + 2]]
var v12 = v1.clone().add(v2);
var v23 = v2.clone().add(v3);
var v31 = v3.clone().add(v1);
v12.normalize().multiply(r);
v23.normalize().multiply(r);
v31.normalize().multiply(r);
var ind = newVertices.length;
newVertices.push(v1, v2, v3, v12, v23, v31);
newIndices.push(ind, ind + 3, ind + 5); // v1, v12, v31
newIndices.push(ind + 1, ind + 3, ind + 4); // v2, v12, v23
newIndices.push(ind + 2, ind + 4, ind + 5); // v3, v23, v31
newIndices.push(ind + 3, ind + 4, ind + 5); // v12, v23, v31
}
vertices = newVertices;
indices = newIndices;
}
```

If you use the above code with the icosahedron generation and you render it, then you get the following:

*Note: I made this pen before I created this post series. It contains some additional stuff, like lighting.*