Hey, how’s it going? I’m back with a second tutorial this week that builds on top of the example I showed you in my previous post. We’re going to be working with three.js to draw something with OpenGL again. But this time it’ll be a little more fun than the triangle we drew last time. That’s right, this time we’re going to draw **A CIRCLE**!

Let’s get down to business! We’re going to be working in the same folder where we wrote the triangle example, so if you haven’t completed that tutorial yet, go back and do that first. Once you’re ready, let’s make a new HTML file in the same directory as `just_draw_a_stupid_triangle.html`

. Except we’ll name this one `making_a_dopey_circle_thing.html`

.

To keep me from jumping around too much, I’m just going to dump all of the code right here. You can copy/paste it into the file and save it, and then I’ll go over each of the numbered sections one-by-one.

Here’s all of the code:

```
<!DOCTYPE html>
<html lang="en">
<head>
<title>Making A Dopey Circle Thing With OpenGL</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
color: #ffffff;
background-color: #000000;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="js/three.js"></script>
<script src="js/Detector.js"></script>
<script>
var webGlSupported = Detector.webgl;
if (!webGlSupported) {
Detector.addGetWebGLMessage();
}
var container = undefined;
var camera = undefined;
var scene = undefined;
var renderer = undefined;
initializeCamera();
initializeScene();
initializeRenderer();
renderScene();
function initializeCamera() {
var aspectRatio = window.innerWidth / window.innerHeight;
var screenWidth = undefined;
var screenHeight = undefined;
if (aspectRatio > 1.0) {
screenWidth = 320.0 * aspectRatio;
screenHeight = 320.0;
} else {
screenWidth = 320.0;
screenHeight = 320.0 / aspectRatio;
}
var nearPlane = 1.0;
var farPlane = 1000.0;
camera = new THREE.OrthographicCamera(
-0.5 * screenWidth,
0.5 * screenWidth,
0.5 * screenHeight,
-0.5 * screenHeight,
nearPlane,
farPlane
);
var distanceFromScene = 500.0;
camera.position.set(0.0, 0.0, distanceFromScene);
}
function initializeScene() {
scene = new THREE.Scene();
// 1
var radius = 65.0;
var sidesCount = 6;
var geometry = getRegularPolygonGeometry(radius, sidesCount);
// 6
var magenta = new THREE.Color(1.0, 0.0, 1.0);
var material = new THREE.MeshBasicMaterial({
color: magenta,
side: THREE.DoubleSide
});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0.0, 0.0, 0.0);
scene.add(mesh);
}
function getRegularPolygonGeometry(radius, sidesCount) {
// 2
var geometry = new THREE.Geometry();
// 3
var centerPoint = new THREE.Vector3(0.0, 0.0, 0.0);
geometry.vertices.push(centerPoint);
for (var outerPointIndex = 0; outerPointIndex < sidesCount; outerPointIndex++) {
var outerPointProgress = outerPointIndex / sidesCount;
var angleInRadians = outerPointProgress * 2.0 * Math.PI;
var x = Math.cos(angleInRadians) * radius;
var y = Math.sin(angleInRadians) * radius;
var outerPoint = new THREE.Vector3(x, y, 0.0);
geometry.vertices.push(outerPoint);
}
// 4
var centerPointIndex = 0;
for (faceIndex = 0; faceIndex < sidesCount; faceIndex++) {
var face = new THREE.Face3();
var trailingOuterPointIndex = faceIndex + 1;
var leadingOuterPointIndex = faceIndex + 2;
if (leadingOuterPointIndex > sidesCount) {
leadingOuterPointIndex -= sidesCount;
}
var face = new THREE.Face3(centerPointIndex, trailingOuterPointIndex, leadingOuterPointIndex);
geometry.faces.push(face);
}
// 5
return geometry;
}
function initializeRenderer() {
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container = document.getElementById("container");
container.appendChild(renderer.domElement);
}
function renderScene() {
renderer.render(scene, camera);
}
</script>
</body>
</html>
```

There you go!

Glancing over the code quickly, you’ll notice that it’s mostly the same. I’ve taken the liberty of pulling the camera functionality out of `initializeScene`

and placing it in its own function (`initializeCamera`

) that also gets called at the beginning of the script. I did this to keep things less cluttered. In general, it’s a good idea to break each function up so it’s as short as you can possibly make it. That’s because shorter functions are easier for humans to grok. They also help you keep responsibilities clearly divided and intents clearly labeled within your code–so that other programmers will be able to make sense of it more easily.

Back in `initializeScene`

, I’ve made some more pretty big changes. We’ll start at `// 1`

