away3d / away3d-core-fp11

Away3D engine for Flash Player 11
http://www.away3d.com
Other
640 stars 276 forks source link

AWD documentation does not match implementation. #607

Open ToxicBakery opened 11 years ago

ToxicBakery commented 11 years ago

I am writing a Java parser for AWD format and I found what seems like a dependency. Reading the AWD implementation documentation :

MxN matrix Matrices are encoded as a column-major (col0, col1, ... colN) serial list of 64-bit floating point numbers. For a matrix with N columns and M rows, the total size of resulting byte array is MxNxP bytes, where P is either 4 or 8 depending on the precision used.

It states 64bit then says the precision will be 4 or 8 suggesting it will actually be 32bit or 64bit. As I know documentation typically lags and is likely to have mistakes I referred to the source and now I am unsure of which is correct.

3x2 matrix VS 4x4 (4x3 read) Matrix

The 3x2 implementation uses readFloat(), ie always 32bit and the 4x4 uses readNumber() which permits variance based on the precision flag. Can anyone clarify if the current implementation is correct?

80prozent commented 11 years ago

Hi I am at work right now, so i only can give you a quick answer. I will look at this part of the documentation this evening. Its correct that the matrix 4x4 which is used to store the object-Transformation-matrix, is stored dependend on the storage precision defined in the file-header-bitflags. I think the 3x2 matrix is only stored to save uvanimation, and has not been updated to use the storage precision yet. I can give you more Information later. Maybe we can connect via skype for better communication. Cheers Robin

ToxicBakery commented 11 years ago

Thanks for looking into it, and no rush. I have several weeks worth of work left implementing all of the block parsers with our engine anyways so its not going anywhere anytime soon so to speak.

jwoolston commented 9 years ago

@80prozent I am continuing the work of @ToxicBakery on this and have encountered a related issue. Models loaded into our engine from AWD files do not have the correct transformation applied. As he points out, the documentation states that the matrix is stored in column major order. When reading the numbers out in this order, I come up with a transformation matrix which does not correlate with the OpenGL environment's column major storage when applying the X/Y/Z rotations shown in AwayBuilder. I have seen a few issues from the old Google Code site so I understand the last row is not included. I have also discovered that whether right or wrong, it appears that the forward direction in AwayBuilder is along the -Z axis rather than +Z. Could you please help clarify how the transform matrix is created because baring an arithmetic error, I can not find a combination of euler rotations which will produce what the file contains given the input to AwayBuilder.

Thanks.

jwoolston commented 9 years ago

Further inspection of the core code makes it clear that this is all handled by flash.geom.Matrix3D's recompose method. The adobe documentation of this method states:

The default orientation is eulerAngles, which defines the orientation with three separate angles of rotation for each axis. The rotations occur consecutively and do not change the axis of each other.

So perhaps our issue is that we are expecting a normal Euler rotation sequence where the axis directions change after each rotation? If I treat it such that the rotations are per each axis rather than the new axis, I get a rotation matrix I would expect, with one exception - it seems the file stores it in row major order rather than column major order, but only for the rotation part of the transform. It seems translation is still column major. Can you confirm this?

80prozent commented 9 years ago

Hi Jared,

Hm. not sure i can confirm this.

Have a look at the AWDparser for as3: https://github.com/away3d/away3d-core-fp11/blob/master/src/away3d/loaders/parsers/AWD2Parser.as#L2416-2455

The matrix is stored into the file, in the most efficient way for creating a flash.geom.Matrix3D. e.g. you can pass it directly to a Matrix3D() constructor, and it will be correct.

look at the docs for matrix3D http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix3D.html from the doc of the constructor:

Creates a Matrix3D object. Matrix3D objects can be initialized with a Vector of 16 Numbers, where every four elements is a column. Once the Matrix3D object is created, you can access its matrix elements with the rawData property.

Think this means the data is stored as coloum major for all matrix. its a 4x4 matrix, but the last row is not written. (e.g. 4x3)

However, it really all depents on the matrix of your enviroment. for example 3dsmax transform-matrix has not only different coordinate system (z-up), but also a different structure. http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/index.html?url=files/GUID-14497600-0839-4225-BA52-B571FCC8AEBF.htm,topicNumber=d30e24647 its a 4x4 matrix, where the last coloum is not written.

