Getting world position of any Object3D Class based object in three.js
In threejs there is getting into using groups as a way to compartmentalize a collection of mesh objects. When doing so there is using the look at method to get a mesh to look at another child object of the group, or some other group in an over all scene object.
One thing that I have found that pops up when dealing with nested objects, and the look at method of the objecy3d class, it is that the look at method will always have the object look at something relative to world space. With that said there is knowing what world space is, and how it compares to local space, or space relative to a parent object if you prefer. To help with these kinds of problems there is the get world position method of the object3d class that when called will return the position of an object relative to world space rather than the position that is relative to the parent object.
There is one weird thing about the get world position method though which is that a target vector3 instance must be given as an argument when it comes to late versions of threejs at least r135+ last I checked. In other words I can not just call the method and have a new Vector3 returned, I must create a new one and pass it to the get world space method as the first argument. The world position will then be copied into this Vector3 that is passed to the method, and that can then be passed as the position to look at, or be used for whatever reason that is needed when it comes to this kind of situation.
So in this post I will be addressing this issue with some source code that has to do with nested object3d class based objects and the use of this get world space method. There is also just working out a few basic examples that have to do with the differences between local and world space in general as well.
Getting world position in threejs and what to know first
In this post I will be writing about the get world position method in the object3d base class in the javaScript library known as threejs. So the content here has to do with just one little issue in an over all larger library that is written in a specific programing language called javaScript. I assume that you have at least some basic working knowledge of how to get up and running with the basics at least, because I am not going to do that here in this post. However I always like to start off my threejs posts with a section like this in which I outline some things that you should be aware of before continuing to read the rest of the content.
Read up more on the look at method of object3d and what it has to do with world space
There is working out not just one but many examples of the look at method of the object3d class to get a feel for where and when the method is useful, but also to become aware of the drawbacks in some situations. The method works great but it will always look at a position that is relative to world space rather than local space. Using the get world position method can help with this, but even then there are some situations in which I am just going to need to work out another solution to set the orientation of an object.
Check out my main post on the object3d class in general
The get world position method is just one of many methods of the Object3d class in threejs. There is a whole lot more to be aware of when it comes to other methods, as well as various properties that will also come into play. Also although often I might not work with the object3d class directly I do work with other objects that are based on top of object3d all the time such as mesh objects, cameras, lights, and much more. There is also a whole lot that comes up when it comes to things that branch off of the object3d class as well such as the vector3 class that is the value of the position property, and the Euler class that is the value of the rotation property of object3d. With all this said you might want to read my main post on object3d.
Learn a thing or two about groups and and nested objects in general
The use of the get world position often ends up going hand in hand with the use of groups, or in any way shape or form the use of objects that are a child of a parent object. That parent object can be a group, but it can also be anything that is based off of object3d, including even the scene object.
The source code examples in this post are up on Github
The source code examples that I am writing about in this post can be found on Github in my test threejs repo. This is also where I park the source code examples for my many other blog posts on the threejs library.
Version numbers matter in threejs
When I first wrote this post I was using revision 127 of threejs which was a late version of threejs as of April of 2021, and the last time I came around to do some editing I was using r146 and thus the demos where updated to the style that I set for that revision. At one point I have found that a basic example that I have made for this post did in fact break with r135. In older versions of threejs I did not have to give a target vector as the first and only argument, but now the method will not work if I do note give one. Code breaking changes are introduced to threejs all the time, this is just one of may examples of this sort of thing. So if the code examples are not working as expected always check the version number that you are using.
1 - Some Basic examples of the Object3d.getWorldPosition method
In this section I will be starting out with a few basic examples of the get world position method. These will just be a few quick examples that have to do with just two objects of interest with the aim of just focusing on the core idea of what the get world position method is all about.
1.1 - Parent and Child objects
For this very first example in the basic section here I will of course try to keep things as simple as possible. The general idea here is that I have a single mesh object that is a child of another parent mesh object which in turn is also a child of the scene object. The scene object is also an example of an object3d based object and as such it also has a position property but for now I am leaving the scene object aligned with world space. So there is just thinking in terms of the parent mesh and the child mesh. When I set the position of the child mesh that position is relative to the parent mesh, and the parent mesh is relative to the position of the scene object which in this case is the same as world space as I am not going to move the mesh object around here.
Anyway if you are still a little confused by this just start playing around with a code examples like this one here:
|
|
Notice the difference between just passing the child objects position property value to look at compared to using the get world position method. When I just pass the child position property the camera looks away from the child mesh, and when I use the get world position method the camera looks at the child mesh object. This is because the look at method will always make an object look at a position that is relative to world space. So when I give the child position value it is not the position relative to the parent mesh, but rather the position relative to world space, which in this case is aligned with the scene object.
1.2 - Basic group example of look at using and not using get world position
In this example I am making a helper function that will create and return a group that I can then add to a scene object. This group object contains two mesh objects, one of which is a cone, and the other is a cube. In this helper function that creates the group I am doing a rotation of the geometry of the cone once to make it so that the orientation of the cone geometry lines up with the face of the mesh object. So it is now just a question of using the look at method of the cone mesh to have it point at something where the tip of the cone is facing the given direction.
So everything in my create group helper method seems to work just fine when it comes to creating a group with two children. So now there is just creating two instances of this group as a way to showcase what the difference is between just passing the position property of the cube to the look at method of the cone, compared to using the get world position method.
|
|
With the group in which I am using the get world position method as a way to get a position to pass to look at the cone points to the cube that is inside the group. However the group where I am just passing the position of the cube to the look at method that cone is not pointing to the cube, it is however pointing to a position where the cube world be if that position value was relative to the world rather that the parent group object. So then this example helps to show the difference, and why in some cases I will want to use the get world position method when working with an object that is a child of a group.
2 - Animation loop examples
I would like to make at least one if not more videos for each of my blog posts on threejs, and this one is no exception. Also in order to really gain a good sense of what is going on with various things that have to go with world space and local space it would be best to make at least a few animation examples with this sort of thing. So in this section I will be going over at least one if not more animation examples that involve the use of the get world position method of the object3d class.
2.1 - Animation example of the cone and cube groups
Here I have an animation example of the groups that contain a cone and a cube as a way to show what the difference is with world space compared to the typical local space that is given to the look at method of the object3d class. Once again I create two groups with the same create group helper function that returns a new group object with two child mesh objects. One child mesh object contains a cylinder geometry that is shaped like a cone, and the other mesh object is just a box geometry. I then also now have an update group helper function that will move the box geometry mesh around in a circle relative to the position of the group.
So then I am creating both groups with the same helper, and I am also updating the positions of the cubes with the same helper function as well. The difference in the update method of the animation loop though is that for group1 I am just passing the raw position of the child cube of group1 to the look a method that I am calling off the cone. This results in the cone looking in the direction of where the cube would be relative to world space. Often I will not want this to happen so I need to get the position of the cube relative to world space rather than just use the local space relative to the group. So to do this with group2 I am using the get world position method to copy the world relative location to a vector3 that I then use with the look at method, the end result is that the cone looks where the cube really is rather than where it would be if it where relative to the scene object rather than the group.
|
|
This is then the source code that I have together for the first video that I have made for this blog post. In time I might very well come around to edit this post again, and when I do so I may or may not make an additional video or two and then expand this section. The main thing here though is to just have a decent visual demo of why the get world positing method can prove to be useful and all ready I would say that this animation dies a good job of that.
2.2 - Moving a camera to move between viewing a static object, and a child of a group
This is then a loop demo in which I am moving a camera between a view of a static mesh object, and then to a child mesh object of a group.
|
|
Conclusion
The get world position method of the object3d class seems to work well for the sake of having a way to go about getting an instance of Vector3 that is relative to a fixed static world space rather than a parent instance of object3d such as a group, or even a scene. The look at method will always point to a position that it is given relative to world space, so it is nice to always have a way to go about getting that kind of position by just calling a method that will always return that kind of position.
Understanding the difference between positions that a relative to group, and positions that are relative to world space is an impotent part of the process of learning how to go about making crude yet effective models that are collections of mesh objects. As of this writing there are still a few ruff edges in my understanding of little topics like this, so each time I become aware of something that I think I should have solid by now I write a lengthly post such as this as a way to help me get a topic like this hardwired into my mind.
When it comes to additional reading in the long run sooner or later there is getting into starting to make some actual projects of one kind or another with three.js. With that said I have a post that I have wrote that is my current standard collection of general threejs project example prototypes for all kids of various things.