Standardizing InPlace, ToNew, and ToRef for Matrix, Vector3, and Quaternion?

Is there any leaning toward standardizing the “plain” functions and whether they are InPlace or ToNew?

Or is there too much code that is dependent on the current functionality?

In another thread:

I was just reviewing the Matrix, Vector3, and Quaternion functions and also saw that insert() is an InPlace function. Is there any leaning toward standardizing the “plain” functions and whether they are InPlace or ToNew? Most Vector3 plain functions (no suffix) create a new object and there is a corresponding InPlace function. Vector3.normalize() is the one exception in that it is the only non-suffix function that is in place and it has a corresponding ToNew function instead.

Matrix.invert() is also in place as noted above (and invertToRef() doesn’t exist).

Any missing InPlace, ToNew or ToRef could be created from the others, but ToRef is most useful, by default avoiding new object creation and not modifying the source object.

  • InPlace => ToRef(this)
  • ToNew => ToRef(new Vector3())
1 Like

Just from memory and from what I have seen out there, but inverting a matrix seems to be a common thing in game dev. Anyway, why not leaving it and aliasing it to “.invertInPlace”. Nothing broken this way :slightly_smiling_face:

For matrix, it does seem to exist: Babylon.js docs


Btw. to be fair we do get a mouseover-hint what it does:

Yes. I overlooked Matrix.invertToRef().

Matrix.invert(), like Vector3.normalize(), is “in place.”

What I don’t see is Matrix.invertToNew(), though it can easily be simulated with matrix.invertToRef(new Matrix()). Just like “In Place” can be simulated by matrix.invertToRef(matrix).

The fact that functions vary in their non-suffix implementation (sometimes “InPlace,” mostly “ToNew”) is confusing to me, which means I always have to look them up.

I’m usually creating a chain of math for which I want everything InPlace. If I want a new object, I’ll do so with the first function in the chain.

Here’s a quaternion chain of two functions that highlights my confusion.

this.#velocityQuaternion.copyFrom(dm.rotationQuaternion).invertInPlace();

Note that Quaternion.invert() returns a new object. And there is no Quaternion.InvertToRef(), only an .invertInPlace(). And Matrix.invert() is in place, and there is a Matrix.InvertToRef().

If Quaternion.InvertToRef() existed, the code above becomes:

dm.rotationQuaternion.invertToRef(this.#velocityQuaternion)

I would also argue that ToRef functions need to be universal unless specific functions can be optimized for space with ToNew.

The first line of code above might be better with a Quaternion.invertToRef(), here’s my untested guess for that function:

invertToRef = (other) => {
    this.conjugateToRef(other);
    const len2 = other.lengthSquared();
    if (len2 != 0 && len2 !=1) {
        other.scaleInPlace(1/len2);
    }  
    return other;
}

Wanna do a PR to add the Quaternion.invertToRef ?

Yes, if timing isn’t important.

I’m working up to being able to do a PR. I’ve got a small amount of progress on physics debug classes. Learned enough of TypeScript to get by. And have a partial build system (by copying a random-ish copy of babylon.d.ts and using tsc). My “dev” system is termux on Android, so it’s difficult to use the full “contributor’s page” tools.

Once I get integrated with a fork from git, I’ll figure out how to do a PR. Might be a while :frowning:

Edit: found another function that would save me compute time: Matrix.ComposeToArray(q,t,array,offset). I don’t happen to need scale, but wondering if including it would make it generally useful. It’s useful in the innards of thinInstances when writing directly to mesh._thinInstanceDataStorage.matrixData

3 Likes