Decent FF7 Model Viewer

  • Thread starter Thread starter Sephiroth2000
  • Start date Start date
Status
Not open for further replies.
Poor Mirex :)

Well I'm working on the PS1 version (using a debugger by Pixel at The Repository.  I've had to do a lot of tweaking though and since it's a debugger things are, entertaining to say the least with making a tool like Spiros.  I'm using XML for the basis to describe structures etc.  This has an additional advantage that isn't obvious at first. I can include prior discovered structures within new structures.  The hard part will be making the structure building interface.  Nothing is easy as they say.  Right now I have something that should work 'OK' for viewing templates in parallel with the data.

Cyb
 
I am not sure what you mean by adding priorly discovered structures into new ones.

If my understanding of that is correct, it’s the same as what mine does.
Adding a template inside of a template is the same as adding a structure to a structure.

At least that is my take on your objective.
I could be way misunderstanding, but if that IS what you mean, don’t worry about it.  MemHack.exe allows as many templates added to other templates as is possible (given your hardware, RAM, etc.).  They can be as recursively deep as you need.

One thing that has yet to be added is the ability to import structures from .h files, or any text files that have valid structures.
It will help a lot when you can convert your existing written-out structures automatically with a click of a button.


Also (this has been intended for a long time) I will eventually add a macro editor, so you can assign macros to data items.  It will show the macro, or combination of macros, instead of the number, so it will be easier to decypher values.


L. Spiro
 
I am not sure what you mean by adding priorly discovered structures into new ones.

If my understanding of that is correct, it’s the same as what mine does.
Adding a template inside of a template is the same as adding a structure to a structure.
That works :lol:
At least that is my take on your objective.
I could be way misunderstanding, but if that IS what you mean, don’t worry about it.  MemHack.exe allows as many templates added to other templates as is possible (given your hardware, RAM, etc.).  They can be as recursively deep as you need.
I think you are misunderstanding this is not a program for dealing with PC programs but playstation programs (IE ones runing on an emulator). I'm just adding a memory viewer is all.
One thing that has yet to be added is the ability to import structures from .h files, or any text files that have valid structures.
Ahh so you have a parser to read that information.
It will help a lot when you can convert your existing written-out structures automatically with a click of a button.

Also (this has been intended for a long time) I will eventually add a macro editor, so you can assign macros to data items.  It will show the macro, or combination of macros, instead of the number, so it will be easier to decypher values.

L. Spiro
Well the target is different, as this has nothing to do with viewing PC memory, put PS1 memory instead.  Same objective however.  I prefer XML for the base description because it's pretty common and interchangable (IE it can be easily used by other people).  The 'MACRO' idea is a bit interesting. Especially if you get into types like those on the playstation  (fixed point values come to mind).

Cyb
 
I am back...  :)

Three quarters after my hard drive crash I finally was motivated enough to rewrite my source code. The only task to do till it is at the same progress as then is to add the TIM converting rountine. This is easy (look at my IOTW at ZFX) but very time intensive due to the amount of code to write (palette handling, image size adjustment, FFVII specific swapping of 8-bit images and so on...).

For this reason I decided to look on animations first. But before I am going to reinvent the wheel, can you guys tell me whether you already figured something out about the PSone animation sequences?

Yes, I know that the first frame of the first animation sequence is the only uncompressed one but do you already find out the data structure of it? The posts on the last pages in this thread are confusing.

Here is a little goody for you: :wink:

cloud_weapons.jpg


From left to right: Buster Sword, Mythril Saber, Hardedge, Butterfly Edge, Enhance Sword, Organics, Crystal Sword, Force Stealer, Rune Blade, Murasame, Nail Bat, Yoshiyuki, Apocalypse, Heaven's Cloud, Ragnarok, Ultima Weapon.

edit: Added link.
edit 2: Added weapon names.
 
This is what I just figured out. I assume that this is nothing new to you.  :z

Animation sequences of CLOUD.LZS (24 bones incl. root bone) with a length of 16, 24, 32 and 36 bytes:

Code: [Select]
Code:
01 00 09 00 04 FE 4E FF   E7 FF 50 00 FE 41 00 0001 00 09 00 04 FF 41 FD   AE FE 84 00 C1 80 00 0002 00 13 00 04 FF CB FD   D8 FF D2 CE 63 91 FF DB   FF EC E0 21 5A 5E 1B 7E03 00 19 00 04 00 9B FE   6C FC 0C 15 B8 BE 71 FF   AF 40 43 F2 B5 DC 29 BB   D4 04 AF B9 D3 43 00 0003 00 1B 00 04 FE A9 FD   42 FB 79 07 1E 4A 80 6A   A5 40 12 6F 75 F9 10 14   58 05 C4 0A 13 BF 8F A803 00 19 00 04 00 AC FE   57 FA 95 0F 0B EF 14 FF   CF 40 71 B7 59 99 C0 69   F0 1E BD BE F6 B0 00 0003 00 19 00 04 00 C9 FE   4C FB DA 0F 0B F1 6B FF   B8 C0 41 F2 B2 70 C3 C1   E0 2C BD FE 46 D8 00 0005 00 1E 00 04 FF 82 FD   16 FC F7 E3 89 81 01 01   76 44 80 40 9D A2 0F CF   A2 92 A2 02 9A 60 15 56   71 EE E8 0003 00 1C 00 04 FE D7 FD   69 FC B7 FA 1F 35 80 64   86 7F E8 37 7D 56 FA 02   47 00 4F 80 F7 DF A7 EF   C1 00 00 00