hence to get from 3dsmax to away3d, we need to write in row-order, but read in coloum order.

another example: c4d. https://developers.maxon.net/docs/Cinema4DPythonSDK/help/modules/c4d/Matrix/index.html#c4d.Matrix here we have coloum-order, but the unused row is the first row, not the last.

Not sure if this is of much help.

jwoolston commented 9 years ago

Thanks. I was able to resolve it but to be honest I am not sure I have an explanation. I am not sure what the coordinate system ActionScript uses is, but in our case we are storing in column major order with standard OpenGL coordinates (Right +X, Up +Y, Forward +Z). I noticed in particular that your coordinate system uses Forward defined as -Z based on the observed behavior. This makes the Away3D coordinate system left handed, compared to OpenGL's right handed.

As for the rotations, when a matrix in our environment is constructed by rotating along the world X/Y/Z axes for each angle rather than the modified axes like a traditional Euler rotation, I am able to generate a matching rotation - so now I know how the rotation is generated. I recognize that in this case, this is behavior of Matrix3D and not Away3D.

The only other remaining question is the order. It seems that only the 3x3 rotation portion of the matrix is different, and in particular it appears to be the transpose. My matrix math is a touch rusty but perhaps this is simply the product of the different handed coordinate system.

80prozent commented 9 years ago

hey again

yes. looks like you need to get from left handed to right handed system.

i am no big matrix expert myself, not sure i can help.

try this order:

in awd:

reordered:

[edit:]

no i think this wont work. i think this applies only if you would want to swap axis (like changing y with z)

think the order needs to be maintained, because we want to maintain order of axis.

all you should need is invert z-position. if the rotation is not correct, you should multiply the 3x3 part with a transform 3x3 matrix that makes it correct.

jwoolston commented 9 years ago

I have found a solution based on a forum post here related to converting between OpenGL and DirectX. Specifically, given a right handed coordinate system of:

| Rx | Ry | Rz | Px |
| Ux | Uy | Uz | Py |
| Lx | Ly | Lz | Pz |
|  0 |  0 |  0 |  1 |

The lefthanded representation is:

| Rx | Ry | Rz |  Px |
| Lx | Ly | Lz |  Py |
| Ux | Uy | Uz | -Pz |
|  0 |  0 |  0 |   1 |

Note the swap of look and up vectors in the rotation matrix and inversion of the Z translation.

80prozent commented 9 years ago

hey

weird

this is the solution i posted above, but than i came to the conclusion that it must be wrong.

only that in your example you show the matrix in row-major order (i think) [edit: oh. i see. its row-major for rotation, but coloum-major for transform)]

my thinking was like this:

left handed identity matrix:

|1|0|0|0| |0|1|0|0| |0|0|1|0| |0|0|0|1|

switched to right handed:

|1|0|0|0| |0|0|1|0| |0|1|0|0| |0|0|0|1|

just doesn't looks like a correct identity matrix to me anymore. (normally in matrices i worked with, for the identity matrix, the "1" values line up as diagonal line across the matrix ) therefore i edited my post to say that this wont work.

but if it works. even better :) congratulations!

jwoolston commented 9 years ago

You are correct, its not your typical identity matrix, but this is the byproduct of the transformation. After seeing the explanation from Unity which backs up the transformation and provides the actual linear algebra derivation, I do recognize it from back when I actually remembered this stuff. I had similar suspicions about the row vs. column major notation, and still do. The reasoning for using the the order I did comes from this site. I would be interested in your opinion because while this resolved our issue with loading a static model, it beyond destroyed handling of the skeleton animations so clearly I am suffering some sort of misunderstanding of the data.

80prozent commented 9 years ago

hm. about skeleton-data: i have not looked at those in a while (been very busy working on flash-pro exporter in last weeks / month).

so you are sure your static transform is working correctly ? tested with different rotation etc... than it should be possible to get the skeleton running as well.

I think this facts are true for skeleton and might help you figure it out:

maybe helps. not sure.

jwoolston commented 9 years ago

I am fairly certain the transform works. I tested with a handful of rotation combinations on the different axes but I will double check to be certain. I have not yet looked into the cause of the issue but I am sure the info you provided will help speed the process, thankyou.