I have been wanting to write a series of posts on threejs for a while now, and I do not care to put it off any longer. I have fiddled with threejs in the past, but never really got into it, that is until now. I have enough experience with it to know that it helps making projects that involve 3d objects very easy, yet it is still something that takes a significant investment of time to get fairly solid with. Also there is not just what there is to know about the various features of the library, but also what there is to known when it comes to working with 3d in general. For example when it comes to really getting into 3d at some point sooner or later I am going to want to also learn a thing or two about using blender as a way to go about making external files that I can then load into a scene.
One thing that I think should be worth mentioning is that threejs and any additional assets should be hosted via http rather than the file protocol. In other words it is not a good idea to just copy and past files into a folder and then open up an index html file in a browser by way of ctrl + o. It might work okay in some situations, but I have found that often I will run into problems with the file protocol that need to be resolved by lossening by browser security settings, or hosting what I am working on over http.
Although it is not required for getting started at least, at some point you might want to install a 3d modeling program of some kind such as blender. As you get into the depth of threejs there will come a time where you will want to create assets externally, and then import theme into threejs. There are official plug-ins for doing so, and the best supported and easiest to use one I have found is the one for blender.
So threejs is very much a front end resource, so installing will not likely involve npm, unless you want to do something involving webpack in which I guess it would involve npm. For me I did not use any package manager, and I wanted to set up a situation in which I have multiple versions of three.js in a name space, so I just grab versions of three.js manually from the github repo, and pasted them in all low tech like.
In my test threejs Github repository I have the source code examples that I am using for this post. In now also have a corresponding for post folder for each of my threejs posts as I get around to editing each of my older threejs posts. Also Cloining down the repo, installing the npm packages, and running the server are great ways to get these examples up and running fast.
Although I do what I can to keep my content on threejs up to date, many of the posts might still be a bit dated compared to what you might be using now. Always be mindful of what version of threejs you are using as this is still a fast moving project. It seems like new revisions come out as often as once a month, and when they do there are a whole lot of changes, some of which do very much break code. So I decided to structure things in a way in which I can make demos for each revision when I am working out my source code demos in my git hub repo where I store the source ode examples for this post.
Threejs will contain a whole lot of constructors that each have a certain importance. There is no way that I can even touch base on all of them, let alone do them justice without having this starting to resemble a dissertation rather than a blog post. However it is possible to touch base on all of the constructors that will be in use in just about any three.js project, including the most basic examples.
As such a three.js project will typically always contain at least one of the following:
- An instance of THREE.Scene
- At least one camera typically THREE.PerspectiveCamera
- There will need to be a renderer such as with THREE.WebGLRenderer
- A Mesh that will contain a Geometry, and a Material. Such as with THREE.Mesh, THREE.BoxGeometry, and THREE.MeshBasicMaterial.
In any case you want to get three.js available in the browser one way or another, including the plain old simple way of having a script tag linking to the location of three.js. In addition you might want some kind of container element in your layout where you will inject the dom element created by the renderer that is used, unless you are okay with just appending to body.
The Scene is the space in which everything will go, your objects, cameras, and anything else that would be placed in a scene like a light source. Once you have a scene we will want to add things into it, like an object of some kind to look at with a camera. To do this I will want to call the Object3D add method, and give it a Mesh, that is composed of a Geometry, and a Material. I will touch base on all of that, because you should have at least a basic knowledge of all of those things, but not get into depth here, as each of these things could use there own posts.
There is a core class Called Camera that has some methods and properties that are shared across all camera types that are used in three.js. Like most objects in three.js, a Camera inherits from Object3D which gives it methods to help make changing the position, and orientation of the Camera pretty easy. There are then four camera types to choose from, in this post I am only briefly covering the perspective camera.
To make some kind of object to look at I need it’s geometry, I will also want to skin that geometry with some kind Of Material, and I will want to tie those two things together into a Mesh. In the example in this Post I used BoxGeometry to quickly create a Cube, and Just a basic Material with a Mesh.
In order to see anything I will need to render it using something like Canvas, or webGL. In this post I just used the webGL renderer, but there are additional renderer’s available in three.js, such as the canvas renderer that uses the 2d drawing context. That will be a lot slower, but it will give greater support on platforms that do not support webGL that well.
A very typical example for getting started with three.js indeed, but still it works to cover the basics of everything if you are new to three.js. Every project will involve a scene, a camera, at least one Object to look at which will be a mesh composed of a geometry, and a material. Also in order to actually see anything you will also need a render as well. That may seem like a lot at first, but once you get into this it all starts to make sense. Trust be this is one of the easiest ways to get into working with 3d objects, and can become a whole lot of fun if you give it a chance.
This example will just draw a cube on the screen. So lets have a break down on everything that is going on here.
I am of course going to want to have at least one simple animation loop example for this getting started post, I just have to do that. Thinking back to when I was first starting out with this library, yeah that was a must. With that said there are a few things to be aware of when it comes to creating a basic animation loop, not just with threejs, but in general when it comes to any kind of canvas project. For one thing the method that is general used is the requestAnimationFrame method, rather than one of the alternatives methods such as setTimeout.
To start things off with this sort of thing the most basic kind of animation loop I think is one where I just step a frame on each call of the loo method. Maybe I do something to cap the frame rate or something to that effect, but for this first example I am not going to want to do anything to complex.
There are a number of things that I could do inside the body of the animation update function, but because this is a getting started post for now I am just updating the instance of THREE.Euler stored at the rotation property of the mesh object to create a simple rotation effect of the mesh object.
This might work okay if I just want to work out some kind of animation loop idea, but there are a number of reasons why I would go with one of the other starting points in this section. The main reason why I have this here is because this is very much a getting started with threejs post. So I have a more basic kind of loop example here, but it lacks a lot of basic features that I think something like this should have.
For this animation loop example I have two values for FPS, one of which will be used to set the target rate at which the update method will be called. The other FPS rate is used to update the rate at which a frame value will be stepped that will be used to update the state of things in the update method. This allows for me to set the rate at which the update method is called at a low rate as only about 12 frames per second, while updating the frame rate that is used to update state at a rate that is say 30 frames per second. For certian projects in which I am doing something in real time in a web page I might want to make a user interface that will allow the user to adjust the rate at which updating happens to allow them to set how much CPU overhead they would like to use or not, that is what this is all about.
Often I find myself in a situation in which I would just like to have a simple 2d overlay to display some debug info. Also when it comes to making a full project of some kind I might just want to have a single threejs canvas layer between two or more plain old 2d canvas layers. When it comes to drawing a plain old 2d canvas to one of the canvas elements used by the WebGlrenderer, doing so is not so easy. There are ways of doing it of course such as having a canvas texture, and using that with a material for a mesh that uses plane geometry. I have made a threejs project example in which I am doing just that when it comes to doing something that way where I have one or more 2d layers as mesh objects in a scene. However for this demo I am doing things the other way around, that is to just have a simple 2d canvas, and then draw to that 2d canvas with the canvas of the webgl renderer.
Often I like to make projects that I will end up using in the process of making some kind of video project. However I think that I should have at least one or more demos that are good starting points for some kind of system that makes use of user input. For this first basic example of this kind of animation loop template I have something where I can define one or more items for an Alpha Controls object. This is a collection of values in the range of 0 to 1 that I can change by clicking an area of the canvas. That is the only way to have user input for this start point at least with one exception which is that it will also make use of Orbit controls if they are there to work with.
Three.js is the kind of library where you really need to devote at least a solid month or more in order to start to get a little solid with it. I am still learning myself, but I think there are some additional aspects of this library that are very important, while others are kind of optional depending on the kind of projects I aim to make. For example if I want to make games I might want to know about the lambert material, as it is more efficient then the standard material. However if I aim to make something that does not need to run in real time I might choose to go with the standard material, as it gives a more realistic look.
I first wrote this post back in April of 2018, and as of this writing it is now February of 2022. Sense I first started this post much has changed with three.js sense then, and with that said I will continue to update this post when I get some time to do so. As my content on three.js grows, and I edit posts such as this one, I often will link to this post as a way to just pipe people to something that is a good starting point for threejs.
If you are still fairly new to three.js but have some of the basics worked out maybe it would be a good idea to work out a whole bunch of examples where you are just using the Box Geometry Constructor. There is not just having a Cube on the screen, but doing a whole word of things with that cube. For example there is moving it, rotating it, using an array of materials rather than just one, changing what the index values are for those materials, doing things with light and shadow and so forth. With that said maybe my post on the Box Geometry Constructor will be a good next step from here.
A real good class to start really learning a thing ot two about would be the Object3D class, I wrote a post on Object3D, and there is also of course the official docs on Object3D. This is not something that you typically work with directly, but is a class that is used in many of the objects in three.js that helps to make working with three.js easy. It gives Objects like Camera, and Mesh methods like lookAT, and position.set.
Read my full post on Vector3
Another class of interest that you should at least be aware of is vector3, This is what you want to use when defining a point in 3d Space.
In the long run thought of course what really needs to happen sooner or later is to start making one or two real examples using three.js. That is some kind of game or animation type thing typically, so with that said maybe another step forward would be to look at some of my basic project examples.
For now I will cover some additional corners of three.js that I think stand out…