.

```
// 1
var radius = 65.0;
var sidesCount = 6;
var geometry = getRegularPolygonGeometry(radius, sidesCount);
```

Okay. So it looks like I’m specifying some properties of a shape. It’s going to have a radius of `65.0`

units, and it’ll have `6`

sides. I’m passing the values into a function called `getRegularPolygonGeometry`

… which I’ve defined right below `initializeScene`

. So scroll on down and find part `// 2`

.

Wait a second. If we’re trying to draw a *circle* here, why did I call the function `getRegularPolygonGeometry`

?

Back in the first tutorial, I told you that *everything* in every OpenGL game you’ve ever played was made up of triangles. So complex polygons are nothing more than multiple triangles put side-by-side. But what if you want to draw something that’s not a polygon? What if you want to draw a curved shape, like a circle?

Believe it or not, there is *no way* to specify a curved shape in OpenGL. Yes, you read that correctly. It’s impossible.

Uhh… *what*? As you know, there are plenty of OpenGL games with curved shapes in them. So either I’m lying or there’s some other weird magic at work here. What gives?

Even though there’s no way to draw a perfect curve in OpenGL, it’s pretty easy to draw an *approximated* curve. You can try to split any curved shape up into triangles, just like you would for any polygon. It’s just that those triangles have to be very, *very* small, or the curve will start to look chunky.

Although drawing so many triangles sounds like it’s going to be pretty performance-intensive, modern graphics processors can handle it. Remember, we should try not to worry about performance until a bottleneck develops. It seems like thousands of tiny triangles would be a lot of work, but I can tell you from experience that the number of vertices in a shape is almost never the thing that overloads your graphics pipeline first. In a typical game, there are many other factors your computer needs to keep track of. If we’re placing bets on what’s slowing your game down, I’d put my money on one of them instead. Modern 3D games often need to render *millions* of triangles every frame. At most, one of our 2D scenes might need to render a few thousand. By comparison, it’s practically nothing.

Now where was I?

```
// 2
var geometry = new THREE.Geometry();
```

Ah, yes. Here we’re creating a `Geometry`

object. Except this time it’s the `Geometry`

of a regular polygon, so it’s going to contain *multiple* triangles. To define those triangles, first we’re going to have to define their points.

```
// 3
var centerPoint = new THREE.Vector3(0.0, 0.0, 0.0);
geometry.vertices.push(centerPoint);
for (var outerPointIndex = 0; outerPointIndex < sidesCount; outerPointIndex++) {
var outerPointProgress = outerPointIndex / sidesCount;
var angleInRadians = outerPointProgress * 2.0 * Math.PI;
var x = Math.cos(angleInRadians) * radius;
var y = Math.sin(angleInRadians) * radius;
var outerPoint = new THREE.Vector3(x, y, 0.0);
geometry.vertices.push(outerPoint);
}
```

Don’t let the `for`

loop scare you. This isn’t rocket science.

The first thing we’re doing is defining a point at the center of our regular polygon. To keep things simple, we’ll keep the center at the origin, `(0.0, 0.0)`

. We add that center point to our `vertices`

array, and after that it gets a little intense. What does *this part* mean?

```
for (var outerPointIndex = 0; outerPointIndex < sidesCount; outerPointIndex++) {
```

All this is doing is defining a loop. If you’re a seasoned programmer you’ll breeze through this, but I’ll give a quick overview here for those of us who haven’t written much code before. We’re going to run the code inside the `{}`

braces several times in a row. *How many* times? In this case, the answer is `sidesCount`

times. We’re declaring a variable called `outerPointIndex`

, and we’re starting it with a value of `0`

. Each time we finish running the code in the braces, we’ll add `1`

to its value–that’s all that `outerPointIndex++`

means. And we’ll keep looping as long as `outerPointIndex`

is less than `sidesCount`

. That means if we start our function with `sidesCount`

with a value of `6`

, then our loop would run *six times*… with the following values: `0`

, `1`

, `2`

, `3`

, `4`

, and finally `5`

.

Okay. We’re running the code `sidesCount`

times. But what does the code actually *do*? It’s building the points around the outside of a regular polygon. If your regular polygon had six sides, the points would be here:

Each outer point is marked with its `outerPointIndex`

value. Now let’s take a look at the code inside the loop.

First, we’re getting the value of `outerPointIndex / sidesCount`

and storing it in `outerPointProgress`

. The result will be somewhere between `0.0`

and `1.0`

. You could think of this value as a measure of how close we are to finishing the polygon. The value for `outerPointIndex`

`0`

