What are the "...toRef" Methods? How Should We Use Them?

I notice that most of the mathematical operations for the basic 3D data structures (Vectors, Matrixes, Quaternions, etc.) have three versions: the basic one, the “…inPlace” version, and a “…toRef” method. I suspect that I’m not fully taking advantage of the latter.

As an example, a Vector3 can be added–myVect.add(myOtherVect)–added in place–myVect.addInPlace(myOtherVect)–or added “to ref”–myVect.addToRef(myOtherVect). The first creates a new Vector3 object as its result. The second changes the original Vector3 object to its sum with the other, but then there’s a third option. What does it do? When is it most beneficial to use?

Basically the no suffix version creates a new vector the inplace changes the data directly in the input and the toref is storing the result inside the parameter passed in inputs.

As Garbage Collection can dramatically impacts perfs, I would recommend to always use inplace or toref for any operation happening on each frames.

1 Like

ToRef will update the vector passed as the second argument: vec.addToRef(vec2, vec3) means: vec3 = vec + vec2

The goal as @sebavan mentioned is to not instantiate new objects to keep the GC away

To expand a little more on @sebavan and @Deltakosh 's comments

In your question you show ‘toRef’ with only one parameter.

It requires two parameters, the vector to add and a results vector in which the addition is stored.

This (rather implausible) example shows the benefit of ‘toRef’ over the basic

There is a line of points along the x axis and from each point we need to draw a random unit vector. We achieve this for each point A by generating a random point B and forming the unit vector from A to B.

Method 1 - GC (garbage collection) rich

for (var i = 0; i < 10; i++) {
    var A = new BABYLON.Vector3(2 * i, 0, 0);
    var B = new BABYLON.Vector3(Math.random(), Math.random(), Math.random());
    B.normalize();
    var C = A.add(B);
    // draw line from A to C

Method 2 -GC light

var A = BABYLON.Vector3.Zero();
var B = BABYLON.Vector3.Zero();
var C = BABYLON.Vector3.Zero();
for (var i = 0; i < 10; i++) {
    A.x = 2 * i;
    B.set(Math.random(), Math.random(), Math.random());
    B.normalize();
    A.addToRef(B, C);
    // draw line from A to C
}
2 Likes

tick tock tick tock…

:slight_smile:

2 Likes

So if I understand correctly,

A.addToRef(B, C);

would be superior to

C = A.add(B);

as the second version would (under the hood) create a new Vector3 object, dereference the current contents of C and replace them with the newly-created Vector3. The garbage collector then needs to get rid of the old contents of C. In the …ToRef() version, instead, the same three Vector3 objects are used in place, with nothing needing to be dereferenced. The …inPlace() and .set() functions, as well as the .x, .y, .z, etc. accessors should also be used as much as possible, for this same reason. Thanks crew!

3 Likes

Correct

1 Like