W3C home > Mailing lists > Public > public-fx@w3.org > July to September 2012

Re: Matrix4x4

From: Chris Marrin <cmarrin@apple.com>
Date: Wed, 25 Jul 2012 09:24:44 -0700
Cc: public-fx@w3.org
Message-id: <4BA0DD8C-5E42-42B2-BB83-6AF1BE87CA04@apple.com>
To: Igor Oliveira <itrindade.oliveira@gmail.com>

On Jul 23, 2012, at 5:39 PM, Igor Oliveira <itrindade.oliveira@gmail.com> wrote:

> Hi,
> 
> Some months ago Dean Jackson submitted a proposal for a more native matrix class[1]. Some new ideas were proposed, so i got these ideas and added in the spec.

This set looks nicely complete. A few things:

1) Having the decomposer return Euler angles (http://en.wikipedia.org/wiki/Euler_angles) for the rotation component is problematic. As has been discussed on this list in the past, that representation has issues with gimbal lock (http://en.wikipedia.org/wiki/Gimbal_lock). It would be better to return a quaternion (http://en.wikipedia.org/wiki/Quaternion). But quaternions are hard to deal with, which can be solved with (4) below.

2) Since this deals with floats and doubles, I assume the internal representation would have to be doubles. For efficiency and use by other components (like WebGL) this could be a performance issue. Many mobile platforms have vector hardware, but it only works in floats. So representing everything in doubles precludes the use of that hardware. And for passing to WebGL, copying to a float array would require conversion from double to float, which is fairly expensive on most platforms. Perhaps there should be MatrixFloat and MatrixDouble variants of this class?

3) It would be nice to integrate this with WebGL. That would allow you to pass the matrix directly to a WebGL function without first copying it into a Float32Array. Doing this begs the question of where does this spec go? It would be better if it weren't in the CSS Transform spec, to avoid requiring WebGL to depend on that spec. It is probably too specific to go into the Typed Array spec. Perhaps it should be its own Linear Algebra spec, which leads me to...

4) It's unfortunate this uses separate scalar parameters and array sequences for passing vector data. It would be much better if this matrix class were part of a more complete linear algebra library. Such a library could get quickly out of hand, with Line, Frustum and Sphere classes. But it seems like the bare minimum would do. That means 2, 3 and 4 component vectors and a rotation object, all with float and double variants. 

It might seems like you could get away without a 4 component vector, but you really can't. When multiplying a vector by a Matrix you are always effectively multiplying 4 components, and being able to get access to that 4th component allows you to useful computations in a homogeneous coordinate system. It effectively lets you manipulate the perspective part of the vector.

The Rotation object can be defined in such a way that it can be accessed using simple axis/angle parameterization, but is internally represented as a quaternion, which makes it more efficient and not susceptible to the problem mentioned in (1). You can even make it possible for the object's API to handle Euler angles.

