Search code examples
mathmatrixmatrix-multiplicationscaling

Creating a matrix to SCALE around an arbitrary axis?


I know how to create a rotation matrix around an arbitrary axis. But I'm looking to SCALE around an arbitrary axis. The goal is to produce a ray-trace where the ray has thickness. Ultimately what I want to do is specify ray's start/end point, and a thickness.

Then the algorithm would scale all candidate faces around the ray's axis, and then I can do a simple DoesLineIntersectTriangle test.

However, online I can find dozens of examples of creating a rotation matrix around an axis... but I can't find even a single example of SCALING around an axis.

The only way I can think of would be to rotate the matrix so the ray is, say, aligned to the Z axis, then I can scale everything else's xy axis. But that seems like a hacky way of doing it. Is there a known algo for scaling around an axis?

(Preferably in C++, though I can convert from other languages)

So, this appears to be a NON-working concept:

Matrix& Matrix::ScaleAroundAxis3D(Vector theAxis, float theScale)
{
    Matrix aMat;
    aMat.RotateFromTo(theAxis,Vector(0,0,-1));
    aMat.Scale(theScale,theScale,1.0f);
    aMat.Multiply(&BuildRotateFromToMatrix(Vector(0,0,-1),theAxis));
    return Multiply(&aMat);
}

Producing this result when I specify the axis as Vector(.707,0,.707): Picture of results

Red is the original quad, yellow line is the axis, green is the quad transformed via the function above. But shouldn't the green result lie in the same plane as the red quads, only appropriately shrunk around the axis?


Solution

  • Things become easier when the axis are coincident with the objects.

    Translate main axis to any point in the axis-line you have.
    Rotate main axis so the Z-axis is axis of your cylinder. I think the typical "LookAt" function used in OpenGL does both translation & rotation in one matrix.
    Now you can scale the objects.
    Rotate back, translate back, in this order. Or use the inverse of the LookAt matrix.

    If you need cylinder-triangle collision I recomend the same method. Once you have things in the axis-line system you only need X,Y coordinates, so you have a 2D circle-triangle intersection, which is much easier than the 3D problem.