Analyzing this data let me assume the following file structure:

ushort num
ushort length
byte unknown
byte[length + pad bytes] compressed data
Notice on pad bytes: Files in a LZS archive have to be 4 byte aligned.

num is a count of something. I see that you guess this is the frame count. Are you sure?

An empty animation sequence has a length of 4 bytes and consists of num (0x1A30) and length (0x0000) only.
 
Kislinskiy
Num I believe is the frame count, however 0x1A30 has bothered me for a while, WHAT is it? I've asked myself, on the empty animations.  My Guess is this is an impossibly long length.
The first frame also is NOT UNCOMPRESSED, just to let you know.  The whole sequence is compressed, this is why some of the characters won't look right when you use the first frame of the first animation sequence.  Section1 I am positive has something to do with the animation, I just haven't figured it out.

One of CID's animation sequences is only 11 bytes long this is not enough for a single uncompressed frame even (it is a one frame animation however).  It might be they use the first frame of the first animation sequence to start all of them, however the compression technique used will take a bit to figure out, I believe. If you display the first frame of REDXIII you'll find he's been playing twister.  This first frame is compressed in some way as I said.

It doesn't appear to be LZS I don't think they would use LZW because it has large memory requirements  huffman and shanno fano compression are complicated bitwise compression techniques and slow, unless they found a way to use the MDEC to decode the animations somehow on the playstation.  It might be the LZS compression bytes are somewhere else, but unlikely.  Delta sigma is possible but has a bit too much overhead. Then there is the 3 16bit offset values.

Cyb
 
What the-

The first frame is not compressed.

I posted this earlier.

That “u1” byte is a “compression code” for the first frame (and may also have meaning on all frames after).
It determines the number of bits in each rotation is 12, 10, or 8.

THAT is why Red XIII’s animation looks twisted.
“u1” can be either 0, 2, or 4, and the formula for the bitcount per rotation is (12 - u1), which means the bitcount for (u1 = 2) is 10.

Red XIII’s animations have only 10 bits per rotation (on his first few, and then some with only 8).
But regardless of the u1 value, the translations are always 2 bytes each, and for some reason they are in reversed byte order and they are also inverted (-466 is actually 466, and 264 is actually -262).


When translating Red XIII’s animations using 10 bits per rotation instead of 12 you get the following table (which I posted already).

Code: [Select]
Code:
Bits from 0x1B      * 360 / 1024 0000000000          0.0   RXOffset 0000000000          0.0   RYOffset 0000000000          0.0   RZOffset 0000001001          3.1640625 0000000000          0.0 0000000000          0.0 0000001001          3.1640625 0000000000          0.0 0000000000          0.0 0000000000          0.0 0000000000          0.0 0000000000          0.0 0001000101          24.2578125 1111111101          358.9453125 0000000000          0.0 1111100001          349.1015625 0000000011          1.0546875 0000000001          0.3515625 1101110101          311.1328125 1100011010          279.140625 0100000111          Etc.…1111111011          Etc.…1010110100          Etc.…1001001011          Etc.…1111101111          Etc.…0001001101          Etc.…1111010111          Etc.…0000111110          Etc.…1111110101          Etc.…0000000011          Etc.…1101110100          Etc.…0011101011          Etc.…1011111001          Etc.…0000000001          Etc.…0010001101          Etc.…01 Etc.…


The formula changes from (X * 360 / 4096) to (X * 360 / 1024) because the maximum number for 10 bits is 1024.


You can decode Red XIII’s entire first frame this way and it is not compressed.
It just has a different decoding key (u1).


L. Spiro
 
That sounds more logical. I can not imagine that animation data should be compressed with an algorithm again. The pad bytes in such a stream also indicate length variable values.
 
Here is an example. This is the 3rd file in CLOUD.LZS. The first animation file without that yet unknown header.

The rotation values with a resolution of 12 bits start at offset 0x5FAD.

The first rotation triple is (000; 0FE; 2E0).

Code: [Select]
Code:
Bone   0: Name: rtam, Parent:  -1, Children:   3, Rotations:   0.00000000   0.00000000   0.00000000  Translating:  -39.00000000Bone   1: Name: rtan, Parent:   0, Children:   1, Rotations: 270.00000000 333.10546875   0.00000000  Translating: -163.00000000...
Related to this post the first rotation value would start at offset 0x5FB3 [(000; 000; 000), (C00, ECE, 000), ...] and ignore the 1st 4 12-bit values. Why? - Could it be that those values are the position/translation of the root bone to handle model movement? PSone coordinates of the battle models are stored in 4 values too. Just a thought.


cloud2.gif
 