This linear algebra library would need 2 matrix classes, 6 vector classes and 2 rotation classes, for a total of 10. But you can use the "template" style in the spec, as in the Typed Array spec (https://www.khronos.org/registry/typedarray/specs/latest/). Then you'd just need to describe the functions for Matrix, Vector and Rotation and then show the specializations.
 
> 
> 
> // -----------------------------------------------------------------------
> // CONSTRUCTORS
> // -----------------------------------------------------------------------
> 
> 
> [
> // Creates an identity matrix
> Constructor(),
> 
> // Creates a new matrix from the value passed in (a CSS transform string with
> // matrix() or matrix3d() - not other functions).
> Constructor(in DOMString string),
> 
> // Creates a new matrix from the Float32Array value passed in.
> // The array has a length of 6 for a 2d matrix (see ref[2]), or 16 for a 4x4 matrix).
> Constructor(in Float32array array),
> 
> // Creates a new matrix from the Float64Array value passed in.
> // The array has a length of 6 for a 2d Matrix (see ref[2]), or 16 for a 4x4 matrix.
> Constructor(in Float64Array array),
> 
> // Creates a new matrix identical to the passed matrix.
> Constructor(in Matrix4x4 matrix),
> 
> // Creates a new matrix from the array of 6 or 16 values passed in
> Constructor(in sequence array)
> 
> // Creates a new matrix from the decomposed values
> Constructor(in sequence<float> xyz,
> in sequence<float> rotation,
> in sequence<float> scale,
> in sequence<float> perspective);
> ]
> 
> 
> interface Matrix4x4 {
> 
> // These attributes are simple aliases for certain elements of the 4x4 matrix
> attribute double a; // alias for m11
> attribute double b; // alias for m12
> attribute double c; // alias for m21
> attribute double d; // alias for m22
> attribute double e; // alias for m41
> attribute double f; // alias for m42
> 
> 
> attribute double m11;
> attribute double m12;
> attribute double m13;
> attribute double m14;
> attribute double m21;
> attribute double m22;
> attribute double m23;
> attribute double m24;
> attribute double m31;
> attribute double m32;
> attribute double m33;
> attribute double m34;
> attribute double m41;
> attribute double m42;
> attribute double m43;
> attribute double m44;
> 
> 
> // -----------------------------------------------------------------------
> // TRANSFORMATION FUNCTIONS
> // -----------------------------------------------------------------------
> 
> 
> // Multiply this matrix by otherMatrix on the right (this = this * otherMatrix)
> void multiply(in Matrix4x4 otherMatrix);
> 
> 
> // Return a new matrix that is this matrix multiplied by otherMatrix on the right
> // (result = this * otherMatrix)
> [Immutable] Matrix4x4 multipliedBy(in Matrix4x4 otherMatrix);
> 
> 
> // Multiply this matrix by otherMatrix on the left (this = otherMatrix * this)
> void leftMultiply(in Matrix4x4 otherMatrix);
> 
> 
> // Invert this matrix. Throw an exception if the matrix is not invertible
> void invert() raises (DOMException)
> 
> 
> // Return the inverse of this matrix. Throw an exception if the matrix is not invertible
> [Immutable] Matrix4x4 inverseMatrix() raises (DOMException);
> 
> 
> // Translate this matrix in place using the passed values.
> // Undefined or NaN parameters will use a value of 0. This allows the 3D form to used for
> // 2D operations.
> void translate(in double x,
> in double y,
> in double z);
> 
> 
> // Return a new matrix that is this matrix translated by the passed values.
> // Undefined or NaN parameters will use a value of 0. This allows the 3D form to used for 2D operations
> [Immutable] Matrix4x4 translatedBy(in double x,
> in double y,
> in double z);
> 
> 
> // Scale this matrix in place using the passed values.
> // Passing undefined or NaN for scaleY uses the value of scaleX.
> // Passing undefined or NaN for scaleZ uses the value 1.0.
> void scale(in double scaleX,
> in double scaleY,
> in double scaleZ);
> 
> 
> // Return a new matrix that is this matrix scaled by the passed values.
> // Passing undefined or NaN for scaleY uses the value of scaleX.
> // Passing undefined or NaN for scaleZ uses the value 1.0.
> [Immutable] Matrix4x4 scaledBy(in double scaleX,
> in double scaleY,
> in double scaleZ);
> 
> 
> // Rotate this matrix in place using the passed values. Each parameter defines
> // an angle of rotation around the (corresponding) X, Y or Z axes.
> // Passing undefined or NaN for rotY and rotZ instead rotates around the Z axis
> // (i.e. rotX = 0, rotY = 0, rotZ = )
> // Input values are in radians.
> void rotate(in double rotX,
> in double rotY,
> in double rotZ);
> 
> 
> // Return a new matrix that is this matrix rotated by the passed values. Each parameter
> // defines an angle of rotation around the (corresponding) X, Y or Z axes.
> // Passing undefined or NaN for rotY and rotZ instead rotates around the Z axis
> // (i.e. rotX = 0, rotY = 0, rotZ = )
> // Input values are in radians.
> [Immutable] Matrix4x4 rotatedBy(in double rotX,
> in double rotY,
> in double rotZ);
> 
> 
> // Rotate this matrix in place using the passed values. The x, y and z values
> // define a vector about which the matrix is rotated.
> // The value of angle is in radians.
> void rotateAxisAngle(in double x,
> in double y,
> in double z,
> in double angle);
> 
> 
> // Return a new matrix that is this matrix rotated using the passed values. The x, y and z values
> // define a vector about which the matrix is rotated.
> // The value of angle is in radians.
> [Immutable] Matrix4x4 rotatedByAxisAngle(in double x,
> in double y,
> in double z,
> in double angle);
> 
> 
> 
> // -----------------------------------------------------------------------
> // CONVERSION FUNCTIONS
> // -----------------------------------------------------------------------
> 
> 
> // Copy the matrix elements into a Float32Array
> // Throws an exception if the input is invalid (e.g. wrong length, etc).
> void copyIntoFloat32Array(inout Float32Array array) raises (DOMException);
> 
> // Copy the matrix elements into a Float64Array
> // Throws an exception if the input is invalid (e.g wrong length, etc)
> void copyIntoFloat64Array(inout Float64Array array);
> 
> // return a Float32Array (length 16) with the values [m11, m12, ...]
> Float32Array toFloat32Array();
> 
> // return a Float64Array (length 16) with the values [m11, m12, ]
> Float64Array toFloat64Array();
> 
> // Returns a string that is in the format of a CSS transform.
> // (e.g. "matrix3d(m11, m12, ...)")
> DOMString toString();
> 
> 
> 
> // -----------------------------------------------------------------------
> // CAMERA FUNCTIONS
> // -----------------------------------------------------------------------
> 
> 
> // Multiply this matrix by a matrix representing a perspective transformation.
> // The eyex, eyey and eyez values define the position of the eye point.
> // The centerx, centery and centerz define the position of the reference point.
> // The upx, upy and upz define the direction of the up vector.
> void lookAt(in double eyex, in double eyey, in double eyez,
> in double centerx, double centery, in double centerz,
> in double upx, in double upy, in double upz);
> 
> 
> // Multiply this matrix by a matrix representing an orthographic transformation.
> // The left and right values define the coordinates for the left and right vertical clipping planes.
> // The bottom and top values define the coordinates for the bottom and top horizontal clipping planes.
> // The nearVal and farVal values define the distances to the nearer and farther depth clipping planes.
> void ortho(in double left, in double right,
> in double bottom, in double top,
> in double nearVal, in double farVal);
> 
> // Multiply this matrix by a matrix representing a perspective transformation.
> // The fovy value defines the field of view angle, in radians, in the y direction.
> // The aspect value defines the aspect ratio that determines the field of view in the x direction.
> // The zNear value defines the distance from the viewer to the near clipping plane.
> // The zFar defines the distance from the viewer to the far clipping plane.
> 
> void perspective(in double fovy, in double aspect,
> in double zNear, in double zFar);
> // -----------------------------------------------------------------------
> // DECOMPOSITION FUNCTION
> // -----------------------------------------------------------------------
> 
> // Decompose this matrix into the passed values. The xyz value represents the translation,
> // where xyz[0], xyz[1] and xyz[2] represent x, y and z, respectively. The rotation value represents
> // the rotated angles, where rotation[0], rotation[1], rotation[2] represent rotateX, rotateY and
> // rotateZ, respectively in radians. The perspective value represent a perspective projection matrix,
> // where perspective[0] is the field of view angle, in radians, in the y direction. perspective[1]
> // is the aspect ratio that determines the field of view, in radians, in the x direction.
> // perspective[2] is the distance from the viewer to the near clipping plane, perspective[3] is
> // the distance from the viewer to the far clipping plane.
> 
> void decompose(inout sequence<float> xyz,
> inout sequence<float> rotation,
> inout sequence<float> scale,
> inout sequence<float> perspective);
> };
> 
> [1] http://lists.w3.org/Archives/Public/public-fx/2012JanMar/0007.html
> 
> 

-----
~Chris Marrin
cmarrin@apple.com
Received on Wednesday, 25 July 2012 16:25:16 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Wednesday, 25 July 2012 16:25:16 GMT