Add Matrix3D::scaling

The Matrix3D class has functions to compute a translation matrix, a rotation matrix, a matrix from any 2D affine transform and even a frustum matrix. However it’s lacking a simple scaling matrix. As this is a very common thing in computer graphics, how about adding this simple function?

static Matrix3D scaling (Vector3D<Type> scale) noexcept
{
    return { scale.x, 0,       0,       0,
              0,       scale.y, 0,       0,
              0,       0,       scale.z, 0,
              0,       0,       0,       Type (1) };
}

I’d like to propose something a bit more detailed than simply the ability to scale a Matrix3D. There are other functions that would be useful and pertinent to 3D graphics: translation, reflection, shearing, and stretching/squeezing. Even more are projections of sorts.

The math library typically used in games is GLM, which contains the assortment of vectors, points, matrices, and the maths that go along with them. For influence, you can see some matrix functions here: https://glm.g-truc.net/0.9.1/api/a00237.html

I‘m aware of glm and indeed, I was happy to get rid of that dependency for a simple project that now only uses the juce Matrix3D class :smile:

For more complex stuff I would always chose glm, however for simple stuff I like to do as much as possible with juce and the std library to keep the dependecy count low. I think this is the target use case for the juce Matrix3D class and a scaling function beneath the existing translation and rotation function would complete this class in a senseful way.

Well, I whipped this up if you want to give it a shot.
juce_Matrix3D.h (11.0 KB)

1 Like

Nice! To be honest I have not that much time to do some extensive testing and my current application needs nothing more in addition to the existing functionality than a scaling matrix, however it should not be to hard to write some unit tests that simply compare the results of your implementation against glm… will see if I find some time to do this.

Is the juce team even interested in extending Matrix3D like that, @fabian, @jules?

It should be straightforward enough to write some tests. Just pluck a resulting mat4 from glm and paste its guts into a Matrix3D for comparison.

Any update on this ?
Would be great to have this inside official juce.
Quaternion could use some stuff as well :slight_smile:

I’ll add my matrix compares. I had to write them as free functions, but would make a good operator==:

template<typename FloatType>
static inline bool compare (const juce::Matrix3D<FloatType>& a, const juce::Matrix3D<FloatType>& b)
{
    for (size_t i = 0; i < 16; ++i)
        if (a.mat[i] != b.mat[i])
            return false;

    return true;
}

template<typename FloatType>
static inline bool compare (const juce::Matrix3D<FloatType>& a, const juce::Matrix3D<FloatType>& b, float epsilon)
{
    for (size_t i = 0; i < 16; ++i)
        if (std::abs (a.mat[i] - b.mat[i]) > epsilon)
            return false;

    return true;
}

I tried implementing @jrlanglois matrix functions but this doesn’t look good :

    /** Returns a matrix which will apply a translation specified by the provided vector. */
    Matrix3D translated (Vector3D<Type> delta) noexcept
    {
        return { mat[0], mat[1], mat[2], mat[2] * delta.x,
                 mat[5], mat[6], mat[7], mat[2] * delta.y,
                 mat[9], mat[10], mat[11], mat[2] * delta.z,
                 mat[13], mat[14], mat[15], mat[16] };
    }

It’s using mat[2] like it’s been copied everywhere, and accessing mat[16] which just doesn’t exist…
And it’s multiplying the translation values instead of adding… Am I missing something or is this code completely weird ???

Also, the operation for translation vector is on the column, where the juce matrix3d seems to operate the translation vector in line (which is actually implemented correctly in @jrlanglois constructor from vector function).

1 Like