W3C home > Mailing lists > Public > public-fx@w3.org > January to March 2012

RE: Matrix4x4 proposal

From: Timm Drevensek <Timm.Drevensek@igd.fraunhofer.de>
Date: Wed, 18 Jan 2012 12:05:34 +0100
To: <public-fx@w3.org>, <public-declarative3d@w3.org>
Message-ID: <06a401ccd5d1$2671b8d0$73552a70$@igd.fraunhofer.de>
Hi,

 

this is a very interesting discussion :)

 

I had started a similar discussion in the “W3C - declarative 3D” Group about a base data types (http://www.w3.org/community/declarative3d/wiki/Base_Types)

 

It way born from the fact that in 3D we need such types. But beside the high performance matrix math we also need some base data types for vectors and quaternions. While our own first implementation of such math works on single values and a copy on return, I was looking for existing JavaScripting libraries and started to test performance on such libraries (https://github.com/x3dom/x3dom/blob/refactoring_math/test/benchmark/index.html) with the result, that not all of them where build on performance reasons or does not deliver the functionality we needed.

 

So while experimenting and implementing inside a branch (https://github.com/x3dom/x3dom/blob/refactoring_math) of our system, I found also some issues like the fact, that TypedArrays are fast…as long as you don’t allocate new ones…what will happen when you are making some more complex calculation.

Also the performance of dereferencing single elements from such arrays isn’t as performing as native Arrays…but I believe both are issue on current browser implementations end will be fixed someday :)

 

-          So what I believe is, beside performance reasons matrix math should also have a look on an user friendly api.

-          Also it would be nice to have vector and quaternion math.

-          Another issue is that we should work on a container, which can be transferred to a api like WebGL by reference.

 

So my belief on a design for function calls:

The low level api has to work only on references with static like functions. There should be no copy inside any provided arithmetic function. This would only lead to that the end user will use such low performing functions without knowing it.

 

So at a low level functionality, our math now is working on TypedArrays (https://github.com/x3dom/x3dom/blob/refactoring_math/src/lang/Math.js) which allows us to use functionality like “views to subarrays” and by this “arrays of vectors” like Vec3[n]. So our function calls look like this:

 

var source, operator_a, operator_b, result = new Float32Array(16);

mat4x4.mult(source, operator_a, result);

mat4x4.mult(result, operator_b, result);

 

This is fast but the semantic is very assembler like and not nice to use.

When you are making a more complex calculation you will get stuck with unreadable code. So what I did was to encapsulate the low level functions to a more high level matrix container (https://github.com/x3dom/x3dom/blob/refactoring_math/src/fields.js#L985), encapsulating the TypedArray for single values and the arithmetic functionality.

 

Also we add two functionalities to this api: copy & always return this.

-          The return of a “this” pointer for any operation allows the user to make a “paper looking like” matrix math like “c = a * b”.

-          As we are using references only, it leads us to the need of a copy operator…because we always act on the left side of the operator and need to copy sometimes.

 

So this design will lead to ability of doing code like this:

 

var source, operator_a, operator_b = new x3dom.SFMatrix4f();

var result = source.copy().mult(operator_a).mult(operator_b);

 

So we have reduced the use of “copy on return” to a single function.

On the other hand we can use performing math without losing an user friendly coding style.

 

 

Beside this design of api calls, we also collected a list of arithmetic functionality which could/should be available:

 

* Constructor for SFMatrix4f, takes 16 params

** Constructor-like methods that return special matrices: identity(), zeroMatrix(), translation(), scale(), rotationX()/-Y()/-Z()

* Convenience functions for setting values (e.g. setValue(v0,v1,v2,v3))

* Converter methods from string to matrix etc.

* Converter methods from matrix to GL data types

* Set matrix partly: setTranslate(t), setScale(s)

* Get column vectors: e0(), e1(), e2(), e3()

** ...and matrix elements

* Get view matrix: lookAt(from, at, up)

* Matrix multiplication: mult(m)

* Point multiplication (with transl.): multMatrixPnt(p)

* Vector multiplication (w/o transl.): multMatrixVec(v)

* Point mult. (incl. projection): multFullMatrixPnt(p)

* Mult. with scalar: multiply(s)

** Optimization for s = -1: negate()

* Add matrices: add(m)

** Optimization for linear operation: addScaled(m, s)

* Comparison: equals(m, eps)

* transpose()

* inverse()

* Determinant: det()

** Det. of upper 3x3: det3()

* Helper functions for matrix interpolation and the like

** Esp.: sqrt(), log(), exp()

* Decompose matrix into translation, rotation, scale, and scale orientation, depending upon optional choice of center point: 

getTransform(trans, rot, scale, scaleOrient, center)

 

…while there should be discussed if operations like transformations should be implemented by producing new matrices or should be applicable on existing matrices:

 

var result = new matrix();

var trans = new matrix.transformation(x,y,z);

result.mult(trans);

 

<< temp matrix + full matrix multiplication

 

vs.

 

result = new matrix();

result.transform(x, y, z); 

 

<< no need of copy + reduction of multiplication

 

For rotation the operations should work only on quaternions and/or only on separated x/y/z functions. This is because the fact of gimbal lock and the ~12 possible orders of operations when using euler angles.

 

 

So far. Sincerely

Timm Drevensek

 

 

 

Resent-From:  <mailto:public-fx@w3.org> public-fx@w3.org

From: Dean Jackson < <mailto:dino@apple.com> dino@apple.com>

Subject: Matrix4x4 proposal

Date: 12 January 2012 01:51:07 CET

To:  <mailto:public-fx@w3.org> public-fx@w3.org

Cc:  <mailto:igor.oliveira@openbossa.org> igor.oliveira@openbossa.org

 

[Apologies if this mail comes out badly formatted - I'm using a crappy web mail app]

 

This is picking up from Igor's proposal [1] and completes my action (given at the W3C TP) to propose a more "native" matrix class.

 

Open questions:

 

- should include ortho() and perspective() functions? (suggestion: YES)

- should include a matrix decomposition method? (suggestion: YES)

- should include a lookAt() method? (suggestion: PROBABLY, requires vectors or multiple parameters)

- ok to remove skew? (suggestion: I HOPE SO)

 

 

// -----------------------------------------------------------------------

// CONSTRUCTORS

// -----------------------------------------------------------------------

 

[

    // Creates an identity matrix

    Constructor(),

 

    // Creates a new matrix from the value passed in (which is CSS transform string with

    // matrix() or matrix3d() - not other functions).

    Constructor(in DOMString string),

    

    // Creates a new matrix from the Float32Array value passed in (length of 6 for a 2d matrix, or 16 for a 4x4 matrix).

    Constructor(in Float32array 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<float> array)

]

 

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 itself by a otherMatrix, on the right (this = this * otherMatrix)

    void multiply(in Matrix4x4 otherMatrix);

 

    // Multiply this matrix by otherMatrix, on the right (result = this * otherMatrix)

    [Immutable] Matrix4x4 multipliedBy(in Matrix4x4 otherMatrix);

 

    // Multiply itself by a 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 rotX>)

    // 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 rotX>)

    // 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);

 

    // return a Float32Array (length 16) with the values [m11, m12, ...]

    Float32Array toFloat32Array();

 

    // Returns a string that is in the format of a CSS transform.

    // (e.g. "matrix3d(m11, m12, ...)")

    DOMString toString();

};

 

 

 

 

[1] http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0376.html

 

--
Dr. Johannes Behr

Abteilungsleiter Visual Computing System Technologies

Fraunhofer-Institut für Graphische Datenverarbeitung IGD
Fraunhoferstr. 5  |  64283 Darmstadt  |  Germany
Tel +49 6151 155-510  |  Fax +49 6151 155-196
 <mailto:vorname.nachname@igd.fraunhofer.de> johannes.behr@igd.fraunhofer.de  |   <http://www.igd.fraunhofer.de/> www.igd.fraunhofer.de

 

 

--
Dr. Johannes Behr

Abteilungsleiter Visual Computing System Technologies

Fraunhofer-Institut für Graphische Datenverarbeitung IGD
Fraunhoferstr. 5  |  64283 Darmstadt  |  Germany
Tel +49 6151 155-510  |  Fax +49 6151 155-196
 <mailto:vorname.nachname@igd.fraunhofer.de> johannes.behr@igd.fraunhofer.de  |   <http://www.igd.fraunhofer.de/> www.igd.fraunhofer.de

 
Received on Wednesday, 18 January 2012 11:20:48 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Wednesday, 18 January 2012 11:20:48 GMT