Averaging Matrices

Started by
7 comments, last by Bosh 18 years, 9 months ago
How would I go about taking two matrices and finding the average between the two? And if you can answer that, is it possible to have different matrices with different weights combined together? I'm doing this for animation since I haven't found a way to have more than 2 track working together in DirectX. I can just go through and transform the vertices and then weight the transformed ones, but I'm looking for a way that I can do it before it hits the shader.
Advertisement
Assuming your matrices are relatively sane (just rotations and translations) and you want a relatively smooth averaging, one method would be to extract the translation components and get a weighted average as normal. Then transform the rotation information of each matrix into a pair of quaternions. The quaternions can then be interpolated between with slerp. Then combine the new quaternion and the weightee average of the translations into a new matrix.
Would taking Matrix1 and multiplying it by it's weight in a scale matrix and adding it to Matrix2 and multiplying that by it's weight in a scale matrix work?

Scale Matrix
[Weight, 0, 0, 0]
[0, Weight, 0, 0]
[0, 0, Weight, 0]
[0, 0, 0, Weight]
Not really. Simple linear combinations of general transformation matrices won't preserve the proper invariants. For lack of a better term, such an approach will make things look really funky.
No, as SiCrane said you cannot in general add matrices to "add" their effect. For example, if you have a matrix A that rotates your object X degrees around some axis then the matrix (A+A) does not rotate your object (X+X) degrees around the same axis.

The best (and most common) way of interpolating 4x4 matrices for animation is to use linear interpolation of the translation (position) and SLERP for the orientations (using quaternions).

- Kasper Fauerby
As they say. You don't "add" rotations, you multiply them, that's why averaging via adding doesn't work as you expect.
It's still a legitimate operation, just it doesn't do what you want it to do.
Let's you draw some mesh M with matrix C=A+t*(B-A)=(1-t)*A+t*B. It is the weighted average.
Result will be the same as if you would linearly interpolate vertices between 2 meshes, mesn M1 that is result of transforming original mesh with A and mesh M2 that is result of transforming original mesh with B
It is clear enough that it will not do what you want it to do - mesh will not correctly rotate between 2 rotations. For example, if it's bottle that is rotated[between M1 and M2] 180 degrees around axis, you'll get bottle collapsing into line, and then expanding back rotated. Sort of weird. [grin]

In general, interpolation of rotation between matrix1 and matrix2 is doable as
f(a)=exp(log(matrix1)+a*(log(matrix2)-log(matrix1)))=exp((1-a)*log(matrix1)+a*log(matrix2)))
and average as
exp(0.5*(log(matrix1)+log(matrix2)))
but it requirs matrix logarithm and exponentiation, (which in core is rather similar to this quaternion thingy they talk about, but is quite a lot more complex and weird.) So better just use quaternions.

For performing weighted change between one quaternion and other quaternion (probably what you really meant by averaging), use SLERP.

[Edited by - Dmytry on July 4, 2005 4:26:08 AM]
I'm facing almost the same problem as Bosh: I like to combine some quaternions (let's say 4 or 5) to perform animation blending.
If I like to combine just 2 I use slerp or lerp, but what should I do to combine 4 or 5 quaternion, each of them having some weight attached?
Quote:I'm facing almost the same problem as Bosh: I like to combine some quaternions (let's say 4 or 5) to perform animation blending.
If I like to combine just 2 I use slerp or lerp, but what should I do to combine 4 or 5 quaternion, each of them having some weight attached?
You might look into quaternion squad().
I have found a way to get out all of the rotations, scales, and translations. Except for the scale of x. It comes out way off every time and I don't know how to get it out. All of the numbers come out a bit off, you know, like .0001 off. So it may be float inaccurcy. If you have any suggestions please let me know. Oh, and I know the the way to find the scale of z is a little bit slow, any suggestions on that would be great as well.

Matrix mat = Matrix.Scaling(2, 4, 2) * Matrix.RotationYawPitchRoll(0, 0.7853981634f, 1.570796327f) * Matrix.Translation(10, 2, 7);			Vector3 angle = new Vector3();Vector3 scale = new Vector3();Vector3 translate = new Vector3();translate.X = mat.M41;translate.Y = mat.M42;translate.Z = mat.M43;angle.X = (float)(Math.Atan(mat.M23/mat.M33));angle.Y = (float)(Math.Atan(-mat.M13/(mat.M23/Math.Sin(angle.X))));scale.Z = -mat.M13/(float)(Math.Sin(angle.Y));angle.Z = (float)(Math.Acos(mat.M22*(Math.Cos(angle.Y)/mat.M12)-(Math.Sin(angle.X)*Math.Sin(angle.Y))/Math.Cos(angle.X)));scale.X = mat.M11/(float)(Math.Cos(angle.Y) * Math.Cos(angle.Z);scale.Y = mat.M12/(float)(Math.Cos(angle.Y) * Math.Sin(angle.Z));

This topic is closed to new replies.

Advertisement