Creative Coding with Canvas & WebGL Creative Coding with Canvas & WebGL

Capabilities of Three.js: Isometric Perspective

Check out a free preview of the full Creative Coding with Canvas & WebGL course:
The "Capabilities of Three.js: Isometric Perspective" Lesson is part of the full, Creative Coding with Canvas & WebGL course featured in this preview video. Here's what you'd learn in this lesson:

Matt introduces a basic ThreeJS template, how to render with isometric perspective, and how to instance many meshes in a single scene. - https://github.com/mattdesl/workshop-generative-art/blob/master/docs/cheat-sheet.md

Get Unlimited Access Now

Transcript from the "Capabilities of Three.js: Isometric Perspective" Lesson

[00:00:00]
>> Mathew DesLauriers: So, the first thing I want to do is make the background not black cuz black background, I don't know, I want it to be a bit brighter. So, I'm gonna use white, or you can use maybe an HSL value, which stands for hue saturation lightness. You can set it to zero, and then maybe something very bright for the lightness.

[00:00:22] So 0 hue, 0 saturation, something bright for the lightness and that's just gonna give us a bit of an off-white color. And then what we're gonna wanna do is let's say we get rid of this lighting stuff. So these two chunks of code, we have the ambient light and the point light.

[00:00:40] Let's come back to those later, but let's just delete those for now, and you'll notice all of a sudden that we end up with a black rectangle. And that's like I was saying earlier when you turn the lights off, you don't have any lighting in the scene, and so your mesh just becomes black.

[00:00:55] But what we can do to fix that is we can change this material. So, right now we're using a mesh standard material. That means it's trying to take the lighting from the scene, but there is none. So we're gonna use a mesh basic material and we're gonna change color to something else.

[00:01:15] So that's pretty standard stuff so far I'm just gonna open my console just so I can see any error messages in case they come up, and you'll notice maybe a warning. This mesh basic material, roughness is not a property of this material. That's because we're passing value roughness but mesh basic material, it doesn't need these things.

[00:01:36] So we can just delete those two things. Just end up with the color red.
>> Mathew DesLauriers: Okay, so there's our red cube, and the next thing I wanna do is I want us to get rid of our controls. So maybe we'll come back to doing controls later but for now, I wanna do an animation that's looping and that's seamless and it's going on its own rather than us having to move it around in order to see it changing.

[00:02:05] So I'm gonna just delete a couple of lines. There's this one, this is the one where we set up the controller. We don't need that anymore and then we just have to make sure that the other two places that it controls are referenced from are also removed. So there it is in the render function.

[00:02:22] We're removing it and then there it is in the unload function and we're removing that as well. So there's three places in total, and if that works, if that works then you should have the image but you can't control it, and this is just gonna set us up a bit more for doing a video loop or a seamless GIF, rather than having to always interact with the scene.

[00:02:46]
>> Mathew DesLauriers: And so the next thing we're gonna do is we're gonna try and get back to some of this style that I was showing here. And remember how I was saying we had the difference between a prospective and orthographic? So what we're gonna do is we're gonna try and learn about how do we do isometric or orthographic in this case perspective so it looks a bit more like this because we want it be a bit more artsy, a bit more like monument valley.

[00:03:13] So I go back to my code and what I'm gonna do here is change perspective camera to be orthographic camera and we don't need to pass any arguments yet and it looks like that. And we're gonna have a couple of errors or empty scenes for a few attempts here, so don't worry.

[00:03:35] These two lines after that, let's just remove those, cuz those are useful for the perspective, but we're gonna them a little differently for isometric or the graphic camera. So, it just looks like that so far. And then when we come down to the resize function, what we have to do is we have to say okay every time there is a scene resizes, we need to set up our camera to this new scene size and this part is really just a bit of a memory game, and it's such a memory game that I've actually put it in the cheat sheet.

[00:04:08] So if you go to your repo, if you go to the cheat sheet and you scroll almost all the way down you'll see isometric 3GS camera. And this is something that I just copy-paste a lot, so don't feel guilty if you're copy-pasting it. I would literally suggest copy pasting it now, just because it will get us there a bit quicker and we can chat about what it's doing.

[00:04:32] Usually I don't copy paste stuff, but in this case, it's a bit of boilerplate and sometimes I forget it. So don't feel too guilty if you're copy pasting. So what it's doing it's just setting the attributes of our camera using some of the code. So we're gonna have to just clean this code up a little bit because I just copied and pasted it and I wanna just clean it up a bit.

[00:04:58] So the first thing you'll notice is we have these two lines at the bottom. You only need one of them, so I'm just gonna remove that one. Just make sure you have one. It doesn't really matter. The other small issue is that in our props here we're using something a little different than width height.

[00:05:16] We're using view port width and view port height. So width height is gonna air us out so I'm just gonna change that to be view port width divided by view port height, and that's just kind of an internal part of the 3GS template that it's using view port width instead of width and height.

[00:05:35] And the difference in our case is kind of nothing at all, but if you have maybe if you're using physical units or something like that, the viewport might not match exactly the width of your image. But in our case it's not really a big difference.
>> Mathew DesLauriers: So if we had copied that correctly And we save, we should already end up with what is an orthographic or asymmetric perspective.

[00:06:04] So I don't know. Maybe you guys managed to get that far. And then one thing that I don't wanna do here is I don't wanna just rotate the mesh. We'll come back to doing some animation in a second. So I'm just gonna delete that line. And now we have a very boring looking output, but let's make it a bit more interesting.

[00:06:23] So, instead of just creating a single mesh, let's create many meshes, and so we're gonna wrap this in a FOR loop, so I just indented it, I'm just gonna do like ten for now.
>> Mathew DesLauriers: And they're all in the same position so they're all overlapping each other so it doesn't look any different yet.

