Hello. I'm deciphering the model structure for an old video game so I can see how my models look in the engine's hardware.
The structure uses 6 bytes for a single vertex. Each vertex has 2 bytes for each axis. The vertices are as follows: the first byte takes a value of 255 to make a whole number of the second unit, while the second unit represents the whole number unit. The good news is that the vertex positions start from the origin: 0x00 0x00. The downside is that the vertex points only move to the right on the X axis and down on the Z axis; the Y and Z axes are flipped for the game engine. So: 0x00 0xFF is basically the origin subtracting 1 whole unit. The weirdest part is that the whole number units wrap around. This means that once a whole number unit is at 0x80, it will wrap from the right or bottom edge to the left or top edge. The decimal unit (the first byte) doesn't wrap around since it is too small to reach the edges of the grid that the whole number unit (the second byte) can reach.
For example: instead of having a position of 2.385 (axis doesn't matter as all vertices work the same on each one), I would like that to be a value of: 0x82 0x02 for the two bytes. Notice that the 2 is the whole number unit, and the decimal (.385) is the 0x82. I hope all of this make sense.
I have searched on Google for floating and fixed point precision for 3ds Max with no luck. I'm hoping someone can help me get the position values properly converted to hex. Anything is helpful, as well as appreciated.
Replies
I have been using these, and they've been very helpful... However, I noticed that my values are much bigger than 0xFF - which is the full amount of a byte in a hex editor. Is there a way that I can lower the values instead of having them overshoot? Right now, the bytes are written in 8-bits: 0xAABBCCDD.
round( myNumber, 3)
to round something off to 3 decimal places. This way you can keep you float values from being tool large to fit in a byte
http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-Python-API-Documentation/index.html
- How do you know that the format is supposed to be what you think it is, is there any documentation? (It sounds like the half-float format)
- "Right now, the bytes are written in 8-bits: 0xAABBCCDD." <---- That's a 4-byte value, like a 32 bit integer or float. If your coordinates use two bytes of storage, then format is this: 0xAABB.
Each byte (AA, BB) is represented by 8 bits, but you don't usually think in bits when writing them. Something like the value 128, for example, you can write in the decimal ("128") or hexadecimal ("0x80") representations.
- Your "385" (from your "2.385") is bigger than 255 and impossible to represent with a single byte. So you cannot break "2.385" down into two bytes, one for "2" and the other for "385" or something like that. The half-float format uses a different way, with sign, exponent and significand bits (read more), if it is what that game uses.
I was unaware that I could use Python in Maxscript. But, I just realized that I have a function for rounding a number to a specific decimal point, so I will use that first. If it doesn't work, then I will look in to the Python documentation. Thanks again for your help.
1.) There is some documentation, but it's loosely based and partially reverse engineered by other people; I had to manually edit bytes on my own to see what exactly the data does. The extra work doesn't matter in my opinion because it's been a good learning experience. I will look at the "half-float format".
2.) Oops, I meant 32-bit. When I see 8 bytes next to each other I think of 8 bits; I know I shouldn't confuse my bytes with bits. Right, so the format is just two bytes of storage. I'm aware I can write the hexadecimal representations, but thanks for reminding me.
3.) I just noticed that I failed to add further information, and it lead to this assumption. I'm figuring out a way to convert my position into hex. I've decided that for the whole number byte is just the whole number of my vertex position, and the decimal number byte is just a normalized value between 0 and 1 (by taking the float portion of the vertex and subtracting it by the integer portion). I've been making calculations for the float portion and have found that I can use the number 0.00392156862 * 255 = 0.999999998 - which is an incredibly small number for getting a roughly "precise" number. With the number (0.00392...) I can use a for-loop and check the decimal number to see what that number lies between, and then set the hex number accordingly. I will also look into the sign, exponent, and significand material; I read a little bit about it already, and it's vert interesting.
Thank you for your help and suggestions; it means a lot to me.
You have 256 steps in that fractional byte, so each step could represent that 1.0 / 255 = 0.0039215... increment of the fractional part, like you mentioned.
In order to fit those two bytes into a two-byte int, you can use the bit shift operations (shift left, in your case). Something like:
(AA shl 2) or BB
(bitwise shift-left 0xAA for two digits, so it's 0xAA00, and then do a bitwise OR with 0xBB to get 0xAABB)
For my normals I'm using: "$.modifiers["Edit Normals"].getNormal i" to get them correctly. Unfortunately, the data still doesn't convert as it should. I know that like the vertices, it will be the exact same for the normals where I will use: "norm.x*10^2" to get the same bytes in memory.
So it's not really a normal, it's more like "the mesh vertex offset by its normal", and the game probably derives the actual vertex normals from the vector 'offsetVertex.xyz - meshVertex.xyz'.
In order to use your original mesh normals, try exporting this vertex normal data as 'meshVertex.xyz + meshNormal.xyz' (vertex position plus its normal vector, same as offseting it like a shell).
Yeah... That threw me off for awhile; gave me some good headaches. It really is strange, because I have come across no other models that use normals in this manner. Thank you for the extra idea about 'meshVertex.xys + meshNormal.xyz'. I appreciate the extra ideas that you have, and that you keep coming back to check-up.