Kislinskiy, I redid the animation structure.
The header of each animation is only 5 bytes long after the block_len and looks like this:

Code: [Select]
Code:
struct s_FF7AAanimHdr {    unsigned long   rec_a;      //0    unsigned long   frames_1;      //4    unsigned long   block_len;      //8    unsigned short   frames_2;      //12    unsigned short   real_data_len;   //14    unsigned char   bit_count_key;      //16 } FF7AAanimHdr; //size = 17 bytes


For every animation file, the first animation DATA starts on 0x15.
The next 6 bytes are part of the first animation frame and they are reverse-ordered inverted unsigned shorts (3).
On Cloud it is:
00 00 = 0
FE 2E = 466
00 00 = 0

Then the rotations follow, with the first rotation being the root bone, and it is not counted as part of the total bones of the animation.

Those 6 bytes plus the root bone plus the model bones are all part of the first frame.
After that things are most likely stored in some form of relational offset of the first frame.

Cloud’s certainly seems that way but Barret’s definitely doesn’t.
So it is most likely another bit-length problem.


L. Spiro
 
Related to this post the first rotation value would start at offset 0x5FB3 [(000; 000; 000), (C00, ECE, 000), ...] and ignore the 1st 4 12-bit values. Why?
The next 6 bytes are part of the first animation frame and they are reverse-ordered inverted unsigned shorts (3).
On Cloud it is:
00 00 = 0
FE 2E = 466
00 00 = 0

Ah, ok. Do you already know what these three values do represent? Perhaps the position/translation of the model as I assumed in my last post?
 
They are a translation for each frame.

But they are stored in a strange and illogical way.

00 00 = 0
FE 2E = 466
00 00 = 0

Why?

Well, FE 2E actually equals 12030.
But 2E FE equals -466 (signed).

In order to get the final final result, this number must then be subtracted from 0.
-466 becomes 466.  That is the first translational Y offset of Cloud’s first frame of his first animation.

Also, subtracting the number from 0 only applies to the Y.
The others still need to be reversed (bytewise) but not subtracted from 0.


So, changing these values moves his whole body to whatever position.

The same applies for the first set of rotations (the root bone).
Changing the first rotation will rotate the entire model by the new amount.


L. Spiro
 
I have problems with the correct rotation. Can someone post an image of the first frame of the first animation of ENEMY012.LZS please?

How do you calculate the position of a bone's child? I store the bone length at an identity matrix's z-element (element 43 in DirectX) and multiply that matrix with a matrix containing the bone rotation. Now I store the x-, y- and z-element in a vector and add it to the bone's position. This new vector represents the position of the child.

Due to FFVII uses another coordinate system I have trouble creating the correct rotation matrix.
 
Here is what I got, Note joints are RED and Bones are blue.
Cyan Magenta and Yellow are the X Y Z axis.

ENEMY012_01.jpg


Cyb
 
I don’t have that file but when rotating you have to rotate in the exact order: -Y, X, -Z.

DirectX® matrices aren’t like OpenGL®’s and translating along the Z by the length of the bone does not work the same way.
In fact, rotating as I mentioned above won’t work in DirectX® either.

OpenGL® uses degrees while DirectX® uses radians for one.

But if you know the math to transform your matrices then I won’t post beyond that.


L. Spiro
 
Thanks to both of you.  :)

@L. Spiro
I totally forgot that DirectX uses radians.
wallbash.gif


@Cyberman
Can you post EMENY041 please? The last one, I promise.  :wink: I think it is more suitable to compare...

My models are twisted.

edit: After analyzing ENEMY165 and ENEMY166 I guess I am a victim of Gimbal Lock... I recode my rotations using quaternions now...  -_-

ENEMY041
ENEMY041.jpg
 
OK, now I use quaternions to prevent Gimbal Locks. But that obviously was not the problem. The problem seems to occur on joint->bone only. There is almost evertime a "90 degree fracture". In addition some model parts are swapped (right arm should actually be left arm etc.).

ENEMY166
ENEMY166.jpg


ENEMY320
ENEMY320.jpg
 
Concerning your reversed models issue, it isn’t just some models that are on the opposite sides of where they should be, it is ALL.
The only reason SOME of them DON’t appear to be on the wrong side is because they are symmetrical.

This isn’t a problem when loading the models in OpenGL® but in DirectX® you have to load the models with -Z and -Y vertices/normals.
By this, I mean ONLY the 3-D model files.  Not the bones, not anything else.

And be sure to remember to load the normals this way also (which of course does not apply to battle models).


The result of this is that the models will stay on the wrong side, but they will be reversed, so the wrong side becomes the correct side.
This means your models will be perfect mirrors of the originals.


L. Spiro
 
Why +X-Y-Z and not +X+Y-Z? The only difference between a left-handed and a right-handed coordinate system is the direction of the Z-axis. I confusingly get the correct result with +X-Y+Z. Probably only apparently due to wrong rotation. Do you have this "90 degree fractures" too? One more time please, YOU (using OpenGL) convert the rotation values XYZ to ___ and rotate in the order ___.

lab3fig5_1.jpg
 
Status
Not open for further replies.
Back
Top