Matrix Multiplication in C[++]
-
@cjthompson said:
is there any reason (transformation * transformation) won't work?
The doc says
*()
isTransformation * Point3d => Transformation
. I'm in need ofTransformation * Transformation => Transformation
.My application is animation. I may be turning 180 degrees by, for example, turning 0.5 degrees over each of 360 frames. If you have
xform
, a "turn 0.5 degrees" transformation, and you callinstance.transform!( xform )
thetransform!()
method multiplies the existing transformation by the newxform
matrix.It also pushes undo info onto the undo stack, which you don't want.
instance.move!( xform )
is supposed to be the same asinstance.transform!()
minus the undo stack. Unfortunately, it's buggy. It forgets to multiply, and just replaces the old transformation matrix with the new one (losing all existing scales, rotations and location). Bad bug.So I'm getting
xform
via API calls, then multiplying (in Ruby) the existing and new transformations and giving the result tomove!()
. It works, but using the matrix multiplication code that's there already would be a lot faster. (The matrix multiplication is so fundamental to 3d geometry that it may be hand-tooled assembler.) -
transformation * transformation
works.The docs says
@unknownuser said:
point1
A Point3d, Vector3d, or Transformation object. -
@thomthom said:
transformation * transformation
works.The docs says
@unknownuser said:
point1
A Point3d, Vector3d, or Transformation object.Blind me! Many thanks.
-
Blind me? Maybe it was, "Lucky me."
Transformation * Transformation multiplies the 3x3 rotation/scale matrix. It does not handle location. My code multiplies the 4x4 matrices. Here are the results:
xform:
1.0, 0.0, 0.0, 0.0 0.0, 1.0, 0.0, 0.0 0.0, 0.0, 1.0, 0.0 20.0, 0.0, 0.0, 1.0
Asked for
Transformation.rotation( [0,0,0], [0,1,0], 30 )
. Got:0.866025403784439, 0.0, -0.5, 0.0 0.0, 1.0, 0.0, 0.0 0.5, 0.0, 0.866025403784439, 0.0 0.0, 0.0, 0.0, 1.0
Used
Transformation * Transformation
, thenmove!()
.xform:
0.866025403784439, 0.0, -0.5, 0.0 0.0, 1.0, 0.0, 0.0 0.5, 0.0, 0.866025403784439, 0.0 20.0, 0.0, 0.0, 1.0
Not my idea of rotating around the origin. So I tried again, using my own matrix multiplication:
xform:
0.866025403784439, 0.0, -0.5, 0.0 0.0, 1.0, 0.0, 0.0 0.5, 0.0, 0.866025403784439, 0.0 17.3205080756888, 0.0, -10, 1.0
My own version appears to rotate around the origin.
Anybody wanting to fiddle with this, here's a little Matrix class. You create a Matrix with
Matrix.new( nrows, ncols, [array of values] )
. From a Transformation, that'sMatrix.new( 4, 4, xform.to_a() )
. Individual values may be retrieved by subscripting:m1[3,3]
is the global scale factor, Wt. You multiply by multiplying:m1 * m2
. (instance_xform * new_xform
. It's not commutative.)class Matrix =begin You can multiply one matrix by another with this class. In m1 * m2, the number of rows in m1 must equal the number of columns in m2. This code does absolutely no checking. Program must check sizes before calling this code! (Application herein; square matrices of equal size, where this is not an issue.) =end attr_reader ;nrows, ;ncols, ;values def initialize( nrows, ncols, values ) @nrows = nrows @ncols = ncols @values = values end # of initialize() def * ( m2 ) vals = [] for r in 0..(@nrows-1) for c in 0..(m2.ncols-1) vals.push( row_col(row( r ), m2.col( c )) ) end end return Matrix.new( @nrows, m2.ncols, vals ) end # of *() def [] ( row, col ) return @values[ row * @ncols + col ] end # of []() def col( c ) ret = [] for r in 0..(@nrows-1) ret.push( @values[r*@ncols + c] ) end return ret end # of col() def row( r ) start = r * @ncols return @values[ start .. (start + @ncols - 1) ] end # of row() def row_col( row, col ) ret = 0 for i in 0..(row.length()-1) ret += row[ i ] * col[ i ] end return ret end def inspect() ret = '' for r in 0..(@nrows-1) for c in 0..(@ncols-1) ret += self[r, c].to_s ret += ', ' if c < (@ncols-1) end ret += "\n" end return ret end # of inspect() end # of class Matrix
Anybody not believing what I say (that included me!) is invited to try for themselves.
-
I have not read much of this thread yet, just enough to see that you can multiply a transformation by a point3d?????
That might be the missing link for moving an object to a specified point, retaining scale/rotation and not having to tweak the matrix manually. I'll investigate that, along with Martin's code later tonight if all goes well,
Chris - I'm excited about this development.
-
Nope, my mistake. Now that i've had a chance to look at it, and think it through, multiplying a transformation by a point 3d moves the transformation by the vector defined by the point at the component axis to the point specified.
I guess my prefered way to translate to a specific point is still done be finding the vector to that point from the given point and then
.transform!
to that point.Chris
Now its time to read Martin's post thoroughly.
-
My third screenshot could have been clearer. This is an elaboration:
-
This is what I learned when I wrote my MentalRay transformation matrix plugin.
Maybe this info can be of some help:A transformation matrix is made of these components and multipled in the following order:
Scale pivot point: point around which scales are performed [Sp]
Scale: scaling about x, y, z axes [S]
Shear: shearing in xy, xz, yx [Sh]
Scale pivot translation: translation introduced to preserve existing scale transformations when moving pivot.
This is used to prevent the object from moving when the objects pivot point is not at the origin and a non-unit scale is applied to the object [St].Rotate pivot: point point about which rotations are performed [Rp]
Rotation orientation: rotation to orient local rotation space [Ro]
Rotation: rotation [R]
Rotate pivot translation: translation introduced to preserve exisiting rotate transformations when moving pivot.
This is used to prevent the object from moving when the objects pivot point is not at the origin and the pivot is moved. [Rt]Translate: translation in x, y, z axes [T]
The transformation matrix is then constructed as follows:
[Sp(Inverse)] x [S] x [Sh] x [Sp] x [St] x [Rp(Inverse)] x [Ro] x [R] x [Rp] x [Rt] x [T]
-
Can anyone explain why (transformation1 * transformation2) isn't the same as (transformation2 * transformation1)?
Anyways, it looks like if you use move!, you have two options, from a practical standpoint:
instance.move!(newTransformation*instance.transformation)
, which is essentially the same as (instance.transform!(newTransformation)) and
instance.move!(instance.transformation*newTransformation)
, which will apply the transformation according to the component's axes. -
@cjthompson said:
Can anyone explain why (transformation1 * transformation2) isn't the same as (transformation2 * transformation1)?
+1
-
I like those lines of code Chris, I want to test those later tonight.
Chris
Advertisement