Question

I'm terrible with matrix maths but I have a situation where I need to scale one. The matrix is an instance of a custom class defined here and my scaling object is a vector containing 3 floats (x,y,z). I'd like the actual code I need rather than a generic explanation because I've already gone down that path and just don't understand the maths involved. Fortunately what I'm trying to accomplish is reasonably trivial once I can scale the matrix.

To clarify here is the code I'm updating. It iterates over a hierarchy of linked objects with relative transforms and updates mat& to an absolute transform:

void LocalModelPiece::GetPiecePosIter(CMatrix44f* mat) const
{
if (parent) {
    parent->GetPiecePosIter(mat);
}

if (pos.x || pos.y || pos.z) { mat->Translate(pos.x, pos.y, pos.z); }
// --> My problem is here. There is no Scale() method, I need one. <--
if (scale.x!=1.0f || scale.y!=1.0f || scale.z!=1.0f) { mat->Scale(scale.x, scale.y, scale.z); }
if (rot[1]) { mat->RotateY(-rot[1]); }
if (rot[0]) { mat->RotateX(-rot[0]); }
if (rot[2]) { mat->RotateZ(-rot[2]); }

}

Was it helpful?

Solution

I looked at the API link you provided, and based on that, this is how I would implement a scaling method for the matrix class so that it's consistent with the existing Translate() and Rotate() methods. That is, it does a right side multiplication with a scaling matrix.

Though personally I find it a bit weird, because the API uses OpenGL style matrices. That means that a right side multiplication applies the new transformation before all the other transformations that exist in the matrix, where as left side multiplication would apply it after the other transformations. So I'm not sure if that's what you want here. You might have to do all the transformations in the reverse order or do a left side multiplication yourself.

void CMatrix44f::Scale(float scalex, float scaley, float scaley) 
{
  /* the function should be equivalent to doing this:
  CMatrix44f scalemat;
  scalemat[0] = scalex;
  scalemat[5] = scaley;
  scalemat[10] = scalez;
  *this = Mul(scalemat);
  */

  m[0] *= scalex;
  m[1] *= scalex;
  m[2] *= scalex;
  m[3] *= scalex;

  m[4] *= scaley;
  m[5] *= scaley;
  m[6] *= scaley;
  m[7] *= scaley;

  m[8] *= scalez;
  m[9] *= scalez;
  m[10] *= scalez;
  m[11] *= scalez;
}

OTHER TIPS

It's not clear to me what you wish to scale. Is it the matrix itself, or do you intend to use it to scale another vector?

If you're talking about a vector in 3D space, I don't see how a 4x4 matrix can be what you want. Scaling a vector in 3D space using a matrix would mean putting the scaling factors on the diagonal of the matrix; off-diagonal elements are zero.

You confuse me when you link to a 4x4 matrix. Are you sure that's what you want?

I think you want this:

alt text

Here's some pseudo-code to show how it's done:

for (int i = 0; i < 3; ++i)
{
    v_prime[i] = c[i]*v[i];
}

If you want to scale a 3x3 matrix, it'd look like this:

alt text

Here's some pseudo-code to show how it's done:

for (int i = 0; i < 3; ++i)
{
    for (int j = 0; j < 3; ++j)
    {
        m_prime[i][j] = c[i]*m[i][j];
    }
}

Note that both of these solutions follow from your statement that your scaling vector has three components. If that's not the case, all bets are off.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top