Often I might be in a situation with a threejs project in which I would like to apply some kind of rules for Vector3 class instances that have to do with boundaries in terms of the possible range of values. There are two general ideas that come to mind with this clamping and wrapping.
In the past I have wrote one blog post on the clamp method of the Vector3 class, and that is one way to go about applying limitations. That is that when a vector goes out of a set range it will be clamped to a value that is within the range, and do so in a box kind of area as it is used by passing two vector3 class instances that define the lowermost and uppermost corners of the box. In that post I also wrote about the clamp length method that works by giving number values that define a min and max vector unit length. This is yet another option that works well, but then both work by clamping values rather than wrapping values. That is that some times when a Vector3 instance goes out of range I might not want to clamp it, but wrap it around to an opposite side of an area.
In the Math object of the Game Framework called Phaser there is a wrap method, and I have found that method works okay with a few exceptions with certain sets of arguments. In any cases there is looking into the source code of various projects that have libraries like this to see how they are preforming a certain kind of task such as this.
I was using r140 of threejs when I first wrote this post, and the last time I came around to do some editing I was using r146.
However even though things are working the way that I want them to with the euclidean modulo method it is still working in a way that is relative to zero forward rather than in a way that can work with a range that might go into negative numbers. Still the general idea of wrapping is there, from here forward I just need to find ways to adjust the range.
The process of making a wrap method from the ground up might prove to be a little involved, at least when it comes to making one from the ground up without looking into what is out there on the open internet at least. In any case there is taking an approach in which I am figuring out that I need to do on a axis by axis bases which just seems like the thing to do. What is good about this is that once I figure out something that works well for one axis, then it is generally just a mater of applying the same logic to all other axis values, at least that would seem to be the case with this anyway with respect to the way that I want to do it.
However I would not just want to use a wrap method with vectors alone mind you. So then this post will be on making a wrap method in general to begin with.
The basic idea of what I want does work very much so with the MathUtils.euclideanModulo method. However I want to have a wrap method where I pass a value, and then a min and max value rather than just two values. So then a wrap method can be made by just using the Math.max and Math.min methods with the a, and b values that are given after the first value. These min and max values can then be used to get a range which in turn can then be used to figure an alpha value by using THREE.MathUtils.euclideanModulo and then divining that over the range.
I have not battle tested this mind you, however thus far it seems to work fine.
The code that I worked out for this solution involves making two instances of the Vector2 class and then calling the distance to method of each to get an idea of what the max distance from 0 is as well as the current distance is. Once I have these two values I can use them with the euclidean modulo method to get how mush I need to add to the min vector or subtract from the max vector for the current axis. Once again I did not battle test this, but also once again it seems to give me a desired result thus far to say the least.
I have wrote a blog post or two on the game framework called Phaser in the past and I remember that the math object of the framework has a wrap method. This method does seem to work the way that I would want it to, but with a few exceptions one of which has to do with NaN values when given the value 0 for the min or max values of the range that I would like to wrap to. This can be fixed fairly easily though of course by just adding some code that will return 0 for such a case of course.
Now that I have a method that seems to work okay for one axis all I need to do to make a wrap method for Vector3 is to just call the method for each axis. What is great about this is that in order to make solutions that will also work for the Vector2 class the only major change is to just call the wrap axis for x and y only when making the wrap vector method. Also if I put more time into researching other solutions for this, and fine a better way of wrapping an axis, I can just recreate the wrap axis method, and leave everything else as is.
Having a wrap vector method seems like the kind of tool that I would want to take with me from project to project. So then in this section I will be writing about the start of a wrap vector module that I might turn into a separate full blown project that I will make one of my threejs example posts. There are a few ideas that come to mind for advanced features, but for now I think this module might just need to have one public method that will wrap a vector that I give it. On top of that I might want to also make a wrap number method public as well while I am at it so for now maybe that will be it for this project, as far as this post goes at least anyway.
The module that I have together then thus far just makes use of the wrap method based off of the one from Phaser, along with the wrap axis method. I then create a public api that is a function and make the main function of the module the wrap vector method. I am thinking that will be the main feature of interest with this that I will be using over and over again in projects, so maybe that is all that I need to do with this one for the most part. The only other thing that I did is make the wrap method public as I might want to do this sort of thing with a number rather than a vector class instance in some cases.
A basic example of the module will now work by setting something up like this one. Here I just have two mesh objects and I would like to wrap them both to the same set of vectors as I move them around. Thus far the module seems to work just fine with this simple hello world type example, but now I would like to move on to something a little more involved.
For this example I made a few functions that will create and update a group of mesh objects. When I create a group I can set some data with the user data objects for the group as well as each mesh object.
For this section I will not be going over the source code examples of a few animaiton loop demos that make use of the various wrapping features that I have wrote about this far in this post.
Here I have an animation loop example that is the basic for one of my videos for this blog post. The first video that I made was based on one of the module examples that I made with the wrap axis methods. For this example I wanted to just make something that has to do with wrapping vector unit length. I also wanted to make something that is a little more interesting than just a single mesh object having the length wrapped so I went a little overboard with expressions and so forth.
A while back I made a threejs project example that I just called object grid wrap because I am very bad at names. Anyway the project is a fairly complex way of creating a grid of objects that I then move around by way of two offset values, and then they, well wrap around when the go out of bounds. The project works okay, but there are for sure a few ruff edges with it at least as of this writing anyway. To cut to the chase here I might get around to making a new revision of that project at some point and to help address some of the problems I am seeing with it I thought I would try to make a very simple form of what I want here as an animation loop demo.
Wrapping Vectors is something that I do find myself doing over and over again as a way to limit vectors to a given range. I have made a whole lot of projects that do something to this effect one of which I find myself using a whole lot when I make my various little video projects that I call my “object grid wrap module”. When it comes to that project I am just using the Euclidean Modulo method to do so by wrapping given values to a range of 0 and 1 and then use those values to set the position of objects in a grid. That kind of system seems to work well also on top of having some kind of function that will wrap a vector directly like I did with my main wrap method example in this post.