[00:06:55] So I'm just gonna do this, I'm gonna set the position. For now, let's just it's just do you know what we'll do, is because what we want to do is we want to set a random position for each of these cubes because we have 10 cubes now. And so, I mean if you set this position to a different position you're going to start to see it moving around the screen.

[00:07:22] And we want to use a random value. So you can do math.random, or what we're actually going to end up doing is bringing in the random number generator that we had before. We'll do that in a second. And if you're this far you're probably gonna get this blob of red.

[00:07:42] That's because the cubes are really big and we need to scale them down a bit. So what we're gonna do is mesh.scale and then multiplyScalar. This is a function that will multiply the x, y, and z, all by the same number value that you give it. You can use some number value there.

[00:08:09] While you're doing that, I just want to very quickly try and explain 3D coordinates in a very simple way. This is something that took me a really long time to wrap my head around, so don't feel too worried if you're still trying to pick it up. But basically when we work in 2-D we have the top left of the screen which is 00 and the bottom right of the screen is the width and the height of the screen.

[00:08:34] But in 3-D we don't have those pixel coordinates anymore. There's no such thing as top left or bottom right of the screen, the only thing we have is this virtual world with these arbitrary coordinates. You might be wondering how do I move this exactly three pixels to the right?

[00:08:52] You can't just move this cube three pixels to the right because pixels don't exist in this. The thing that we're working with, this arbitrary coordinate space, and so the best way to think about it is to think of it in terms of real world units like meters or inches or something like that, so you would specify a coordinate space that you want to deal with it.

[00:09:11] So, let's say we want everything in our virtual world to be in meters, and then you specify an origin and everything is relative to that origin. So if I was to say I'm standing at the center of the world, the center of the world is always 000, and then every object that you place in your world is gonna be relative to where you're standing, where that origin is.

[00:09:35] So if I was to place an object to the right of me, maybe we might say that it's x along the x axis by one unit, maybe this is maybe not one full meter. But imagine it's one meter, it's the same with going backwards or forwards, if I was to step forwards that might be along the zed axis by one meter.

[00:09:53] And if I was to be in the air maybe it would be one meter in the air. So it's a really hard thing to sort of wrap your mind around and it took me a long time but I just tried to think of it in terms of just real world positioning.

[00:10:06] Like if I was to place this 3D mouse somewhere on the table and move it this way that might be one unit along the x or along the y or along the zed. And actually there's a little trick that I do all the time, and you guys can try and do it as well to hold your fingers out like this like a gun just using your thumb and your index finger on your right hand.

[00:10:31] And you stick it out like this just in front of you and then you stick out your middle finger and you make your little finger perpendicular to your index finger and this becomes the three axis X, Y, Z that we're actually gonna be dealing with in 3D. And you just have to remember these three things.

[00:10:50] You have to remember that your thumb is the Y axis, and so your thumb is going up and down just following the line of your thumb going up and down. So that's y, so if we actually were to change, where this is x, y, z, if we were gonna change this numbers, the y coordinate, you'll see if I make this 2, or 3, is going up and down because our thumb is going up and down.

[00:11:17] And then for the other finger, let's say our index finger is zed. So Zed in this case is gonna be forward and backwards. So if we were to change the zed, which is this third coordinate, we'll start to see it's going depending on where our camera is it's gonna maybe appear to go forwards or backwards.

[00:11:40] But this is this weird concept that we have to just try and deal with for now. And if you're ever stuck, just think of this where your thumb is y, your index finger is z, and your middle finger is x. So you might wanna write that down just to remember thumb is y, middle finger is x, index finger is zed, but it's a really weird thing to try and wrap your head around, and even more difficult to try and explain.

[00:12:06] Especially because when I started this kind of creative coding I wasn't very familiar with any of these math concepts. And this is a sort of misconception I think is that a lot of people think that to be a programmer, to be a creative coder you have to know a lot about math, and I don't know a lot about math, and I have had to learn it basically myself, but that's basically just to say that it's not as scary as it appears.

[00:12:33] And definitely with practice and just trying to memorize things, and use the ways of memorizing just like the index finger, you can start to pick it up. So, yeah, just to say you don't need to be a math wizard to do this kind of stuff. Okay, going back to our code.

[00:12:54] I was saying I wanted to position things randomly in this xyz space. So what I'm going to do is I'm going to require our utility that is the random utility and we have to do canvassketchutil/random.
>> Mathew DesLauriers: So it just looks like that.
>> Mathew DesLauriers: And then here in our positioning for each of these x, y and zed coordinates I'm gonna do random.value, so I'm gonna do this again, random.range which means I wanna a random number between a minimum and maximum.

[00:13:43] So the minimum is gonna be -1. We'll just use -1 to 1 for now. And then the same, random.range -1 to 1 and the same here, random.range -1 to 1. So what you should end up with is this, these three coordinates. Each of them is going to be random between -1 and 1, and our cubes are gonna start to appear all over the place.

[00:14:15]
>> Mathew DesLauriers: And one thing I'm gonna do just so we can visualize this a bit better. If we scroll down to our orthographic stuff that we copy-pasted I'm gonna increase the zoom to a larger number like 2 or 1.5. That's gonna just zoom everything out a little bit so we can start to see this scene a bit better.

[00:14:37] Does anyone remember what I was saying earlier about geometries and how we shouldn't be using this geometry many times? Well this is one thing where we should change this because right now I´m creating ten box geometries and so we should actually just use this BoxGeometry once outside of our loop, and then reuse that for each mesh.

[00:15:03] And this is gonna look no different, it's just gonna produce a more efficient code, and it's really important when you start to do things like animation or interactivity, especially if you're trying to give somebody a mobile experience with this code.