will always be `0.0`

, and if our polygon has `6`

sides, then the value for each successive point will increase by `1 / 6`

, which happens to come out to about `0.1666666666666666`

. After we calculate the `outerPointProgress`

, we multiply it by a factor of `2.0 * Math.PI`

. Why? Because that’s how we convert the progress fraction into a value in radians. You can think of this like taking the six points of our polygon and spacing them out evenly around an imaginary circle.

So the values for our six points would be as follows:

`outerPointIndex` | `outerPointProgress` | `angleInRadians` |
---|---|---|

0 | 0.0000000000000000 | 0.000000000000000 |

1 | 0.1666666666666666 | 1.047197551196597 |

2 | 0.3333333333333333 | 2.094395102393195 |

3 | 0.5000000000000000 | 3.141592653589793 |

4 | 0.6666666666666666 | 4.188790204786390 |

5 | 0.8333333333333334 | 5.235987755982989 |

Each time we increment the `outerPointIndex`

, we also increase the value of `outerPointProgress`

by `1 / 6`

, and consequently, we increase the value of `angleInRadians`

by `Math.PI / 3`

. If you look closely, you’ll see that the `angleInRadians`

value for the fourth point is `3.14159`

something, which happens to be the value of `PI`

. That makes sense, since it’s halfway around our imaginary circle. Now that you mention it, this imaginary circle is starting to remind me of something I learned about in high school and then tried to forget. Sorry–it’s back. It’s our old friend, the dreaded *unit circle*.

Hopefully that didn’t trigger too many unpleasant memories. I’ll try to avoid mentioning high school from now on. At any rate, the unit circle is actually pretty handy when it comes to drawing shapes. Do you recall anything about *sine* and *cosine*? If you need a refresher, no worries. The values in the parentheses around the outside there are actually what you’d get if you plugged the angle values into `cos`

and `sin`

to get the *x* and *y* values, respectively, of a point around the circle. For instance, if you plug in our second point’s angle, which is `Math.PI / 3`

, or `1.047197551196597`

, you’d get a point at `(0.500000000000000, 0.8660254037844386)`

. It turns out another way to express this is `(1 / 2, Math.sqrt(3) / 2)`

.

So when we say this…

```
var x = Math.cos(angleInRadians) * radius;
var y = Math.sin(angleInRadians) * radius;
```

We’re just taking the values from `cos`

and `sin`

around our unit circle, and we’re saving them in their own `x`

and `y`

variables. Except we’re doing something else at the same time–we’re multiplying by the `radius`

that we passed in. That’s because, as its name implies, the *unit* circle has a radius of just *one unit*. We set up our coordinate system so that the drawing area would be `320.0`

units wide. Therefore, we’ll need our shape to have a larger radius so that we can actually see it on the screen. To achieve this, all we have to do is multiply.

Finally, once we’ve calculated the `x`

and `y`

values for each point around our polygon, we store those points in a `THREE.Vector3`

object with `0.0`

for the `z`

coordinate, just like we did in the first tutorial. After we create each `Vector3`

, we add it to our `vertices`

array and move on.

```
var outerPoint = new THREE.Vector3(x, y, 0.0);
geometry.vertices.push(outerPoint);
```

Did somebody say *faces*? 😛

When we were drawing just one triangle, we had to create just one `Face3`

object for it. But now that we’re drawing a regular polygon, we’re going to need to specify a `Face3`

object for each side. If we wanted our polygon to have a `sidesCount`

of `6`

, then we’d want it divided up into triangles with the following indices.

This looks like a job for a second `for`

loop!

```
// 4
var centerPointIndex = 0;
for (faceIndex = 0; faceIndex < sidesCount; faceIndex++) {
var face = new THREE.Face3();
var trailingOuterPointIndex = faceIndex + 1;
var leadingOuterPointIndex = faceIndex + 2;
if (leadingOuterPointIndex > sidesCount) {
leadingOuterPointIndex -= sidesCount;
}
var face = new THREE.Face3(centerPointIndex, trailingOuterPointIndex, leadingOuterPointIndex);
geometry.faces.push(face);
}
```

Before we start our loop, we declare that the index of the center point is `0`

. That’s because it was the first point that we added to the `vertices`

array. Then, we added all the outer points on top of it. So at this point, the indices for *all* of the points in the `vertices`

array look like this:

It might feel like our loop is doing something complicated, but if you pay attention to the pattern in the output, it’s simple to see how it’s creating the `Face3`

objects. If your regular polygon had a `sidesCount`

of `6`

, you’d get faces with the following indices:

