What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
WebGL and Three.js Fundamentals
by Alex Mackey
In this course, viewers will learn how to develop WebGL applications using the Three.js library.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Introduction
Introduction
Hello, and welcome to Pluralsight. I'm Alex Mackey and it's my pleasure to welcome you to WebGL with Three.JS Fundamentals course. A question some of you may be asking, is why should you bother learning Three.JS or WebGL at all? I guess you might be here because you've seen some of the many awesome WebGL demos around at the moment. Maybe you wanted to create something similar yourself. Currently web developers have an awesome choice of graphical technologies available such as CSS, Canvas, SVG and of course, WebGL. Each of these technologies has its own distinct advantages and disadvantages. So why should you look at WebGL? Well, probably the main reason's you use WebGL is that you can create graphical effects that just aren't possible or very difficult to implement with some of the other graphical technologies such as, Canvas or SVG. Unlike technologies such as Flash and Silverlight, WebGL doesn't need a plugin to work. It's platform independent and it's supported in all modern browsers, including Internet Explorer from version 11. WebGL has even supported by many mobile browsers, like Windows Phone, Oprah, and Firefox Mobile. It is worth noting, that currently WebGL is not available in iOS, except through as part of Apple's iAd program. It's a bit of a shame it's locked away, but hopefully this will change in the future. WebGL allows you to create or make use of pluggable, reusable, graphical, code modules called Shaders and you can perform some really cool graphical effects with these. With WebGL you still have access to all existing web page technologies so you can combine it with technologies such as CSS, SVG, and Canvas. WebGL is a very open standard and theoretically there is nothing stopping use of making a feature or change if you something could be improved. I also think that WebGL is one of a number of technologies driving advances in browser technology and it's exciting to be part of this. So what might you want to use WebGL for? Well, probably the main use is --- are for visualizations or simulations, and of course, games. But don't think that WebGL can't have commercial usage too. For example, maybe you're running an online shopping site and you want your users to be available to explore your products in detail. WebGL could be a great solution for this. So there's some really nice examples of just what you can achieve with Three.JS, if you head over to three.js.org. And on the homepage here, you can go and click on various examples and explore them in more detail. I want to pull out a couple of examples. This one here allows you to go and explore the Bat Mobile here. We can go and rotate the vehicle around, we can zoom in, we can zoom out from it, we can change it into a different mode, into its Pursuit Mode there. Now you could think, maybe you could use this type of functionality to allow your users or visitors to your site to go and explore a product in great detail. Another example I really like is this one here, which allows us to picture the Arms Trade around the world. And we can focus on individual countries, we can zoom in and we can see individual figures here. I think it's a really nice example because it's much more interesting than some graph or spreadsheet, and it really illustrates the point it's trying to make of which company --- countries that are really trading a lot of arms. Another example and I've got a game here, and if we go and Resume it, and the object to this game is just to go and escape the zombies that are moving around the place. And sooner or later if we walk around we'll see some zombies in the distance there. And I think some of these examples really demonstrate just what you can achieve using Three.JS. Once we've been through the basics, we're actually going to be putting together a game of our own. We're going to take something a bit simpler for this foundational course. And we're going to be looking at the game Frogger, but we'll come back to that once we've covered some of the basics. Before we get started, it's probably worth mentioning that Three.JS and WebGL do have something of a steep learning curve. And this really was a driver for me putting together this course. It's not necessarily that it's particularly hard to learn, although there are so scenarios that can get very complex indeed, it's more that's it difficult to find good information and documentation for topics beyond the basic. Three.JS has many excellent examples, but it's not the easiest thing to get started with and a documentation, like many open source projects, is something of a work in progress. I'll be recommending a few supplementary materials and books you may find of interest at the end of this module. I think Concatenating Fraidy programming can be quite tricky, as it crosses a number of different disciplines. There is of course, programming: you have to have knowledge of Three.JS, WebGL, JavaScript, and have a web tec --- page technologies. Math: you probably won't be too surprised to learn that there is some elements of math involved in Three.JS programming. Now I'm going to try to keep this element to a minimum. I don't have a background in math and I haven't done any formal math study since I was 16. One thing Three.JS has done however is peak my interest in this area and I hope it peaks your interest too. I can assure you there's plenty you can accomplish with only a basic knowledge of math and the other stuff you can pick up as you go along. Say for example, you need a formula to move something around in an arch, a quick Google will usually provide the math behind this. Hardware: Three.JS programming is hardware dependent and knowing how this works behind the scenes can help you get the most out of your applications. Three.JS programming techniques are also slightly different to what you may have been working with and I found a number of solutions to common issues such as ca --- collision detection and performance techniques. You should be aware that some people think that WebGL could be a security risk. There's already been a few proofs of concepts around this area. OpenGL to Standard WebGL is based on --- was originally developed with speed in mind, not security, and it was intended to be run on a single device rather than over the web. Having said that, WebGL does run through a number of abstractions and browser vendors are of course, doing their best to ensure this is as secure as possible. Only time will tell how much of a problem security is with WebGL, but you should probably expect WebGL to be disabled in some environments because it won't be subtle for old purposes.
History of WebGL and Three.js
There a number of attempts at developing a web based 3D rendering format in the past 10 to 20 years. Most of these have disappeared into obscurity now. I don't think this will happen with WebGL, but who knows what the future holds. WebGL has probably been so successful partly due to some lucky timing. It was made possible by browser performance advances, improved bandwidth and infrastructure, some great libraries, and the ever increasing popularity of JS. Basing the framework on another framework called, OpenGL, probably didn't hurt either. As you probably know WebGL is based on another existing standard called OpenGL. OpenGL is a way of working with the GPU and it's used in a number of applications such as games and visualizations. To be exact, WebGL is actually based on OpenGL ES 2.0. The ES, stands for Embedded Systems and is a cut down version of the full OpenGL specification that's aimed at mobile devices. WebGL can be considered as essentially providing a JavaScript wrapping around OpenGL embedded systems. Depending on the platform there is also an abstraction sitting between the browser and operating system. For example, on the Windows platform, Chrome or Firefox use something called ANGLE, which stands for Almost Native Graphics Layer Engine. WebGL was originally developed by a guy called, Vladimir while he was working at Mozilla. Vladimir was playing around with a 3D version of Canvas and demonstrated a prototype as early as 2006. Fast-forward to 2009 and we saw the creation of the Khronos Working Group, which still managed the WebGL specification today. WebGL has seen contributions from many big industry names such as, Apple, Google, Mozilla, Oprah, and of course, many less well-known companies and individuals. Here's an example of some pure WebGL code. This creates a red rectangle. To work with WebGL you utilize the canvas elements, provide a drawing surface, and JavaScript to call the various WebGL APIs. Pure WebGL is a bit time consuming to work with and there's a lot of code to perform some simple tasks. Of course the solution to this was to develop libraries and frameworks to make WebGL easier to use. To give you an idea of some of the savings that using a framework such as, Three.JS over WebGL can give you, the code here on the left is Three.JS, whereas the code on the right here is using WebGL to perform the same task of a simple moon animation. There are a number of WebGL frameworks available. At the time of writing the most popular were probably Three.JS, while Babylons.JS is gaining a lot of popularity. At some level the APIs and concepts between these various libraries are not so different so it's likely that by learning one you'll probably be able to pick up the others relatively easy. In this course we'll be focusing solely on the Three.JS library. Three.JS provides a lot of functionality that makes it very easy to develop WebGL applications. Three.JS provides the following high-level functionality: all the graphical primitives you might expect and you have the ability to manipulate these or also create your own shapes entirely from scratch. You can load models from the most popular 3D modeling formats. Three.JS even has its own format optimized for the web. There's a number of useful math and geometry functions, limited effects such as fog and particles. You also have the ability to work with something called a shader. Shaders are a big topic in themselves that we won't be covering in this course, but you can think of a shader as a graphical processing unit that can manipulate the position and color of elements on the screen. You can create some really cool affects with these and they run directly on the GPU. Three.JS's primary focus is rendering content on the screen, but also contains some basic collision detection functionality that you might use in games for example. Three.JS's documentation is certainly something of a work in progress, but it does contain a heap of really great examples you can refer to. Finally, Three.JS has a growing community. If you have any queries, head over to site such as, Stack Overflow. Three.JS was originally developed by a guy called, Ricardo or more commonly as he's known, he's alias mrdoob. Around 2002, Ricardo was very interested in the demo scene where programmers and graphical artists would create exciting demos to challenge themselves and show off their skills. Ricardo would work with programmers to produce demos for a scripting system or editor. He soon realized however, that this approach had some limitations and became interested in developing the skills needed himself. The first release of Chrome demonstrated how quickly JavaScript applications could run and this drew Ricardo to experiment more with HTML 5 and related web graphical technologies such as SVG and Canvas. Ricardo also liked that these technologies were operating system independent. He then released a version of Three.JS, which at the time was called, Three.AS. Three.AS contains support for Dome, SVG, and Canvas based renderers. Abstracting the rendering was a good move, as it made it much easier to add WebGL support later. Ricardo sums up his motivation for developing Three.JS, as needing a 3D library that suited his needs and realizing this could be useful to others as well.
Course Outline
What we will cover. This course is very much an introduction to Three.JS. I won't be talking to you much about topics such as, OpenGL and Hardware. There's already many excellent courses covering these areas in great detail. That's not to say it's not useful to have a good knowledge of OpenGL or how things are working behind the scenes, but I believe you can accomplish a lot without having to know these in detail. I aim to provide you with a toolbox of concepts and techniques that will contain everything you need to create simple applications and games. This should set you on a good starting to move forward with 3D programming on the web in the future. There's always more to learn. Right now I'm learning more about 3D modeling application called, Blender and another topic called, Shaders. On this course I won't assume you have any advanced math knowledge. Don't worry, I don't either. You will however need a working knowledge of JavaScript. Three.JS has a JavaScript based API. If you only have basic JavaScript skills and you're not familiar with topics such as passing functions around and closures, you may wish to refer to some of the other excellent Pluralsight courses on these areas. I've tried to keep the examples as simple as possible. For me there's nothing more irritating than trying to learn a topic and have an example with a lot of noise. This can of course lead to some simplistic examples, but don't worry, we'll be putting together something more complex towards the end of the course. So what do you need to get started? Well, not much as it turns out. You'll need a web browser, some kind of web server, and a simple text editor. Regarding which web browser to use, although there is WebGL support in the latest version of all the major browsers including Internet Explorer from version 11, I'm going to recommend for this you use Chrome. Chrome currently probably has the best support and debugging experience. Some examples will load models or textures and to get these to run properly you're going to need some kind of web server. I'm working on a Windows platform so I use IIS and virtual directories for this. The Three.JS site has some great instructions on how to set things up using Ruby and Python based web server solutions, if these are preferable to you. The Three.JS libraries and complete source are contained at three.js.org and you can download or reference just the libraries or the complete source from GitHub. I highly recommend you download this source at some point, as there's some really great examples that you can refer to. It's important to note that this course uses the R67 release of Three.JS. You may find in the future that some of the APIs have slightly different names. Before we get started I wanted to recommend a couple of links I found really useful for learning Three.JS. The first of these is a really great book called, 3D Programming for kids. Don't let the title put you off. It's a great resource and it will get you up to speed very quickly. It's the sort of book you can read in the weekend and I won't tell anyone if you've read it. Learning Three.JS is another great book. It's a good reference for those that want a good general understanding and --- and reference guide to Three.JS. The authors also put all the examples from their book on the website and some really excellent examples to refer to. The other set of examples I found myself referring to regularly are provided by a guy called, St --- Stemkoski. Please forgive my pronunciation. These are used in an earlier version of Three.JS, but they remain a great reference. Okay, time to get started with our journey into Three.JS.
Three.js Building Blocks
Three.js Building Blocks
Hi, I'm Alex Mackey, welcome to Pluralsight. In this module we'll be talking about the building blocks of Three.JS applications. Now that we have discussed the background around WebGL and Three.JS, it's time to get started creating our very first Three.JS demo. As it's our first, it's probably not going to win any design prizes or set new standards in 3D, but it will demonstrate how easy it is to get started and give us a good foundation to build on for the future. In this module we'll be running through the following, we'll be looking at the basic building blocks or components of any Three.JS application. We're going to be putting together a Hello World style demo. This will display a red cube on the screen. We'll take a quick diversion into looking at the Three.JS coordinate system. We'll look at something called Object3D and all the properties and methods available on this object. We'll look at how to change an objects position, size, and rotate it. We'll look at the effect that these changes can have on any child objects. And then finally, we're going to wrap up looking at some common mistakes that those new to Three.JS can make and hope that we can avoid them. I like to think of Three.JS applications as being bit like a movie. To film any movie we need four main components and Three.JS is no different. Pretty much any application you develop will need the following: a scene, a camera, lighting, and actors or objects for our scene. It can get a bit tedious to create these objects every time you want to develop a Three.JS application so you'll probably want to create some kind of Boilerplate app of these setup already. If you refer to the downloadable examples for this module, you'll find I've created a Boilerplate app to help get you started. Okay, let's get back to our demo. We'll create a very simple application that will display a red cube on the screen, which probably is one of the simplest things that we can created. The first thing we will need to do is to create an HTML page to display our content. I've created one already called index.htm. I've also created a folder called scripts to put all my JavaScript in and keep everything organized. We are of course going to need the Three.JS library so if you haven't got this already, head over to the Three.JS site and download it or you'll also find it in the examples folder for this module. Let's add a reference to the Three.JS library in. We will also split out our scene setup logic into another file in the scripts directory called, "app.js", which we will reference now. (Typing) On our page we will need to add an element to render content into. I'm going to add a div with the id "webgl-container". (Typing) Okay, let's switch over to app.js and continue setting up the scene. In app.js I've created a self-executing JavaScript function, which when executed will assign the results to the variable example. You don't have to set right your scene setup logic using this pattern, but it has many advantages such as stopping objects clobbering global scope and it also tends to keep everything neat and modular. I've also turned on JavaScript script mode, which will help catch some common errors. You can learn more about this and other pa --- patterns in other Pluralsight courses. The first object we will create is a scene. (Typing) In Three.JS a scenes main purpose is to act as container for all the other items that make up our application such as a camera, lights, and any objects that we want to display. Once we've added our scene we will also create a renderer. (Typing) A renderer tells Three.JS how content will be displayed on the webpage by specifying the type of renderer to use. Three.JS supports a couple of different types of renderer's that can provide full back options for older browsers that don't support WebGL, but for now we will stick with the WebGLRenderer, which is the most performant and feature rich of all the renderer's. Before we get on with adding a camera to our scene, we need to take a little diversion and talk about coordinates.
Coordinates Refresher
Three.JS uses the Cartesian coordinate system. This system has been around since the 17 century and was invented and named after Rene Descartes, who I'm undoubtedly pronouncing his name wrong. The Latin version of Rene's last name is Cartesias, in case you were wondering where the Cartesian bit came from. You'll know doubt have come across this system before. Maybe when you're plotting simple graphs, which generally have two axis. These axis can be referred to the X and Y axis. If you have trouble remembering which is which, I like to think of X as across, as in across the screen. Or perhaps you've used this system when playing a game of Battleships when you reference various quadrants. Normally when placing graphs in this format, 0 for the X and Y axis will be in the bottom left-hand corner. This can be referred to 0, 0 and it's sometimes called the origin. If you've done any work with CSS, you'll know that the origin moves to the top left-hand corner. Three.JS and WebGL for that matter, I'm afraid change this and use yet another model with the axis crossing over in the exact center of the screen. And of course, as we're working in 3D we're going to need another axis to represent the objects depth position. The third axis is called the Zed axis. Using these three axis we can now refer to any position on the screen, using three numbers to represent the X, Y, and Zed axis. This can be referred to as a Vector and contains all the information we need to position an object anywhere on the screen. For example, 0, 0, 0, refers to the exact center of the screen or the origin. A X+ value such as, 50, 0, 0, would position an object towards the right of the origin. A X- value e.g. -50, 0, 0, the object would move to the left of the origin. What is it if you had a -X and Y value such as, -50, -50, 0? The object would move to yet another position. If you need something closer to the camera or viewer, you can increase the Zed value. And to move an object further away, decrease the Zed value. When you add objects to a scene in Three.JS, if you don't specify a position the object is always added to the scene exactly dead center at 0, 0, 0. But don't worry; you can always move it around later. This means that if we had a cube that the width, height and depth of 10 and we don't specify a position when adding it to the scene it would be added exactly in the center. Which means the top of the cube will actually be at 5Y and the bottom at -5Y. This can confuse a few developers new to Three.JS, who would be expecting the cube's top to be at 10Y. Okay, now we've covered coordinates, let's get back to our movie.
Camera and Rendering Options
Let's continue setting up our scene. We're going to need some new objects. Here I'm going to create a new light and also variables to hold the camera and the box that we create. As I'm going through this example don't worry too much if you see things that you don't understand, as we'll be covering all of these items in detail. Next up I'm going to create a function to initialize the scene. (Typing) Okay, we now need to tell the renderer what size that we'll be rendering content. (Typing) And we're going to tell it where to render the content. (Typing) And we're going to need to add our light to the scene; otherwise we're not going to see too much. (Typing) And now we're going to initialize our camera. (Typing) And we'll add the camera to the scene as well. Now I'm going to take a short diversion to talk about some of these options when setting up the camera. When we created our camera we needed to specify a few values about how it was set-up. The first of these is the FOV, or the camera frustum vertical field of view. This is the vertical field of view from top to bottom of the screen and is specified in degrees. Changing this is a bit like changing the lens on the camera. For most purposes values of between 35 and 45 seem a good match. You might want to modify this however, for certain scenarios such as games. The next parameter we specified is the aspect ratio. And this is similar to the aspect ratio on your TV or monitor. Usually this is the width divided by the height of the container. You can calculate this using the window object if you're using the whole screen to display your Three.JS application. But if your Three.JS application just takes up a portion of the page, you'll need to modify this to be the containing elements width and height. If you don't you're going to get some funny issues, particularly when we come to interact with the scene. Next up we need to define the near and far planes. Only objects that are inside this range will be rendered. These values can be quite useful for performance reasons, as it means that Three.JS doesn't need to calculate stuff that's outside these boundaries. When we add in our camera by default it's going to point to the -Zed access, so be looking into the screen. We can modify this using the LookAt method, but we're going to leave it alone for now. Three.JS has two main types of camera: a perspective camera, which is the one we'll be using for most of this course, and also another type called an autographic camera. This example here shows an autographic camera. An autographic camera doesn't display perspective, but it can be useful for certain types of scenarios where you want kind of an isometric view, maybe something similar to SimCity. And don't think that you're constrained to using just one camera. Here's an example I created of space invaders and I've got multiple cameras on the same scene here, which can give you some interesting effects for games. In our example we specified that we'd be using a WebGL renderer. Three.JS is of course best known for rendering content in WebGL, but the renderer is actually separated out from the rest of the framework, meaning it's possible to render content in other formats. And I guess there is nothing to prevent you from creating your own renderer if these don't suit your purposes. Out of the box Three.JS supports three main types of renderers. There is of course, the WebGL renderer. This is the most feature rich of them all and also the most performant. There's the Canvas renderer and also the SVG renderer. SVG isn't part of the core library, but it is available in the examples folder. It's worth noting that the Canvas renderer doesn't support all the features that WebGL does, but it might provide a full back option for those using older browsers. Okay, so first what I'm going to do is to just start data wrap application so that it will work on older browsers that support Canvas, but don't support WebGL. So I'm going to take the initialization of the renderer here and I'm just going to place it with this bit of code here. What this does is just for the existence of the WebGLRedereringContext, and if that exists then we need WebGLRenderer, otherwise we're going to use the Canvas option. Now let's add some stuff to our scene. I'm just going to add in a simple cube to the scene. And write in our cube or box there. And don't worry too much about this because we're going to be covering this in later modules, but what we're doing in this parameter is defining in the dimensions of our cube and the second parameter we're defining the material or the sort of covering of the cube. In this case we're just going to cover it with a red color. We're going to give the box a name, I'm going to call it "box". This just makes it a bit easier to find for debugging purposes. Now the next thing we need to do is to tell Three.JS to actually render our scene. So I'm going to create function here and I'm going to call it render and I'm going to go and make a call to renderer.render. And this is a recursive function so it's going to call itself. And we're using a requestAnimationFrame, which is something that's been built into modern browsers now. And this will insure that the animation is as smooth as possible. Now there's a couple --- extra little bits we need to do. We need to kickoff our scene initialization and just do this with the window onload function for now. And on the --- once we set up our scene here we're going to call a render function there. Now the final bit you don't have to do, but I do recommend --- you might want to consider it. And I'm just going to go and expose my scene object here. And my reason for this is it's for debugging purposes, as if things don't work it could be quite useful to get a hold of the scene objects and go check on the status of various variables and properties. Okay, let's see if this has worked. Hurray! The red cubes appearing. All looks good. And just to prove to you this is actually a cube, I'm just going to rotate this cube. And don't worry too much about this we're going to be covering this in the next module, but I'm just going to rotate it on its Y axis, a small amount, each time the render leap's called. There we go, rotating cube. Congratulations, you've just created your first Three.JS application.
Object3D
So I want to talk to you about an important class called Object3D. Now Object3D is the base class for many of the objects that will be added to a Three.JS scene. This contains a number of properties and methods that you're going to find yourself using a lot. Now here we are at the three.js documentation. It somewhat makes the quality of this documentation and you're going to find some methods that aren't documented at all. One of the great things about the documentation though, is it provides an easy way to link through to the actual source code. So if I scroll down to the bottom of this Object3D class for example, I can click the link here and I'll then be taken to the source of the Object3D class in GitHub. So when you're trying to understand Three.JS, this can be a very useful way of getting a real in-depth understanding of how things are put together. Let's talk about some of the important properties on Object3D. First up id, id is the unique number of the objects instance and will be assigned automatically by Three.JS. You can retrieve properties by id if you want. uuid, is a unique identifier again, created automatically by Three.JS for you. We have the name property; we used this earlier in our demo when we labeled our cube "box". You can retrieve objects by name. position, this is a Vector representing the ob --- objects current location in the scene. userData allows us to hold metadata or information on an object instance. For example, in a game maybe you'd use it to hold the score the player would receive for destroying the object. Finally, we have the parent/children properties. Scene objects in Three.JS are hierarchical and ca --- contain an unlim --- unlimited number of children. The child/parent properties allow us to navigate this hierarchy. There's also some important methods you will use in lots of applications. getObjectByName allows us to retrieve an individual object by its name. It's important to note however, that Three.JS by default won't search an objects children when you use this. If you do want to search all an objects children then in addition to the name you'll need to pass in true. getObjectById works very similar to name, but searches for an object by id. lookAt will allow you to rotate an object to face a Vector. So let's play around with some of these Object3D properties and methods. So I'm going to expand our example window there and Refresh that. And I'm going to bring up the browser tools with F12. Now I don't know if you remember, but one of the things we did in our example object was expose the scene properties so we could get at it later. And what we can do is I can enter an example into the Console there and I expand that out and I can see my scene object that we exposed earlier. And we can look through the first properties here and go and explore them. So for example if we expand the children Array there we can see that there's actually three items here. And you might have been expecting to see just one, which is the cube, but we actually have the Lights, the Camera and indeed the cube or Mesh itself. We'll see some of the other properties we were referring to such as the id and a couple of other ones throughout there. If we want to go and get an individual item I could do 'var box = example.scene' and we'll go 'getObjectByName'. (Typing) And we'll go ('box'). And then if we go and look at box we can see we've we have our box or cube instance there and the various properties. We can go and manipulate this if we want to. (Typing) And let's go move this up slightly. And move it up a little bit more so we can see it better. We can move it over to the right (Typing) or we could move it over to the left. So by exposing objects this way it's quite useful to be able to debug them if you have funny things happening with your application if you want to do some experimentation. Now the next thing we're going to look at is how to go and manipulate our objects and change their size, position, and rotate them.
Modifying Position, Size, and Rotation
We will now look at how to manipulate objects. We'll look at how to change their position, how to modify their size or scale, and how to rotate them. There's a number of different ways of specifying an objects position; here are the main ones. We can specify its position on an individual axis. We can specify its position on all three axis. Or we can assign a new vector free object to specify an entirely new position. To resize an object we use the scale property. Scale is declared as factors relative to the original size of the object. If for example we had an object that was 10 units along its axis, changing the X axis scale to 2 would now make it 20 units long. Changing the X axis scale to 2.5 would make it 25 units long and so on. Changing an objects scale is often needed if we're importing a model from a 3D package. We can modify sc --- an objects scale in a similar manner to position in an object. We can specify it on an individual axis or on all three axis at once. Rotations are a little bit more complex than changing an objects scale or its position. Rotations can be performed around all three axis and there manipulated using radians rather than degrees. Some of you may be wondering what a radian is so let's talk about this before we look at how to rotate an object. A Radian is measured by taking the center of the circle and then drawing a line to its edge. Let's call this distance R. Now if we were to measure this on a bit of string and then wrap this around the edge of the circle, this would be one radian. There's roughly 6.28 radians in a circle, which is 2 * pi. Don't worry about his too much though, as a simple way to convert degrees to radians and I for one find degrees much easier to work with. Let's look at how to do this. To convert degrees to radians simply multiply the number of degrees by (pi/180). And if for some reason you need to reverse this you can simply multiple the number of radians by 180 and then divide it by pi. Let's go back to our rotations. An object can be rotated on any of its three axis. I like to imagine each axis as pole stuck through the object. So with default positioning the Y axis would run up and down the screen and an object rotated around this would spin around the pole. One thing that can confuse people about rotations is that once an object has been rotated its internal axis is also rotated. We're going to take a look at this shortly. I've created a nice demo here for playing around with position, rotation, and scale. I've also used an additional class called, axis helper, which allows us to visualize an objects internal axis. In the right-hand corner here there's a number of controls here that allow you modify various properties. These are created using a nice library called, dat.GUI that provides a visual interface for properties. If for example we wanted to play with the cameras Zed position, we can take this here and we can move this in and out to adjust this property. We could move the camera up or down a little bit. And we can rotate it around the Y axis. Let's position it a little further down. We could change its Zed rotation. And you can see the affects this various changes have. And one of the things I want to demonstrate is how an objects internal axis will change when you go and modify its properties. Si I have the cube here, I'm going to rotate it around the Y axis. And you can see there these lines coming off it represent its individual axis. Let's perform an X rotation on the cube. And again, you can see these axis also change. And this (_____) has implications if you were to move the cube about in your scene and it might behave not quite how you're expecting. Using classes such as the axis helper can be very helpful for visualizing how this will work. Let's play around with the scale a bit. So I'm going to reset the scene and we're going to go in and increase the cubesYScale. And you can see it appears to grown. One of the things I also want to show you is that it's actually growing beneath the ground here as well. So if we zoom out a little bit, we can see that its positioning is also growing. I encourage you to play with around with this application until you're quite happy how all these properties work. Before we move on from transformations, I just want to talk a little bit about how Child Objects will respond to scale, position, or rotation modifications. Now I've also added a green cube to the scene as a child to the main cube. If I'm to modify the main cubes XPos, note how the child also follows it. If I modify its YPos, again it will follow it. This will also happen if we were to rotate the cube. So all these transforms will also be performed relative to the parent on any child objects.
Common Problems
There are a few common mistakes that every developer new to Three.JS will make and I'm almost 100% certain that at some point you will find yourself making one of these as well. One of the hard things about graphics programming is that instead of a nice syntax or compile time error, your scene just might not appear at all or maybe it just doesn't look quite right. So first up, if nothings appearing I suggest you head over to the browser tools. Check if you have any error or syntax messages. You might also want to check the network tab to check all resources are loading properly. If everything looks good then it may well be due to one of the following issues. The first of these I call, 'It's behind you.' It's surprisingly easy to position an object behind or even position yourself inside the object. Secondly, forgetting to add lights. Depending on the materials you are using for your objects, and we'll be talking about this more later, unless you add a light to your scene then objects will not display. It also might be that your object hasn't been illuminated by a light if you're using more advanced lighting features. Finally scale, particularly when working with imported objects you can sometimes import the object correctly, but then forget to increase the size so its actually visible to you.
Summary
We have covered a lot in this module. We looked at how all Three.JS applications contain a renderer, a scene, a camera, and a light object. We looked at Object3D and some of the properties and methods available on this object. We looked at the hierarchical nature of Three.JS objects; how to position, scale, and rotate objects. And finally we wrapped up by looking at some common issues and how you can avoid them.
Meshes and Geometry
Introducing Meshes and Geometry
Hi, I'm Alex Mackey and welcome to Pluralsight. In this module we'll be talking about Meshes and Geometry. You can think of these as being the skeleton or framework for our 3D objects that we will display on the screen. In this module we will be covering the following. We'll be introducing you to the concept of Meshes, Geometry, and materials. We'll be checking out some of the inbuilt shapes or Geometry supplied out of the box by Three.JS. We'll cover how to create Geometry from scratch. We'll look at how we can modify and manipulate existing Geometry. And finally we'll wrap things up looking at how to load and export Geometry. First up let's talk about Meshes. Meshes are actually made up of two different things. Geometry: Geometry's a bit like a scaffold for a shape and it's made up of an array of X, Y, and Zed coordinates called, vertices. These define a location in 3D space and the shapes boundaries. There then linked together (_____) faces. The second item that makes up a Mesh is material. And materials define a covering for our skeletal structure. There are lots of different types of materials in Three.JS. For example, you could create a dull, mate-like material or a shiny, slightly transparent material. Materials are a big area and have their very own module, which will be coming up next. Let's not get ahead of ourselves and let's talk in detail about Geometry. I want to refer to the demo we created in the previous module. As part of this demo we created a cube with the following code. Note how that when we did this we gave the Mesh function two things. First we defined the Mesh by specifying the Geometry we wanted to use. In this case, we use the Box . --- Geometry. Secondly, we defined the material we wanted to cover our cube with, in this instance, the MeshBasicMaterial. MeshBasicMaterial is probably the most basic of all materials in Three.JS and it doesn't respond to light at all. In fact, we could remove the light from our scene and our demo and the cube would still be visible. Let's take a closer look at what makes up a Geometry. Geometries are made up of two things: vertices and faces. Vertices define a position in space and are specified as X, Y, and Zed coordinates. In this example, here's the coordinates to represent a triangle. Faces then connect these points together. There are a number of different types of geometries that you'll encounter when Three.JS: Inbuilt Geometry, Custom Geometry, and geometries exported from Three.JS modeling packages. Let's look at the inbuilt geometries first.
Inbuilt Geometry
Three.JS has a large number of inbuilt geometries specifying pretty much every basic shape you can imagine. I like to think of these as being a nicely wrapped-up package ready for us to use. Here's a simple example I created showing some of the Inbuilt geometries in Three.JS. Three.JS defines a large number of geometries and shapes ready for you to use. And you can find instructions on the Three.JS documentation about how to use each of these individually. I want to talk a bit more in detail about the CircleGeometry. I'm going to go the source of the CircleGeometry. All Inbuilt Geometry in Three.JS will make a call to the THREE.Geometry class. It will then define individual vertices. And then how these link together with faces. If you find you need a particular shape a lot, you could always create your own Geometry in a similar fashion. Now CircleGeometry was a nice simple example, but as we are working in 3D, let's talk about SphereGeometry instead. Most of the Inbuilt geometries have two main types of properties. The first will be a size related property, and this will define how large the shapes should be. As we've seen already, you can modify this later with the scale property. When working with the SphereGeometry this property is radius. The second and third parameters allow you to specify the number of segments the object is made up of. The more segments you make an object the smoother the shape will be. However, this comes at a cost as it will require more resources to render and manage. There's a balance when specifying this and there's a point where adding more segments won't add anymore detail to a shape and you're just wasting memory if you do so. Let's look at an example of this now. So I have a simple example here or a rotating sphere. And our sphere is looking a bit square at the moment. This is because it's not made up of really enough segments to show a circular shape. Let's sort this out now. (Typing) We'll Refresh our example. That's better. It still may be looking a little bit blocky though, so we can do better than that. (Typing) As you can see this is a much more complex and smoother shape. Now one disadvantage of this is it's going to take a lot longer to render and is more expensive to manage. You may want to look at how this will affect your applications performance. And a great way of doing this is using the stats library. The stats library is separate from the main Three.JS library. Let's include it in our application now. So I've added in a reference to stats.js in my index.htm file. And the next step to setup stats.js is we need to define where its control panel should be rendered. And I'm going to do this just after I add the sphere to the scene. (Typing) And let's format that so we can see it a bit better. And then I'm also going to need to make a call to stats.update in my rendering loop. And if we Refresh this, now we can see in the top left-hand corner we now have a nice stats counter showing the frames per second and also a nice graph being generated below. Now we should find if we go and simplify our sphere that this counter increases. So we'll put this down to just one segment, a very simple sphere here. And we'll Refresh that and it really doesn't look too much like a sphere, but we should find the frames per second count jump up there as it's much more simpler to render. And if we go and start increasing the complexity of our shape, --- so let's put this back up to 150 there. We'll go and Refresh it, and we should find the frames per second count will fall gradually. And if we increase it to quite a lot more, (Typing) because we have a very complex shape now, we'll find that it will take a lot longer to render. The frames per second count has now fallen to the twenties. And when you're developing your applications and games you might want to add this stats.js library. Just go and find that right balance between level of performance and detail within your scenes. A stats.js can be a great way to do this.
Creating Geometry
Let's talk about how to create geometries. Now in addition to using all the Inbuilt Three.JS geometries, we can also define our own Geometry and build a shape from scratch. Maybe Three.JS doesn't contain the shape that you need or maybe you're just creating some cool demos or affects. We'll do this be creating the simplest shape possible, a triangle. I have some code here that setups a typical Three.JS scene and rendering loop. Now the first step in creating a shape from scratch is creating a new instance of THREE.Geometry. Next up we'll need to define our shapes vertices. (Typing) And then we need to define how these link together. (Typing) And then next up we need to create a new instance of THREE.Mesh. Now previously when we've used THREE.Mesh, we've been using Inbuilt geometries in Three.JS, but this time we're going to use our triangle Geometry that we've created. And the final step that remains is to add this to the scene. (Typing) Note I haven't specified a material here. Now if you don't specify a material, Three.JS will create a new THREE.MeshBasic material for us with a random color. Let's see if this has worked. Hurray! A nice triangle appearing. Let's take a look at how we can modify the colors on the vertices. So the first thing we need to do is create new material. Now this is special material, and we're telling Three.JS to use the vertex colors in this case. And we're also specifying our material will be DoubleSided. The reason we specify it will be DoubleSided is because if we rotate our triangle it wouldn't be visible on the other side otherwise. Next up we need to tell Three.JS to use different colors for each vertice. (Typing) And we're going to add this in here. (Typing) And what we're doing here is we're specifying the color to use on each vertex. Now we're just using red for two of them and green for the other one. And Three.JS will kind of shade in-between or int --- interpolate the values between them, which can create quite a cool effect. Now the final thing we need to do is to tell Three.JS to go and add in this --- to use this new material that we've created. Just add that in now. (Typing) Let's go ahead and have look at what this looks like now. There we go; we have our nicely shaded triangle now. And you can see how very easily you can create some quite cool effects and demos. Next up let's look at how to modify existing Geometry. So in addition to creating geometries from scratch, you can also modify geometries that have already been added to the scene. You can use this to create some cool effects and animation. Let's do this now by creating a simple wave effect. Here's the demo I've created for a wave effect. What I've actually done is just add a plane, which is just a flat shape, and I've just iterating through the vertices modifying their position. Let's take a look at the code for this. So the code to setup this demo isn't really important, but I do want to draw your attention to two areas. The first of which is where it says, 'plane.Geometry.verticies{i}.z+=increase'. What we're doing here is in this loop just iterating through all the vertices in our plane Mesh and then going and modifying them. The other area I want to draw your attention to is where it says, 'plane.Geometry.verticesNeedUpdate. Now any time you play around with a vertices' position you need to make sure this is set to true, otherwise you won't see the results on the screen. As you can see it's pretty easy to go and modify existing Geometry. Now one thing you should be aware of is this is actually quite an expensive thing to do and there are better ways to do this through something called, Shaders. In addition to modifying a Meshe's Geometry manually, you can also perform a type of transformation called, an extrusion. So what I've got here is some code that just sets up a simple triangle. And we can use extrusion to go and sort of pull-out the shape, if you will. So I'm going to extrude the shape by 15, and let's go and refresh this. And you can see our flat triangle has now become 3D. And we can specify the amount of steps or sort of level of detail to do this with. Let's increase the amount a bit more so we can see that a bit better. And then we'll Refresh this. And you can see you can get some quite cool effects with the extrusion settings. Before we move on from modifying Geometry, I just want to draw your attention to a couple items you might find useful. The first of which is GeometryUtils, which contains a number of useful functions for modifying Geometry. Another very useful library is called, csg.js. Now this allows you to add two shapes together and then specify various interactions in order to create an entirely new shape. So for example, you can union shapes together, you can subtract shapes, or you can take the intersection of a shape all to produce an entirely new shape. Of course there comes a point when you're really better off working with a 3D modeling package. Let's look at how Three.JS can load various modeling formats.
Loaders and Exporters
As awesome as all the Inbuilt functionality around modifying and creating geometries are, it would take a very long time to create something more complex. More complex models are of course, designed in 3D modeling packages. . . . Three.JS supports a number of different modeling formats. In order to use these you'll need to add a reference to the loader you want to use. Now if you aren't using the Three.JS model format, which we'll come back to in a minute, you're going to need to add a reference in to the particular loader for your format. And you'll find a lot of different loaders in the examples folder, (Typing) js, loaders. And you'll see there's various loaders for pretty much every format you can imagine. So I'm going to load an existing model from the Three.JS examples folder. And you'll find a number of models there. So the first one I've done is I've invited a reference to the particular loader that I'm using. And then in my 'app.js' I'm creating a new instance of the loader. I'm specifying that I want to use the 'convertUpAxis' option; otherwise our model is going to be loaded upside-down in this particular instance. I'm then making a call to a 'loader.load' and I'm passing in the path of my model. Now you need to give this function a call back, because it could take a bit of time to load some models, particular a really complex one. And in our call back we simply specified that we're going to be adding this to the scene and call the render. Let's see what this looks like. Great, there's our model loaded now! Pretty scary looking thing. And if he can appreciate that there's really no way you could create this type of model Three.JS primitives. Now don't think that you need to be a 3D artist to play around with this type of thing. You'll find there's a number of different models available in the Three.JS examples ready for you to play with. And in addition there's various sites which offer 3D models that you can download and use in your applications. Now their divided by different types, and you'll find that they all have different licenses. So quite a lot of them you won't be able to use for commercial purposes, but it does mean that you don't need to be particularly artistic in order to make some pretty cool scenes. Next up let's look at Three.JS' own format. So although Three.JS does have support for various 3D modeling package formats, it's really not the best format to load. The reason for this is is they were never really meant for the web because they can be quite large. Additionally, some web servers may require you to specify something called a MIME type before they'll serve them up correctly. The best way to load models in Three.JS is using Three.JS' own modeling format. This is specified in the Three.JS wiki. Three.JS supplies a number of different converters, which you can plug-in into your 3D modeling applications to export your models in Three.JS' format. Let's see how to do this now with an application called, Blender. Blender is a free open source 3D modeling package. It's available on a number of different platforms, making it a great way to get started with 3D modeling. Probably the only downside to Blender is it's probably not the most friendly of applications, and it can be quite tricky to get into if you don't have a 3D modeling background. I'd advise you to look at the numerous tutorials online in order to get started with Blender, before trying to anything too complex with it. Okay, let's look at how to export a Blender model to Three.JS. One of the great things about Blender is its extendibility. Now to install the Three.JS exporter for Blender if you go to the Three.JS source you'll find instructions on how to do this for your operating system. Now depending on which environment you're using, you'll basically copy the Addon folder to a particular location and then you'll go into the Blender User Preferences, Addons and add this in. Just remember when you're copying the addon to copy the whole folder, otherwise you won't see it in the Addons menu. So here we are in Blender. Now let's just delete the default cube, as that's a little bit boring. And one of the nice things about Blender is that it gives us a monkey head out of the box. So I'm going to the Add menu, Mesh, and then select Monkey. And we'll see that it's added the monkey to the center of the screen there. And we can see this is a reasonably complex shape already, so it's great for our purposes. Now if you've added Three.JS exporter into Blender you should find when you go to the File, Export menu, you have a new option, Three.js. So if you know go and Export your monkey head to somewhere on your hard drive, and we'll look at how to load it next. Okay, let's get on with the important business of loading up our monkey head. Now the first thing I want to show you is that in my index.html file I haven't had to reference any additional loaders, and that's because out of the box Three.JS understands how to load its own modeling format. The other one I want to show you is our exported file from Blender. Now some of these concepts should be looking pretty familiar by now, so we can see within here we have vertices specified and faces. Okay, let's load up our monkey head. Now the first thing we need to do is create an instance of THREE.JSONLoader. And then, like the previous example, we call loader.load, pass in the path of our model and then a call back function. In this particular example we're going to specify the material ourselves as a simple wire frame material, and then we're going to create a new Mesh based on the loaded Geometry and our created material, and then finally add it to the scene. Let's see what this looks like. And there's our monkey head all loaded up. You can see how easy it is to create, export, and load a 3D model in using Three.JS and Blender.
Exporting Geometry and Scenes
Now the final thing we're going to look at in this module is how to export Geometry and our scenes. Three.JS allows you to easily export individually geometries and your entire scene setup. First up let's look at how to export a Geometry. The first thing we need to do if we want to export a Geometry, is add a reference to GeometryExporter.js. And you'll find this script in the three.js source examples exporters folders. Let's add this reference in now. And then we need to go to our code and I've setup some simple code here, which just has a sphere. And we're going to go and export this sphere now. We need to create an instance for our exporter class and then we need to tell it that we need to go and parse the Geometry of this sphere. (Typing) And then we can serialize it by using the JSON.stringify method. And then we can do whatever we'd like with it. So maybe you'd output it to a file somewhere. Maybe you'd put it in local storage; whatever you'd like. So just to demonstrate it's working, I'm going to go and output this to the console here. (Typing) And let's go and take a look at our example now. So I've added a debugger statement here just so we can step through what's happening here. So the first thing we do is we go and create our instance for exporter, and then we tell the exporter to go and pass our sphere's Geometry there. And then if we look at this object here, we can see it contains all the information about sphere's Geometry. And then what we do is we go and stringify this using the JSON.stringify method. And then we'll output that to the console and you can see here we have a collection of vertices. And then you might go and stick this in local storage. Maybe you save it to the server, something like that. So you have a number of different options there once you have it in this format. Let's look at how to go and load this Geometry once we've exported it. Loading the Geometry is very easy. First up just create a new THREE.JSONLoader, tell the loader to parse JSON and then create a new instance of the Mesh, passing in the Geometry and any materials. And finally you can add it to the scene as (_____). Next up let's look at how to export an entire Three.JS scene. Now the Geometry exporter only exports one individual shape or Geometry. And there's going to be times where you might want to export and load your entire scene and for this you need the SceneExporter. So to use this, simply include the SceneExporter and then your code to create new instance of THREE.SceneExporter, tell it to parse your scene and then you can work with it in the same way as the GeometryExporter. Now before we wrap-up this module, I just want to tell you about the Three.JS editor. This is a nice visual editor for your scenes and can be quite useful for experimenting. I can add in various shapes. I can select them. I can play around with their position. (Typing) We can change their Scale. And we get this nice GUI for playing around with this, and then if we want we can go and Export them. So for example, I could Export individual Geometry or I could Export the entire Scene. And then I could load it in using the method shown previously.
Summary
We covered a lot in this module. We looked at the out of box Geometry supplied by Three.JS. We looked at how to create our very own geometries from scratch. We looked at how you can modify existing geometries. And we wrapped-up this module looking at all the different 3D modeling formats that Three.JS supports, and how to export individual geometries and scenes for later use.
Materials, Lighting & Textures
Introducing Lighting and Materials
I'm Alex Mackey, and welcome to Pluralsight. In this module we'll be looking at Materials, Lighting, and Textures. First up we'll discuss why we need materials and lighting, and why they're so important in 3D programming. Then we will look at some of the different types of materials we can use. And we'll be covering what I consider are the main three types, which are Basic, Lambert, and Phong. Next up, we'll look at how to create different types of lights and again, we'll cover the most important and commonly used types provided by Three.JS, which are Ambient, Point, Directional, and Spot light. Finally, we'll wrap-up this module by looking at how to load and apply Textures. And we'll look at some more advanced texture techniques such as BumpMaps. Our demos look very flat right now. Although we can see the shape on the screen is a cube, it doesn't look very realistic and it's a bit dull really. One reason for this is that the color is uniform across the shape and the cube cast and receives no shadows. We can solve these issues by utilizing Three.JS' lighting and materials functionality. Three.JS allows us to define a number of different types of lights and materials to make our scenes more realistic and interesting. Lighting and materials are closely linked, which is why I've combined them in this module. It's important to note that some materials and lighting affects will only work correctly when used in the right combination. For example, a shiny type of material called, MeshPhongMaterial, probably won't appear how you would want and expect it to when used with an ambient light source alone. Using different types of lighting can radically alter how a scene looks. For example, here's a picture of a street I took at sunrise, during the day, and at night time. Lighting adds depths and realism to our scenes, but there's also a bit more to this. Film and game makers have long known the importance of lighting and how it can be used to create different experiences and emotions. And you can make use of similar techniques in your demos and games. For example, maybe you're creating some kind of horror or zombie game; you probably won't want a bright daylight setup, as the game will appear a whole lot creepier in the dark. Lighting can also be used to create special effects and more realistic looking materials. For example, a volcano spewing lava would probably look a lot more interesting and realistic if it had some kind of glowing light inside it. Or maybe you're putting together a Sci-fi game and you want a light blue laser that glows in your scene. Okay, time to run through the Three.JS materials.
Materials - MeshBasic, MeshLambert, and MeshPhong
Materials are closely related to lighting. And by modifying the materials properties and lighting conditions we can give the same material a radically different appearances. Three.JS has three main types of materials you will find yourself using regularly. These are: MeshBasic, MeshLambert, and MeshPhong. They're also some other types, but these are more advanced and we will not be discussing them in this foundational course. There are some properties common to all materials I want to draw your attention to. These can be set when either initializing the material for the first time or after it's created at runtime. One thing to watch out for however, if you do modify certain properties at runtime, and properties of lighting for that matter, is that you may need to tell Three.JS you have changed these, otherwise you won't see its effects, but don't worry we'll come back to this (_____) shortly. Back to the properties. Color we've used already in our MeshBasic examples. One thing to watch out for is when using Phong or Lambert materials, color doesn't behave quite how you might expect. If you want to perform a similar affect to that of setting a color in a MeshBasicMaterial, but you're using a Lambert or PhongMaterial, you probably want to be working with the ambient property instead, but we'll talk more about this shortly. Side tells Three.JS whether to color or texturize the Front, Back, or both sides of a Mesh. There are performance benefits to not doing this to size that cannot be seen. Map allows us to define texture to use for a Mesh, and we'll be looking at this towards the end of this module. Note that you can specify both a map and a color. Transparency and opacity, you can make an object appear transparent by setting transparency to true and opacity to a value between 0-1. If you don't set transparency to true, and modify the opacity, you will see the object appear slightly lighter or darker. Visible is a Boolean value indicating whether the material is visible or not, and can be useful for debugging purposes if you need to hide, show a particular object on Mesh. Wireframe is a Boolean property we have used already in our demos and shows the boundary of our Meshes. There's also a number of other wireframe related properties that control the thickness of the wireframe lines. The first material we will talk about is MeshBasicMaterial. This should be like an old friend by now, as we've used this many times in our previous examples. MeshBasic is the simplest raw materials and it's completely unaffected by lighting. In fact, you could remove the lighting from the scene entirely and it will still be visible, which makes it very useful for demo and debugging scenarios. To create a new instance of MeshBasicMaterial is very easy, and note how we can pass in a property object into the initialization function. This is where you would specify details such as color, wireframe, etc. And all the materials work in a similar manner to this. The next time type of material I want to talk about is MeshLambertMaterial. MeshLambertMaterials have a dull, non-shiny appearance like pottery or maybe skin or wood. To see MeshLambertMaterials properly you need to use them in conjunction with certain types of lights. These are directional, point, or spot lights. Creating a MeshLambertMaterial is very simple, although you'll probably also want to specify two properties we haven't used before: ambient and emissive. Ambient allows you to specify a color that would be multiplied by the ambient light color of the scene. Emissive is a solid color unaffected by other lighting that defaults to black and can be used to alter materials appearance. Don't worry we're going to have a play with these shortly. The next type of material I want to talk about is MeshPhongMaterial. MeshPhongMaterials are shiny. So an example of a Phong-like material might be metal or shiny plastic. Like lambert, MeshPhongMaterial need to be used in conjunction with directional, point, or spot lights. Creating a MeshPhongMaterial is very simply and similar to previous materials we've looked at. MeshPhongMaterials however, allow you to specify some additional properties we haven't used; specular and shininess. Specular dictates how shiny an object is and the color of the shine; it's a default of a dark gray color. Setting specular to the same as the original color makes the material more metallic looking. Shininess, as you might have guessed, indicates how shiny the object is and a higher value will make the highlight sharper. Shininess has a default value of 30. Let's take a look at a demo of these materials now and play around with some of these properties that we've been discussing. So I've created a little demo here to allow you play with the MeshLambert and MeshPhongMaterials. The cube on the left is using a MeshLambertMaterial, whereas the cube on the right is using a MeshPhongMaterial. And you can see the cube on the right appears a slightly shinier than the other one and more influenced by the lighting there. So using this control panel on the right we can play around with some of these. So I'm just going to wait for that cube to rotate around, and we'll stop it just when the light appears to be shinning on it. And we'll stop it there. And by playing around with the shininess property, we can see the sort of different affects that this can have on the material. If we wanted to change the specular highlight color, so I'm going to go in into this here. We'll make this a red tint. And you can see the affects that doing this has on the light highlights of this cube. We could play around with the lightColor itself. And we'll go alter that. And you'll probably want to be a bit careful with this as it can tend to overpower some of the other changes you might have made. So put that back to white. We'll turn around, change around the emissiveColor of the cubes entirely. And you can see you can get some pretty cool effects by playing around with these. It probably will take you a bit of time and experimentation in order to get the effects that you want. Okay, time to talk about lighting.
Lighting - Ambient, Point, Directional, and Spot
Let's talk about the main types of lighting in Three.JS. Three.JS has a number of different types of light. We've already used the AmbientLight in our previous examples. Let's talk about the AmbientLight now. The AmbientLight affects all objects equally on the scene. There probably isn't a real world equivalent of and AmbientLight, but maybe you can consider it's being a bit like an office fluorescent light with equal brightness everywhere. Generally, AmbientLights are used in conjunction with other lighting types, and provide a base-level of light or color to a scene. You can create a softer AmbientLight by initializing it with a gray color. The AmbientLight accepts one parameter, which is the color. Next up is PointLight. PointLight is a special type of light that shines in all directions. It will only affect MeshLambert or MeshPhongMaterials. PointLight allows us to use two additional properties we haven't used before in our lighting examples; these are intensity and distance. Intensity is the light's strength and has a default value of 1. Setting this to two will make the light twice as strong, and so on. Distance specifies the distance value where the intensity will reduce to 0. And I guess affectively it allows you to modify a light's range. When we create a new PointLight we get the option of specifying intensity and distance values, but don't think you need to specify these, as if you leave them out then Three.JS defaults will be used. DirectionalLight is a lighting source will all the light appears to come from the same direction and doesn't fade over distance. A good real world example would be the sun. When creating a DirectionalLight you can specify the color and intensity of the lighting source. The final light source we will look at is the SpotLight. This is a bit like a theater or concert spot light and allows you to create a light with kind of a cone effect that will cast shadows in one direction. SpotLight has an additional property we haven't come across before, angle. This is specified in radians and specifies the extent of the SpotLight's cone affect. Getting the effect you want with a combination of lighting and materials can be something of an art form, and you'll probably have the play with the properties a bit to get the effect you are looking for. Okay, let's have a play with some of these lighting and materials now and see what we can do. I've created a demo to allow you to play around with some of the different types of lights and properties that we have been discussing. The white cube represents the current position of the light, and we can play around with this using the lightX, Y, and ZPos. We can change the type of light. Let's change this to be a Pointlight. We'll play around with the lightIntesnity, its Distance. Let's have a look at the SpotLight. We'll change the Angle of the SpotLight. Switch the Material over to be the phong material. Let's play around with the Color of the light. And so on. And you can have a play with all the different types of affects that you can create. Next up let's talk about how to enable shadow rendering in Three.JS. One aspect we haven't looked at so far is how to enable shadows to be rendered. Displaying an object's shadow is quite a computationally intensive calculation. Some developers have even developed alternative techniques to simulate this. Let's see now how we can enable shadows to be rendered. There's quite a few things that have to be set correctly for this to work, and so I like to look at stackoverflow alited with questions about how to get this working. I have some code here that sets up a Three.JS Scene consisting of some ground, a spinning cube, and a directional light. Let's enable shadows. The first thing we need to do is set the renderer.shadowMapEnabled = true. Next up we need to tell Three.JS that a light is capable of casting shadows. So we'll go to our night light initialization logic here, and we'll set light.castShadow = true. The final step is we need to tell Three.JS that our cube can cast a shadow, and we'll set cube.castShadow = true. Let's see if this has worked. There we have it; a simple shadow being cast from our spinning cube, but it looks kind of blurry. Let's see how we can improve this. Now I'm going to tell Three.JS we want a more detailed shadow. And I'm going to do this by adding the shadowMap property. Let's save this. And now let's take a look at the result, much better. You can even debug your shadows by setting the shadow camera visible property to true on the light. And this gives you an indication of how the shadows are being calculated on your scene.
Textures - Loading, Transparency, and Bump Maps
Being able to choose different types of lights, different colors, and specify when to use shiny or non-shiny materials is really great. However, let's say we want to create a red brick wall or a black and white stripped zebra model for our scene. Being able to set these sort of properties probably won't give us what we want for these particular scenarios. We can however use textures to accomplish this. (_____) texture is very easy in Three.JS. Simply use the THREE.ImageUtils.loadTexture method and pass in the location of your texture. One thing to watch out for is that textures load asynchronously. So if you're not working with a rendering loop, you'll need to ensure your texture has finished loading first before you render your scene. Okay, let's dry loading a simple texture now. So I have some sample code here and you've guessed it, it sets up a spinning cube in a typical Three.JS scene. One difference I want to call out, is where I create my material here, and I'm using MeshBasicMaterial, I'm using the map property to go and load the texture, which in this case is 'crate.gif', which I've taken from the Three.JS examples. Let's go and see what this texture looks like. And there we have it, our nicely textured cube. And you can see how easy it is to start building up some really interesting and complex scenes. Now another thing I just want to show you on the textures is that don't think that you can't use the other material properties that we've been playing with. So I'm just going to go onto the end here and I'm going to add in 'color' to the declaration of this material as well. We'll save that, we'll go and refresh this, and you can see that this color also got applied to the texture here. So you can create some quite interesting affects through some of this. Next up, let's take a look at transparent materials. Now you can also create transparent materials in Three.JS. And to do this all you need to do is specify transparent = true, in your materials and also specify an alternative capacity. Now when you combine this with textures you can create some quite interesting affects. So I have an example here of a texture and transparency. And I've done is set the transparency property to true, and in my texture I have a transparency color here. And you can see you get an interesting effect here, where the --- where the crate appears to have some cracks throughout it. The other thing I've had to do in this particular example is use the side property to get this to display properly. I've used some of the techniques we've been talking about so far to create this kind of lava effect using a combination of materials, lighting, and textures. Let's see how this was created. So I have some typical scene setup logic here. Let's scroll down to where we create our texture. Now I'm loading 'fire.jpg'. Now one thing I want to mention about textures is that if you're going to repeat them you need to ensure that their width and height are a pair of two. Now there are a couple of reasons for this; one of which is that they can be quite efficiently stored if they're part of this multiplier. And secondly, you can only use certain repeating modes in WebGL if the texture is created in a pair of two. So that means that you should use textures of say, 16 pixel x 16 pixel, 32 x 32, 64 x 64, and so on. And then we declare how we're going to be repeating the texture using the wrapS and wrapT properties. These correspond to the X and Y directions. And then we tell Three.JS that we're going to repeat our texture 10 times across the X axis, and 10 times across the Y axis. We create our material, and I'm using the emissive and specular properties to give out sort of a slight glow affect. And I played around with this for a while to get the affect that I wanted. And you'll probably find that if you're doing this type of thing there's quite a lot of experimentation involved. And then using a similar technique to what we used in a previous module, to just alter the geometry of the plane and get that sort of slight bubbly lava effect. Now I don't want this to carry in every time that we go through our rendering affect. So I have kind of a --- it's not the best way to do it, but I have a random number and if it's more than 9 I'm going to go and create that bubbly affect there. Now there's a better way to do this with the Three.JS clock. And I'm going to be covering that in a later module. And the final bit I want to just draw your attention to is that you can offset textures. So I'm offsetting the x and y position of the textures and that gives us that night sort of flowing affect. It could be useful, maybe you want to create a river for a game or scene. Three.JS also supports some advanced texture techniques such as Specular and BumpMaps. Let's take a look at BumpMaps. A BumpMap is a technique for simulating small changes on the surface of an object. And it does this by performing manipulations to how the light is rendered; it doesn't actually alter the object itself. BumpMaps can make textures such as, stone and skin, to look more realistic. So I have this example here, the cube on the left is using a BumpMap, whereas the cube on the right isn't. I'm going to zoom in so you can see the difference on this. So this cube here, I'm just going to turn the BumpMap off entirely. And you can see here we get quite a flat surface with the cube there. And if I go and apply the BumpMap, we get a lot more detail, and it perhaps feel a bit more realistic. We can alter the scale of the BumpMap. And you can see as I gradually adjust this, you start to get levels of detail, and to the point where maybe it's a bit too much and there's a bit too much noise there. Let's see how we can apply a BumpMap. Now a BumpMap is simply a separate file that describes how to distort the light on the surface of an object. In this particular example, I've purchased a texture from a site called, arroway-textures. Arroway-textures is a really good site, as it provides some very high-resolution images. And it also provides various maps that you can utilize, such as the BumpMap, in this particular example. Another great feature is that you can download trial versions of some of these textures to try them out before you purchase. There are lots of free options available as well. So there's a site called cgtextures, for example. It has a lot of different texture types here. You can search through divided by category. Now you probably will find some of these, the quality's not as good, and you won't have the separate map files. Although, you can create these map files yourself, but that's out of the scope of this particular module. Applying the BumpMap is very easy. We simply create our material, specify the BumpMap texture to load, and the scale of the BumpMap to use. Now you might be wondering how textures get applied to more complex models. This is often done using a technique called, UV Mapping. Now in Blender here, I have a simple cube. I'm going to go over to the Edit Mode here, and I'm going to scroll down to the options until we get to this one here, UV Mapping. I'm going to select Unwrap, and I'm going to select Smart UV Project. Okay, a couple of options there. I'm just going to stick with the defaults and click OK. Now I'm going to go into the UV Image Editor mode here. And you can see that Blender has generated this for us. Now we can export this to an image file, and then what happens is this then gets applied sort of wrapped around the object that we've created. And when the objects' exported, it contains information about how to wrap this back onto it. So in this particular example here, if we were to put this onto a bit of paper and cut it out, we could essentially create a cube from it. Now let's take a look at what's generated with a more complex model. This is the UV Map that's generated for the monkey head that we used in a previous module. It looks more complex than our cube UV Map, but you can see how you can take this and go and create the texture. So we could pass this to a graphic artist who would then fill-in the shading. So before we wrap-up this module, I just want to show an example that we used earlier. Here's a texture over on the right and you can see how this got wrapped onto the Mesh.
Summary
This has been a packed module. We began by looking at the importance of lighting and materials. We then looked at the three main types of materials. We looked at MeshBasic, which we've used many times in previous demos. Remember MeshBasic is a flat material not influenced by lighting. We looked at MeshLambert, which is a dull, non-shiny material, maybe like pottery or unvarnished wood. We looked at MeshPhong, which can be used for shiny, metallic or plastic-like surfaces. Remember when using MeshLambert or MeshPhong materials, that to display properly they need to be combined with a point, directional, or spot light. We then moved on to look at the different types of lighting available. We looked at ambient, where the light comes from all different directions and affects all objects equally. Remember that ambient light is usually used in conjunction with other types of lighting. We looked at point, which shines from all directions. Directional, which is a bit like the sun. And finally we looked at the spot light, which can cast shadows in one direction. We also looked at the various properties available on lighting such as ambient, emissive, intensity, and angle. And then before we moved on from light we looked at how to enable shadows in Three.JS. Remember shadows need to be enabled on the renderer, material, and any lighting. Finally, we concluded the module by looking at how to load and apply textures. We played around with transparent textures. And then concluded the module by looking at how to load and apply a BumpMap. Now this completes the foundational building blocks for our Three.JS scene, but at the moment we can't interact with our scenes, and this is what we'll be looking at in the next module.
Scene Interaction
Introduction and Page Events
Hi, welcome to Pluralsight. I'm Alex Mackey and in this module we'll be talking about Scene Interaction. In the last few modules we have pretty much covered the basic tools you will need to create a scene in Three.JS. But wait, there's one big area we haven't covered yet; Scene Interaction. If we were not able to interact with our scenes, it would make for some pretty dull games and applications. Although Three.JS' primary concern is displaying content on the screen, it also contains functionality around scene interaction such as Raycasting and control libraries. In this module we will look at the following scene interaction concepts. We'll look at how to work with a standard page event such as the user clicking the mouse and key presses. We'll look at some of the out of the box control libraries provided in this Three.JS source. We'll look at collision detection techniques using Raycasting and Box3. And finally, we'll wrap up the module looking at how to integrate a physics engine into our application. And in this case, we'll be using the Physi.js physics engine. Let's get started. Probably the easiest way to get started with scene interaction is by hooking into page events. You should never forget that Three.JS or WebGL applications, sit inside a web page and this gives you access to all the standard web page functionality you know and love. For example, we can create buttons or listen out for keyboard or mouse events to manipulate the view point and objects on the scene. You can also use standard HTML CSS as part of your WebGL applications. For example, you could utilize these technologies to construct items such as a score or game control panel. We've already been doing this with the dat.GUI library that we've used in some previous examples. We will get started with scene interaction by looking at how to work with the keyboard. Mousebased scene interaction is a bit more complex, and we'll need to talk about collision detection and Raycasting before handling this. So for now we'll hold off on this, and we'll start by creating a simple example to move the camera around with just the arrows keys. So I have some code here that sets up a scene; it just has some ground and a cube laying on it. I'm going to modify this code so that I can use the arrow keys to move the camera around. The first thing I'm going to do is add in a function called, checkKey. And what this is going to do is it's going to receive a key pres event, it's going to look at the code, and then it's going to move the camera around depending on which key is pressed. Next up, I just need to add a reference to this function so when the onkeydown event occurs, we're going to call the checkKey function. Let's take a look at this now. So here's our example, and I can now use the arrow keys to move the camera around and explore the scene. You can see it's a little bit jerky and you'd probably want to be able to do some additional things like be able to turn and rotate; otherwise you're not going to be able to look at your scene in probably the quite way --- quite the way the users might expect. There's actually quite a lot of complexity in coming up with a decent control system, and one that's intuitive and works how the user expects. And this is really where you want to look at external libraries. Now out of the box Three.JS provides a number of different control libraries in its example folders. And this is what we're going to look at in the next section. Let's take a look at these now.
Controls
While responding to page events can work for simple scene interaction, there are some tasks that it won't work quite so well for. For example, let's say you're creating a typical first person shooter game; making the controls intuitive is actually really difficult and contains some tricky math problems that most people would rather stay clear of. . . . Luckily for us Three.JS in the examples folder, provides a number of different control libraries for you to utilize, which we'll probably cover the main types of controls you might want to implement. There's even a library provider for Oculus Rift integration. . . . Let's look at now how to integrate two common control libraries; the Orbit and the Fly controls. First up, let's look at the Orbit controls. Orbit controls are great and --- for allowing a user to explore an object or model. For example, maybe you have a model of a product you want your new users to be able to look at in detail by rotating and zooming in and out of. So first of all, let me show you what the Orbit controls do. So I have a cube here and each face has different colors, just so I can see as I go and rotate it. Using the left mouse button in the mouse, I can now rotate the camera's view point around to go and explore my object. I can use the mouse wheel to zoom in and out of the cube. . . . And you can see that this could be quite good if maybe you had some kind of online shopping site. You could allow users to really explore the products that you're offering. So for example, maybe it's a watch or something, and they could zoom in to look at all the detail on the item. Let's see how to add this now. Adding in the Orbit controls library is really easy. First up, we need to include the OrbitControls.js file. You'll find this in the example/JavaScript/controls directory in the Three.JS source. Next up, we create a new variable to hold our controls. Then we instantiate a new instance of the THREE.OrbitControls passing in the camera. And finally, all we need to do is add in a EventListener, that whenever there's a change in the controls, we'll call the red to function. And that's it. So here's an example using the Fly controls. You can see I have the cursor in the center of the screen at the moment, and it's not really moving. If I move it either to the left or the right you can see the camera changes. If I move it further over, it moves quicker. I could use the left and right mouse buttons; left mouse button to move forward, or right mouse button to reverse. Let's see how to add in the Fly controls now. Implementing the Fly controls is very similar to the Orbit controls. First up, we add a reference to the FlyControls.js library. Then in our application code we're going to create a new controls variable to hold the Fly controls. And in this instance we're also going to create a new THREE.Clock. Don't worry too much about THREE.Clock for now; we're going to be talking more about this in the next module. Then what we're going to do is we're going to initialize our controls here, creating a new THREE.FlyControls instance passing in the camera. And then we're going to setup a couple of options there such as the movement and rollSpeed. And then with --the Fly controls we need to do an extra step. We need to use the clock.getDelta function here, as the controls.update method expects this. So you can see how easy it is to go and add in various controls to your applications. So go and explore some of the other options that are available in the example control library files. Next up, we're going to talk about collision detection.
Collision Detection
Sooner or later in your applications you'll want to detect if objects are interacting with each other or if the user has clicked on an object. This functionality is commonly known as Collision Detection. In a game context, collision detection could be detecting whether a bullet has hit an enemy or whether the player has touched a wall that should stop them from moving forward. You can perform simple collision detection checks yourself by checking if coordinates overlap and calculating the distance between objects. There's certainly a time and a place for these techniques. For example, they're very quick to do in performance as an issue. Three.JS provides functionality to make these type of checks simpler and also work with more complex scenarios. We're going to look at two approaches; Raycasting and Box3. It is worth noting that there are additional libraries that will assist with collision detection. For example, visor.js provides an event based model, which is a bit easier to use. And we'll look at this towards the end of this module. Let's talk about Raycasting first. Raycasting is pretty much what it sounds. An invisible ray is drawn from one point in space to another. So we'll take an origin vector, a destination vector, there'll be some objects in-between and we'll draw a ray between them. And then we can return any objects that this ray hits. You should be aware that Raycasting won't work for 100% of the time. For example, rays can miss small objects when projected from a large object, and also when a ray originates from within a Mesh, no intersections will be registered that are contained inside the Mesh. We will use Raycasting to detect whether the user has clicked on a sphere, and change its color if it's clicked on. Before we get into this however, we need to talk about how to convert mouse click coordinates to Three.JS world coordinates. Converting screen coordinates to Three.JS world coordinates, isn't the most straight-forward of tasks so let's run through how this works at a high-level first. First up, we need to register an event listener and listen out for standard mouse click events. When the mouse is clicked this gives us X and Y screen coordinates. We then use a formula that takes the rendering canvas' side and aspect ratio into account to create a vector. The vector is then used with a new class we haven't looked at before called, projector. Projector takes into account the camera's location and the angle it's pointing at. Next up, we use a Raycaster in conjunction with the projector and vector we created earlier. This shoots out a ray and we can then use the ray to retrieve any objects that it intersects using the raycaster.intersectObjects method. And then this will give us a collection of objects that have been hit by the line. Yup, it's not the easiest thing in the world and the mask behind it is doing some clever stuff, which to be perfectly honest, I don't quite understand how it's performing some of these calculations. The good news however, is that you can create a standard function for this and then not have to worry too much about how it's working behind the scenes. One thing you do need to watch out for when doing Raycasting and any interaction with mouse click events, is that you've setup the rendering area correctly, otherwise you might find your click detections might be offset. So be sure if you've modified the size of the rendering area to also modify the formulas to take this into account. Let's try this in code now. So here's the example we're going to look into the code of very shortly. There's two spheres displayed, and by clicking on these spheres you can see they change color. And we're going to look at the code to get this working. Before we do that I just want you to notice that the rendering area is slightly smaller than the whole window size, which is what we've been using in previous examples. The reason I'm doing this is because I want you to be sure that if you've modified the actual size of the canvas that you're going to also need to modify some of the formulas for calculating some of your Raycasting and projections. Okay, let's take a look at the code now. Okay, let's dive into some code. The first thing I want you to notice is that I've created width and height variables. I'm going to use these to specify the size of my rendering area. You can see in the call to renderer.setSize, these are getting passed in. They're also utilized when we go and create the camera; it'll just create the correct aspect. Now if you scroll down we can see I've created an onDocumentMouseDown function. I'm registering this using the addEventListener function, and this listening out for the mousedown event. Now in this function there are a couple of things going on. We create a new instance in the projector, we then create a vector. And then we need to do a bit of math here in order to convert this into something that we can use. We then call the projector.unprojectVector function, passing in the camera. We create a new raycaster again, passing in the vector here. And then this gives us an intersection collection here. And if we get any intersections then we just go and change the color of the first object that we get. Now I just want to show you some of the other things that the intersection method gives us. So let's go back to the example now. So I've entered a break point here, and I've clicked on one of the spheres, just so that we can go and explore the intersects collection. If you go and hover over this you can see we just have one intersection in this particular case. I'm going to open this up, and you can see that we have access to a number of properties here. Now one thing to bear in mind is that it you're using Raycasting to maybe detect a bullets path, is that you're going to get all the objects this ray intersects with, not just the first one. So you might want to make use of properties such as, distance, in order to insure that you're only detecting the first one or two items that are in the ray's path. A couple things we have, we have the object itself, that it's intersected with. So --we used this in a previous example, just to go and change its color. And we also have the point itself; so where the actual intersection occurred. Now let's look at another example of using this technique in order to be able to move an object around to some terrain. Now I've created an example to show you how to use Raycasting in order to move an object around the screen. So in this example I could select my cube, and then I could choose a new position for it and it will move to it. I'm using another library called, tween.js, that's quite good for performing simple transitions and animations like this. And then I'm also drawing a line in order to show the path that this will follow. So we'll select our object, we'll move it again. And then we can see the path that the ray took. So you could use this type of technique in a game for example, to move a character around a landscape. Next up, let's look at Box3. The next concept I want to look at is Box3. Box3 can be used to quickly determine if one object has touched or is inside another. Three.JS geometries have a property called, bound in box, we can utilize to detect if an object is inside another's bounded box. This is quite a quick calculation to do, so probably ideal for scenarios such as games. Let's use Box3 now and create a code example to demonstrate this. I have a simple example here to demonstrate Box3. I can use the arrow keys to move a box around. (Typing) When the red box touches the green box you can see the title changes to, 'Boxes touching'. (Typing) Let's see how this works now. So I have some code here just for working with the keyboard to move the box around. And you can see that it calls a checkForCollision function after moving the box. Now there are two boxes on the scene; box and box2. And what we're doing here is we're creating two box THREE objects based on their position. Now this is quite important in that you can call a method called, compute bound in box on the object itself, but you'll find if you've performed any manipulations or modifications to its position or size, these don't seem to be taken into account. So it's probably better to create a new Box3 object based on its current position. I then use this and call the isIntersectionBox, passing in the box2, Box3 object in order to determine whether the boxes are touching or not. So we've covered two basic methods of collision detection, Raycasting and Box3, but there's some more complex scenarios that these really won't cut it for. So we're going to look at how to integrate a physics engine into our application next.
Integrating a Physics Engine (Physijs)
As we have seen Three.JS is an excellent framework for developing WebGL applications. Although Three.JS does have some functionality around games issues such as, collision detection, it's important to note that Three.JS' primary focus is to display content on the screen. As we've seen, Three.JS contains some basic collision detection using a technique called, Raycasting and Box3, but for more advanced cases these may not be sufficient for your purposes. For example, let's say you're creating a 3D pool game. It's probably not too tricky to create the balls and table, but getting the balls to behave realistically when hit, can be very tricky indeed. A ball will behave differently depending on the speed and angle that is hit, and it will also need to interact with other balls and the boundary of the table. Or let's say you're creating a racing game; players are now used to vehicles behaving realistically. While you could try and code how these objects should behave under these different scenarios, it'd probably take a very long time to get satisfactory results. So what is the solution? Probably the best solution to this issue is to incorporate a physics engine into your application. Physics engines simulate concepts such as gravity, velocity, and how objects will interact when they touch other objects in an environment. A great option when using Three.JS is to use the Physi.js and Ammo.js libraries. Physi.js is basically a Three.JS focus wrapper for another library called, Ammo.js. Physi.js performs all the calculations in a web worker to avoid interfering with the UI as much as possible. Physi.js is actually using another library called, Ammo.js, which itself is actually a JS translation of a C++ library called, Bullet. Bullet is used extensively in many commercial games. Anyway, don't worry too much about this, but do be aware there's a heap of additionally functionality in Ammo.js., that isn't directly exposed by Physi.js. Let's head over to the Physi.js site now. Now before we look at how to download the libraries, let's take a look at a couple of the examples to see the sort of things that you can do with this library. The first one I want to look at here is the car example here. Physi.js actually includes an entire vehicle system with various different types of setups that you could use a basis to construct various types of games. You can see this car behaves reasonably realistically. I can go and turn it around, and let's go drive it into these boxes here. And you can see that they go and sort of move about in a somewhat realistic fashion. Let's take a look at another example. We have a Jenga setup here; I can go and remove these blocks here and you can see as I go and remove them that the --- the actual Jenga tower behaves reasonably realistically, to the point where if I go and remove too many it's all going to go and collapse. Interested? You should be. Let's go and see how to add the physics engine to our applications. Okay, let's get started and see how it's --- to integrate the physics engine into our application. The first thing we need to do is to go and get the various libraries. We'll actually need three files to use the Physi.js physics engine; these are: physi.js, Physi.js_worker.js, and Ammo.js. Let's head over to the Physi.js.js site to get the libraries we need. You have a couple of options for obtaining the libraries, or if you don't want to go and get the latest version, you'll find I've already downloaded these in the examples folder for this module. Now on the Physi.js site you can either clone it directly from the GIT repository or you can download a zip file containing everything you're going to need. Now it's worth noting, that both the zip file and cloning the GIT repository, it contains a number of really awesome examples that you're going to probably want to refer to as you get more involved with Physi.js. Now the other file you're going to need is Ammo.js. I just want to make you aware that this is actually maintained on a separate site. Okay, let's look at the sort of things that Physi.js allows us to modify. With Physi.js we can modify how gravity behaves in our scene. Now we could have just standard gravity, where objects just fall downwards, or we could reverse this. Maybe we're creating a space game, or maybe we're creating an underwater simulation and want gravity or objects to be pulled to the left or right. Physi.js also allows us to optionally set a Mass property on objects. The Mass property as you can probably guess, is used in calculations to determine how objects will interact with each other. For example, a heavier object will be less likely to move when a lighter object collides with it. Physi.js also provides a wrapper for materials that allows us to define friction and restitution properties. Friction is exactly what you think it is and creates a resistance against an object moving. Restitution is another name for bounciness. Friction and restitution have values between 0-1, with 1 being higher friction or restitution. Now Physi.js does do a bit more than this, but we're going to be concentrating on these basic properties. So let's create a simple application to demonstrate Physi.js. So the first thing we need to do is add in reference to the Physi.js libraries. (Typing) So let's add that in now. And I'm going to go over to my app.js and there's a bit of setup logic that we need to do. Now we need to tell Physi.js where the various scripts are held. So at the top here, I'm just going to add this in there. And these are the locations of some of the other files that we downloaded, Physi.js_worker and ammo.js. Next up, instead of creating a new Three.JS scene, we need to create a new js scene. So we'll replace that reference there. Now we're going to define the gravity for our scene as well. So in the initScene function I'm going to come down here, and I'm going to use the scene.setGravity method here. And this takes a Vector, which allows you to define the direction of the gravity there. Next up, let's actually create some objects in our scene. So first up, I'm going to define a material for the box that we'll shortly be adding to the scene. So we'll create boxMaterial there. And notice that the two properties there, friction and restitution/bounciness there. We'll define a new box. And we'll put that just below there. And notice how in both these cases we're using the Physi.js rather than the Three.JS versions. And this is kind of a wrapper around the Three.JS functionality. So I'm just going to rotate the box slightly as well, because it will allow us to see some of the physics a bit better there. We'll add our box to the scene. (Typing) And let's add some ground for it to fall onto. (Typing) And again, notice that I can set the friction and restitution properties there. Now there's one final step to make this all work. In our rendering loop we need to call the scene.simulate method in order to kick off the Physi.js physics engine. Okay, let's see what this does now. There we have it. We've setup gravity and you can see the cube falls from the sky and bounces slightly on the ground. Let's have a play with some of the properties. So let's change the restitution property of the ground. We'll modify this to null .6. Save that, and Refresh it. And you can see as the cube drops, it now bounces a bit more, as we've upped the bounciness or restitution properties of the ground. The other property that's quite fun to play with is the gravity direction. So we'll scroll across here to scene.SetGravity, and let's make it drift off slightly. Refresh that. And then you can see the cube comes down at an angle now, to the point where it's actually pushed off the screen there. (Typing) One of the other things that's really useful with the Physi.js library is it provides an event based model for a --- a collision detection. So what I'm going to do is I'm just going to add this in there, and scroll across and you can see I've called, box.addEventListner, I'm just (_____) out the collision object. And we then supply a function, and you have here a couple properties that might be useful depending on what you're doing with it, such as the otherObject the box is colliding with. And then some other properties around the Velocity, Rotation, and the contact. And in this function I'm just going to test if the other object that we collide with is the ground, and if it is I'm going to fire-up an alert box there. So Refresh this and you can see as the box drops down, it hits the ground and we then get an alert that there's actually been a collision here. It's probably a bit more intuitive to work with this type of model rather than all the Raycastings. It could be better for some scenarios. Here's a simple game I created with the Physi.js physics engine in Three.JS. Now the idea is to balance as many blocks as possible on the seesaw, and you get kind of random block sizes. And you can see that if I start to add too many blocks to one end, the seesaw is going to start to tilt, and I then need to go and offset this on the other end. And the game continues until the seesaw actually touches the ground. So if I start to stack up more blocks on one side, you'll see that it eventually overbalances, and it's game over. Now this was created in probably just an afternoon. So it gives you an example of how quickly you can develop some quite nice applications using the Physics engine in Three.JS.
Summary
So let's wrap-up this module now. We began by looking at page events. Now remember, your Three.JS application are contained on a web page, so you can utilize any web technology you know and love. And this can be really useful for creating items such as control panels, scoreboards, that type of thing. Next up, we looked at some of the control libraries that are provided in the Three.JS examples. Now there are an awful lot of different control libraries and we covered just two of them. We covered the Orbit and the Fly controls. You'll probably want to look into detail at some of the other ones and some of the other properties are available on the Orbit and Fly controls to customize them to your needs. Next up, we looked at collision detection, and looked at two approaches to this using Raycasting and Box3. Now it's important to note that there are also some other ways of doing this using geometry and comparing coordinates and distance between objects that might be better for some circumstances. Finally, we wrapped up this module by looking at how to integrate the Physi.js physics engine. It's important to note, that we've barely touched the surface of what you can do with the physics engine, and it could easily form an entire Pluralsight course of its own. I suggest you look at the Physi.js examples further to get some good ideas of just how far, and the sort of things that you can develop with it. As we've been covering the basic fundamentals of Three.JS, I've tried to keep the examples as simple as possible and self-contained so each module builds on functionality that we've covered in previous modules. But let's take a more complex example now and put all this together and see just what we can do with Three.JS.
Creating Three.js Frogger
Introduction
Hello, and welcome to Pluralsight. I'm Alex Mackey: Creating ThreeJS Frogger So we've reached the end of our course now, and I thought to wrap things up I'd create a more complex example than those we've been working with in previous modules. We will be producing our own version of the classic game, Frogger. So if you've never played Frogger before, shame on you. Here's a typical implementation. You play the small frog and you have to get across from one side to the other. So you have to cross over the lanes of traffic, dodging the cars. You have to jump on the turtles, onto the logs, and then hopefully you can get across the lily pad on the other side. Now if we were creating this game properly, we would create or buy 3D models for the various elements of our scene. Given that I'm not a 3D artist, and that due to licensing restrictions I can't use many of the free models available, we'll be sticking to making our scene elements from primitive shapes. In my opinion, it actually creates quite a pleasing effect too. So before we dive into the design and code, let me show you what we will be creating. So we can control our character using the arrow keys. So we can move them left, and right, and of course forwards and backwards. Something I've implemented is pointerLock, which allows us to rotate the camera around the scene obtaining a different view point. Okay, let's try and cross the road now. We'll move forward, watching out for cars. Quick, into the tress! And we'll try and get across watching out for the final lane of traffic. And then we're home free. And then when we reach the end, we'll display some nice text to the player. So of course the other thing that could happen is that the player can be hit by a car, and they should die. So let's make this deliberately happen. So we'll move out into a lane, ready to be hit by a car, and poof, there we are. And our character is knocked sideways and a life is deducted.
Game Components
So our scene will be made up of a few different components. We will create our scene objects from Three.JS primitives. For example, trucks are made from cube and cylinder geometries. I'll being using a Physi.js physics engine that we used in previous modules. We're also going to need to display how many lives the player has left. Although, we could use Three.JS to display this, it would be a bit time consuming, so we'll be using HTML and CSS, and then overlaying this on our rendering area. Finally, I thought it'd be fun to play with a pointerLock controls. Now these only seem to work properly in chrome right now, and I have modified the library from the Three.JS examples version. I've done this so you can't accidentally rotate the camera under the ground. Our scene will be made up of a couple of lanes of traffic, with vehicles moving at different speeds. Rather than create lots of vehicles, I would just reset a vehicles position once it moves outside the player's point of view. Now this does seem to upset Physi.js a bit, as I guess it's a bit of a strange thing to happen to an object. Now in this example, we'll also be using a Three.JS clock. This allows us to maintain movement at a constant pace, rather than have it influenced by the rendering frame rate. If you want to know more about this, checkout the stack overflow link at the bottom. If you want to obtain the latest version of Three.JS Frogger, head over to GitHub. Please feel free to submit any (_____) request with any cool new features you add. If you want to work with the version of code we'll be talking about in the course, you'll need to change the Branch to the Pluralsight Branch. I wanted to show you an earlier version of the game that contains some amusing bugs. As you can see some strange things are happening. The reason for this is that the vehicles will eventually hit one another. There's a couple of reasons for this, one of which is a friction on the scene, another the uneven wheels, and secondly, that the web worker that Physi.js is running in seems to quite upset when you go and change tabs. And I think this has something to with Chrome shutting it down in the background. To some degree this still occurs if you'll leave it long enough. Anyway, enough about bugs; in the next section we'll be looking at how this game is put together.
A Closer Look at The Games Code
Let's take a look at how our game is put together. Index.htm sets up a simple layout, imports the various JavaScript files we will utilize in the application. Note I'm using two libraries: PointerLockControls from the Three.JS examples, and physi.js that we've used previously. game.js is an essential script in our game. The game begins when the window.onload event occurs and the game.init method is called. In game.js there's some typical scene and initialization logic that you know and love. We also have some specific game functionality such as maintaining the number of lives the player has. In the init method we setup our scene, player, and enemies. Most games have some kind of loop where they go and move the player, enemies, and check whether the game has been won or lost. Our equivalent would be the render method here. sceneSetup.js as you may have guessed, is responsible for setting up the static objects on our scene. It's responsible for creating a road, the lake, the trees, and of course, the ground as well. I'm using some textures from a site called, opengameart.org. To make the game slightly more interesting I have a loop here that's going to go and create a number of different trees so I can create a more realistic tree line, and I'm passing in some random numbers just to get a bit of variety in my trees. The other thing that scene.Setups' responsible for is the lighting. And I'm using two lights, an ambient and a spotlight. gameControls is responsible for moving the player in response to keyboard events. We make use of the window.onkeydown event and then use various methods on the player object. player.js is responsible for creating the player out of Three.JS primitives. Additionally, it contains a number of methods for moving the player around the scene. We also check if the player has reached the end, in order to know whether they have won the game. support.js just contains a method to get a random number between an upper and lower limit; this is used to generate our tree line. text.js allows us to display text on the screen. Remember to import the font geometry, otherwise you won't see too much on the screen. pointerLock as you may have guessed, is responsible for initializing the pointerLock controls on the scene. In order to initialize pointerLock, the browser needs a click event to occur. It's worth noting that I have modified the pointerLock controls from the Three.JS examples, to stop the player rotating the camera underneath the ground. enemy.js is probably one of the more complicated scripts in the game. It starts off when the init function is called and we call the createEnemies method. In createEnemies we initialize our trucks on the various lanes of the road, passing in a number of parameters. The createEnemy function accepts a number of different parameters such as which side the truck originated from, it's speed, it's startPos, and also it's zPos. We then use Three.JS primitives to go and create our trucks, which are made up of a couple of cylinder geometries and also a cube geometry, which uses the Physi.js materials. The other thing that happens in this method is that we add in an eventListner to listen out for collisions with our enemies. When a collision occurs we call the handleCollision method. We check where we've collided with the player, and if we have we perform a number of different things; we disable the controls, set the player to not be active, remove the Life from them, and then call the handlePlayerKilled method. We use the setTimeout method to allow the player to go and see their little frog thrown across the screen. The other method I want to focus on is the update method. This accepts a delta parameter. This delta parameter is from the Three.JS clock and it's used to ensure our enemies move at a constant rate, rather than be affected by the rendering rate. Within update we go and iterate through our enemies collection, check whether they've reached the end of the screen; if they have go and put them back over the other side. Alternately, we'll go and rotate the tires round. Note I'm using the enemy._dirtyposition property in order to go and update the Mesh correctly. We need to use the dirtyposition property due to an integration issue between Physi.js and Three.JS. Check out this page to learn more about this. We've reached the end of the course now I hope you've enjoyed it as much as I have putting it together. We've come a long way from putting together a simple cube on the screen to creating our own Three.JS Frogger game. Now that you've reached the end of the course, what next? Well, I have a few suggestions that may be of interest. First off, why not have go and modify in ThreeJS Frogger. Maybe you could add in some models or some additional functionality. Next, how about looking at the Three.JS examples in more detail. There are some really awesome examples there that you can learn a lot from. Another item that you might want to consider is learning the 3D Modeling package, Blender. It's something I'm looking into at the moment. Finally, an event stopping at Shaders. Shaders allow you to perform some really awesome affects by manipulating vertices and colors.
Course author
Alex Mackey
Alex emigrated to Australia from the UK and works as a consultant for the Australian consultancy Readify. He founded the non-profit DDD Melbourne conference, and has written two books: Introducing...
Course info
LevelIntermediate
Rating
(182)
My rating
Duration2h 13m
Released15 Sep 2014
Share course