Moving a camera in threejs over time
I work with threejs a lot, and when doing so I have found that one thing that is fun is working out expressions for handling the movement of a camera. There ae a number of options to work with when it comes to cameras but for the most part I end up using a perspective camera. Apart from working out javaScript expressions for the x, y a,d z values of a position there are all kinds of ways to go about moving a camera such as having a camera move around of course, and must of this applies to objects in general actually
There is also having the position and rotation of a camera be subject to event handlers that are attached for pointer events. In other words to control the camera with a mouse, and or keyboard which is nice when I am working on a project and I would like to see how things look from all kinds of different perspectives. There are some official controls that are in the threejs Github repository for this sort of thing in the form of orbit controls, and fly controls for example. However there is also of course making ones own custom controls for a project which is often a required part of working out an over all user interface.
So in this post I will be writing about some threejs examples that have to do with using the position and rotation properties of an instance of a camera along. This can involve working out expressions, but also there are a whole lot of threejs feature to work with also when it comes to this sort of thing as well when it comes to looking into everything there is to work with in the Vector3 class, as well as Curves just to name a few core features to be aware of.
What I work out here for a camera will also apply to just about anything in threejs that inherits from the Object3d class as well. So much of this is just ways of moving and rotating objects in general actually, but still I will be keeping the emphasis on cameras alone for the most part here.
Moving a camera in threejs and what to know first
This is a post on how to move a camera in threejs, a front end javaScript library that has to do with 3d modeling. This is not a getting started post on threejs, or javaScript in general so I assume that you have at least some background on this to get started with, otherwise you might have a hard time gaining something of value from reading this content. In this section I will then be writing about a few things that you might want to read more about then when it comes to closely related topics that you might want to get solid with first.
You should really look into the Object3d class when it comes to movement of objects in general
A camera in threejs inherits from a base class in threejs called Object3d, which is also the case with many other objects that will be part of a scene such as Mesh, Group objects, and many helper objects. Also speaking of scene objects, yes even that is based off of the Object3d class as well, and it is possible to adjust the position of that can change its position relative to what is often refer to as world space. So by learning how to work with the Object3d class you in turn learn how to work with everything which is built on top of Object3d which includes cameras.
Read More about the Vector3 class
The main property of interest with the Object3d class in the position property which stores an instance of a class known as Vector3 as the value for this property. This Vector3 class in turn is another class of interest that applies to many things in threejs when it comes to positions of things. The set method of an instance of this Vector3 class is one way to set the position of a camera when it comes to the position property.
There is also Object3d.lookAt, Euler, and Quaternion Objects for setting rotation
There is also changing the orientation of the camera when setting the position, for this there is the rotation property that is also part of the Object3d class. This rotation property is an instance of the Euler Class which is like Vector3, only we are taking angles rather than a local position.
There is working with the instance of THREE.Euler directly at camera.rotation, or there is making use of a method like the Object3d.lookAt method as another way to go about setting the local rotation of the camera. There are also quaternion objects as well that prove to be a more professional way to go about stetting the local rotation of a camera also. All of these features are worth looking into in depth in order to really know how to move things around, and also adjust the rotation after doing so, not just cameras but many objects in general.
You might want to check out the Orbit Controls, and other official controls as a way to move a camera by way of user input
When it comes to moving a camera the first thing you might want to figure out is if you just want to move about in the scene using the mouse. I often use the Orbit Controls that are in the examples folder of the Three.js repository for many of my examples as a way to be able to have the basic typical movement right away. There are also a number of other options when it comes to official controls use in the official threejs examples, as well as many other useful libraries to work with in the examples folder.
However when it comes to moving a camera by way of some kind of application loop, or working out custom controls that will work a little differently from that of the orbit controls. Then it would make sense t start working out some examples like the ones in this post here. Still of you think that the official orbit controls will work okay, and you just want to move on to other things you might want to check out my post on orbit controls.
The source code that I am writing about in this post is on Github
The source code examples that I am writing about here can be found in my test threejs github repository. This is a also a location in which I park the source code for my many other blog posts on threejs beyond just this one.
Version Numbers matter with threejs
When I first wrote this post I was using r111 of threejs, and the last time I edited this post I was using r146. Threejs is a fast moving project when it comes to development, so at some point in the future these threejs examples might break because of this. I do get around to fixing up my code every once in a while, but there will often be large gaps of time between major edits. So be sure to always check the version number of threejs when working with these examples, or any threejs examples on the open web for that matter.
1 - A Basic camera movement example with an animation loop function
In this section I will be starting out with some basic threejs examples that has to do with moving a camera by way of an animation loop. So nothing major or fancy here, just a kind of hello world when it comes to moving a camera around in a threejs project along with some other typical things that come up when doing so. If this sort of thing is new to you in general with front end javaScript you might want to start out looking into the request animation frame method in client side javaScrit alone.
1.1 - World relative position of camera
I started out this example like that of any other threejs example when it comes to the usual set of objects. What I mean by that is having a scene object, camera, and renderer set up. After that I just created a single mesh object that I will be leaving at the default origin location.
I then have the main app loop in which I will be moving the camera over time, and this is where things can get at least a little involved when it comes to moving a camera this way. There are many ways of making this kind of animation update loop, some of which are a lot less complex than what I am doing here. However I have found that there are at least a few key features that one should always have in this kind of loop in order to have something that is in better shape for production.
The first and foremost thing that comes to mind is to not update the scene each time the loop function is called, rather a date should be used to find out how many seconds have based sense the last update and use that as a means to update the scene or not. This way the client running the threejs program is not getting slammed and I can adjust how low I want to fps to be for updating the scene. However fps values will result in using less CPU overhead, but at the cost of choppy rather than smooth motion.
On top of having a main FPS update value I can also have a septate FPS value for how to go about updating the frame rate of the animation. This way I can update the scene at a very low frame rate, but still update the position of the camera at a higher frame rate.
|
|
When this example is up and running the end result is having the camera at a location away from a mesh, and the camera is still looking in the direction of the mesh. In most cases I will not just want to set the position of the camera but also adjust the rotation of the camera as well one way or another, however that will be something I will be getting into more so inn the nest example here. Over time the camera moves, and I am not doing anything to change the rotation of the camera over time so the camera does not stay fixed on the mesh.
1.2 - The look at method
There is more to moving the camera that just moving the position of the camera in world space, there is also setting the rotation of the camera that can also be tough of as a kind of movement as well. There is learning how to work out all kinds of ways to manual setting the state of the Euler instance of the rotation property of a camera, but maybe the easiest way to go about setting the rotation of a camera would be to make use of the look at method of the object3d class.
|
|
1.3 - Using the Vector3 lerp method along with other Vector3 class methods
A very useful method in the Vector3 object not just for moving a camera around, but objects in general, as well as points in space in general is the lerp method of the vector3 class. This is a method of vector3 in which I can call the method, then pass another vector3 object that I want to move to along with another argument that is an alpha value between 0 and 1. This alpha value will then set the value of the vector3 obect that I call the lerp method off of between the two vector3 objects based on the given alpha value.
This lerp method will mutate the vector3 object in place, so if I am in a situation in which I have two source vector3 objects that I do not want to mutate I can do something like call the copy method off of the vector3 object that is the position of the camera, and then pass the vector3 object that is the start point to the copy method. This will then copy the state of the start vector3 to the start point without mutating the start point, after that I can then call the lerp method, pass the end point that I want, and then the alpha value that I want to use to lerp between the start and end point.
|
|
1.4 - Using Curves to get Vector3 objects along a curve, and using that to set the position of the camera
One great tool for setting the position of a camera would be to look into using curves. The base class of curves has a get point method that allows for me to pass an alpha value and get a vector3 object that is at a corresponding point along the curve. The resulting vector3 object can then be used as a way to get the position of a camera. The same thing could also be done as a way to set the point for the camera to look at as well on top of that as well of course.
|
|
2 - Object relative position
So far I have covered some simple examples that have to do with just changing th rotation and the position of the camera. However when it comes to setting the position of the camera I am doing so in terms of world space, or maybe a kind of relative space but relative to that is the scene object rather than a child of the scene object such as the one mesh object that I have in these examples thus far.
|
|
3 - Using the curve module
I have made a threejs project example cented around the idea of using curves to create paths that will be used to move objects. These objects can be mesh objects, but with the theme of this post in mind it can also be used to move a camera around a scene as well. What is great about this module is that I can not only use it to create a path in which to move a camera along, I can also use it to get the kind of value that I would use to get a point along the curve as well on top of that.
The curve.js modue ( R1 )
This is R1 of the curve module that I have made for my set of threejs project examples, many of which have to do with modules like this one rather than a full complete project of some kind. There is a whole lot to write about when it comes to the state of this module. However for the most part all I care around for the set of demos that I will be using here is the QB Curve Path method and also the get alpha function method. These are what I will be using to create a curve path for a camera to follow, and also how to create an alpha value to pass when calling the get point method of the curve. The return value of the get point method will be a vector3 object to which I can then copy to the Vector3 of the position property of the camera.
|
|
3.1 - Using the curve module to move a camera along a curve
Here I am then using the curve module to create a path in space for which the camera will move along. I am also using the get alpha method to create a get alpha function. It is then the alpha value that will be returned by this get alpha function that will be passed to the get point method of the curve I created.
|
|
4 - Updating things by way of sequences
One thing that I have found that I like to do when making video type projects using threejs is to have some kind of system that can be used to break things down into many parts, or sequences if you prefer. This way I have have some kind of setup where I define an array of objects and each object can be given an update method. Each update method of each object would have access to a main sequence object with values that have to do with the progress of the over all video, but also values that have to do with the progress of the current part, or sequence.
The sequences-hooks.js file ( R2 )
Here I have a javaScript file that I am using to define a system for this sort of thing when it comes to sequences. I have made a whole other threejs project centered around this kind of thing. In fact this is R2 of that very project that I am writing about here.
On top of having update methods for each sequence object, I will also want to be able to define hook functions that will be called before and after the call of the current update method in the objects array. This way I can use the before objects hook to update the state of a mesh object that will change over the whole span of the video, or set defaults for things. The after objects hook would be a good place to do anything that I would want to always do with the camera or an object for every frame and override anything that might happen before.
|
|
4.1 - Getting started example of the the sequences hooks module to set camera position
I then just want to have some additional code that I can then use to demo this sequence module as a way to just test out the core features first for camera movement. With that said I can use the before objects hook of this project to define what I want to happen over the while span of a video project. For this demo I am just moving a mesh object of a sphere around in a circle. I can then use the after objects method to make sure that the camera will always look at the first mesh object. I should take care when doing this in the after hooks method as this will override any look at method, or rotation calls over that I might make in the before objects hook, or the current sequence object update method.
|
|
5 - Camera movement helper example that moves the camera via javaScript code
For this example I am making a more advanced version of my basic animation loop example that has to do with moving a camera. This time I have a move camera helper that takes a camera as an argument along with an update index number in the range of 0 to 1, and a function that will be used to create the values that will be used to change the camera position and orientation. So now the idea is more or less the same as the first animation loop example, but now I am creating additional code that has to do with creating a camera, with values attached to the userData object of the camera. If you are not aware of the user data object of a camera or any object in threejs that is based off of the object3d class, the user data object is just simply an object where I can pack values that have to do with my own custom system for an object such as a camera.
|
|
Conclusion
So moving a camera is more or less the same as moving anything else in three.js that inherits from the Object3d class by making use of the position and rotation properties of the object, and cameras are no exception. So then I could get into making all kinds of examples that have to do with different ways to change the values of the position and rotation of a camera over time, but with the collection of examples thus far the basic idea, and much more beyond that has been covered in this post I think.
I do get around to editing my content on threejs from time to time, and this post is just one of many that I am sure I will come back to again at some point also. I all ready have many more ideas when it comes to additional examples, and improvements to the examples thus far. If you did enjoy what I have wrote about here, or thing that you have obtained something of value there is checking out one of my other posts on threejs.