`faceIndex` | `centerPointIndex` | `trailingOuterPointIndex` | `leadingOuterPointIndex` |
---|---|---|---|

0 | 0 | 1 | 2 |

1 | 0 | 2 | 3 |

2 | 0 | 3 | 4 |

3 | 0 | 4 | 5 |

4 | 0 | 5 | 6 |

5 | 0 | 6 | 1 |

We’re literally just telling OpenGL how to connect the dots. When we get to the last `Face3`

, our `leadingOuterPointIndex`

would hit a value of `7`

, which doesn’t correspond to any point. To avoid this, we just wrap it back around to `1`

by subtracting `sidesCount`

.

Once again, we `push`

each `Face3`

onto the `faces`

array after it’s created.

Part `// 5`

is just one line, but I decided to enumerate it to remind us what we just finished doing. We’re at the bottom of the function (`getRegularPolygonGeometry`

) that builds and returns our polygon geometry object. …And we called this function as part of `initializeScene`

. So now that we’ve created a new `THREE.Geometry`

object, we’ve defined the points of the triangles that make it up, and we’ve spelled out which points belong to which triangles, we’re finally ready to `return`

the `geometry`

to the calling function. Oh yeah, that’s right.

To find part `// 6`

, you’ll have to scroll back up to where `getRegularPolygonGeometry`

returns in `initializeScene`

.

```
// 6
var magenta = new THREE.Color(1.0, 0.0, 1.0);
var material = new THREE.MeshBasicMaterial({
color: magenta,
side: THREE.DoubleSide
});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0.0, 0.0, 0.0);
scene.add(mesh);
```

I thought it would be boring to draw another `green`

shape, so this time I decided to try something different. When you turn down a pixel’s `green`

channel to `0.0`

and turn up its `red`

and `blue`

channels all the way to `1.0`

, the resulting color is `magenta`

. Fancy.

The rest is basically the same as what we did in the first tutorial. We create a `THREE.Mesh`

object to pair our regular polygon `geometry`

with the double-sided, brightly-colored `material`

we just created. Then we add that `mesh`

to the `scene`

. And *voila*! Go ahead and open the HTML file in your web browser. You should get the following lovely, magenta hexagon.

I almost forgot that this is supposed to be a tutorial about drawing *circles*, not hexagons. Fear not, for this is easily remedied. Back at part `// 1`

, we gave our polygon a radius of `65.0`

and a `sidesCount`

of `6`

. What happens when we mess with these values? Let’s find out.

Try changing the `sidesCount`

to `12`

and refreshing the page in your browser.

Nice! If I’m not mistaken, that’s known as a *dodecagon*.

Now just for fun, let’s lower the value to `3`

and refresh once again.

Heh, just what you’d expect.

But I promised you a *circle*. Let’s try turning the `sidesCount`

all the way up to `80`

!

It’s technically not a *circle*. It’s an octacontagon. But you could’ve fooled me. And in a game, that’s all that matters.

Feel free to mess around with the `radius`

value as well. Make a small circle. Make a big circle. Geometry is *fun*!

Just to prove a point, I’d like you to make one last little change. Try turning the `sidesCount`

up again. This time to `900`

. And again… to `9000`

. And *again*… to `90000`

!

You might experience a slight hiccup when the page is loading on that last one, but only if your computer is pretty old, and even then only if you’re paying *really* close attention. That’s because modern computers are fast. Outrageously fast. Mind-blowingly fast.

Also, it’s important to point out that any slowdown you *did* experience probably wasn’t caused by your graphics processor. The bottleneck probably formed in the JavaScript that ran on your CPU. Writing performant OpenGL code is a constant balancing act between CPU and GPU. If your game has to fill a lot of pixels with a heavy *shader* program, then your GPU might not be able to keep up. But if your shader is simple, as is often the case in 2D games, then your CPU will probably be the first to buckle.

I’ll talk a lot more about these *shader* programs in future tutorials, but for the time being, let’s simply appreciate the sheer speed of modern hardware as we gaze upon our glorious magenta creation.

If you’ve made it this far, take a moment to congratulate yourself. Seriously! OpenGL isn’t easy. At times it’s actually infuriatingly tedious. …At least when you’re still mastering the basics. Nevertheless, you’ve persevered through the worst of it. From here on out, the learning feels a lot less like high school, and the possibilities really begin to explode.

I hope you’ll stick around for the next few tutorials that I’m about to write!

Click here to run the finished product!

And here’s a link to a downloadable version of the source code: making_a_dopey_circle_thing.html. *Note that you’ll need to run it from inside the folder structure that we set up in the previous tutorial.*