Jump to content

Silent Hill 4 Xbox animations


Recommended Posts

  • Engineer

Hi, we already have a Noesis plugin for SH4 Xbox characters(meshes and skeleton), thanks to Durik256 and alanm1: SH4 Xbox characters & skeleton

So now I want to know if it is possible to extract animations too. I analyzed animations format and this is my research:

Ok, first a reminder, .bin files have a main header. First 4 bytes of this header tells you the number files or parts and then pointers to each part, I am using henry01.bin, most of all pointers go to animations, just last 3 pointers go to mesh, textures and shadow. I cut the 1st animation to analyze it better:

 

sh4 animations.PNG

sh4 animations2.PNG

Edited by roocker666
  • Like 1
Link to comment
Share on other sites

  • Engineer

In some animations Table2(T2) are Floats, looks like 3 Floats of data and 1 Float padding. You can see this in animation number 2. Here is henry01.bin and the two first animations(I cut those from henry01.bin):
henry01

I have zero  knowledge about animation formats, lol. I just tried to understand the different blocks of SH4 animations. Thanks! 

Link to comment
Share on other sites

  • Engineer

Well, looks to me like an unusual proceeding.  Wouldn't you go for the bone count first, then check a simple animation for its frames per bone?

edit: I see you found 29 pointers. Surprise... (== bone count)

In the smd file created from Henry.bin using Durik256/alanm1's py script the rotations are all zero. No idea whether it's a SH4 feature or whether they need to be found.

(Also it would be nice to have the real bone names instead of placeholders bone_[number].)

bone_0 is 'root', the two "chains" starting at 12 and 17 are not fingers, seems, because there's left hand/right hand bones only?

version 1
nodes
  0 "bone_0"  -1
  1 "bone_1"  0
  2 "bone_2"  1
  3 "bone_3"  2
  4 "bone_4"  3
  5 "bone_5"  1
  6 "bone_6"  5
  7 "bone_7"  6
  8 "bone_8"  0
  9 "bone_9"  8
  10 "bone_10"  9
  11 "bone_11"  10
  12 "bone_12"  9
  13 "bone_13"  12
  14 "bone_14"  13
  15 "bone_15"  14
  16 "bone_16"  15
  17 "bone_17"  9
  18 "bone_18"  17
  19 "bone_19"  18
  20 "bone_20"  19
  21 "bone_21"  20
  22 "bone_22"  4
  23 "bone_23"  11
  24 "bone_24"  7
  25 "bone_25"  16
  26 "bone_26"  -1
  27 "bone_27"  -1
  28 "bone_28"  -1
  29 "bone_29"  -1
end
skeleton
time 0
  0 0.000000 -219.022919 -2.569616 0.000000 -0.000000 0.000000
  1 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000
  2 18.000000 33.022919 -7.430384 0.000000 -0.000000 0.000000
  3 0.000000 78.000000 -2.000000 0.000000 -0.000000 0.000000
  4 0.000000 84.000000 -6.000000 0.000000 -0.000000 0.000000
  5 -18.000000 33.022919 -7.430384 0.000000 -0.000000 0.000000
  6 0.000000 78.000000 -2.000000 0.000000 -0.000000 0.000000
  7 0.000000 84.000000 -6.000000 0.000000 -0.000000 0.000000
  8 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000
  9 0.000000 -40.977081 -5.430384 0.000000 -0.000000 0.000000
  10 0.000000 -43.284210 -2.452426 0.000000 -0.000000 0.000000
  11 0.000000 -13.832092 3.474270 0.000000 -0.000000 0.000000
  12 10.000000 -30.000000 -4.000000 0.000000 -0.000000 0.000000
  13 24.000000 6.000000 -4.000000 0.000000 -0.000000 0.000000
  14 56.000000 0.000000 -2.000000 0.000000 -0.000000 0.000000
  15 54.000000 0.000000 2.000000 0.000000 -0.000000 0.000000
  16 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000
  17 -10.000000 -30.000000 -4.000000 0.000000 -0.000000 0.000000
  18 -24.000000 6.000000 -4.000000 0.000000 -0.000000 0.000000
  19 -56.000000 0.000000 -2.000000 0.000000 -0.000000 0.000000
  20 -54.000000 0.000000 2.000000 0.000000 -0.000000 0.000000
  21 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000
  22 1.000000 18.000000 22.000000 0.000000 -0.000000 0.000000
  23 0.000000 -3.830841 -0.022519 0.000000 -0.000000 0.000000
  24 -1.000000 18.000000 22.000000 0.000000 -0.000000 0.000000
  25 17.274750 6.581696 1.481747 0.000000 -0.000000 0.000000
  26 -18.000000 -24.000000 -18.000000 0.000000 -0.000000 0.000000
  27 18.000000 -24.000000 -18.000000 0.000000 -0.000000 0.000000
  28 -144.000000 -284.000000 -16.000000 0.000000 -0.000000 0.000000
  29 144.000000 -284.000000 -16.000000 0.000000 -0.000000 0.000000
end

Couldn't make sense of the pointers (to frame blocks?) Tried an offset (0x80) at no avail.

Search for signature 010001FF gave 170 results and might help structuring the bin.

(ok, you used it already - "animation ID")

Edited by shak-otay
  • Like 1
Link to comment
Share on other sites

  • Engineer

Sadly there are no bone names. Henry's skeleton has no bones in fingers because it is a playable character but it has an extra bone in one hand(for weapons maybe. Check this screenshot).  Yes, signature "010001FF" is the ID for animations so henry's file has 170 animations. Then each animation has two more signatures "030001FF"(don't know what this means, it has more bytes after this) and "020001FF"(pointers to frames?). We can search in SH4 E3 debug symbols, some .c files have structs about animations. For example this .c file:
SH4 E3 sg_anime.c this has some structs, maybe for those signatures. In line 236 that struct matches with "frame header", I don't know about Table1(T1) but Table2(T2) looks like key frames(?) 

Those .c files are for PS2 but Xbox and PC have the same animation format.

That animation folder has more .c files about animations, so maybe we can find some answers in those .c files.

henry_skeleton.PNG

Link to comment
Share on other sites

  • Engineer

Well, that c code is an information overkill for me. I'd start it simpler, here's an assumed animation curve of a bone:

(integer list at 0x5AA0 with 27 values should be the time line, 4 values skipped, 4, 0C etc )

The 27 points at 0x5AE0 are floats.

Henry_anim_curve.png

At 0xCAB0 a frame with 42 integer points (shorts):

Henry_anim_frame_int.png

Still we don't know which frame blocks belong to which bones.

I did a signature check (2 DWords):

   1C 3C    58x
   1C 4C    20x
   1C 5C    13x
   1C 6C     9x
   1C 7C     3x
   1C 8C     6x
   1C 9C     2x
   1C AC     2x
   1C BC     5x
   1C CC     2x

------------

   10 80    76x
   10 90    61x
------------------

  14 44    9x
  14 54    4x

  14 74    7x
  14 84    3x

  14 A4    3x
  14 B4    1x

  14 D4    1x

Sadly the sum of highest counts (58, 76, 61) exceeds 170, so I'm wrong here?

(The DWord before those 2 DWs (1C000000 8C000000 for example) is the count of frame lines in the specific frame block.

0x35 = 53 decimal at 0x407B8.)

edit: the high counts seem to be wrong because of uncomplete signature search:

for 0000 10000000 80000000 there's 3 findings only.

For 0000 1C000000 3C000000 still 58 results but 44 to be subtracted (DWord being 0)

so 14 findings remain. Good. But not checked now...

Edited by shak-otay
  • Like 1
Link to comment
Share on other sites

  • Engineer

According with this struct(which I think is "frame header"):

struct _anon4
{
	short key_type;
	short reserved;
	short nb_keys;
	char skeleton_no;
	unsigned char relative;
	unsigned int time_table_offset;
	unsigned int keys_offset;
};

first short "key_type"(unknow), 2nd short "reserved"(unknow2), 3rd short "nb_keys"(number of keys or count?), char "skeleton_no"(maybe bone number? ), char "relative"(unknow3), unsignet int "time_table_offset"(pointer to Table1), unsigned int "keys_offset"(pointer to Table2).

So yes, maybe Table1 is time line(0x5AA0) and Table2 is key frames(0x5AE0 and 0xCAB0, these could be short or Float). I still don't know what are those bytes after 03 00 01 FF signature..

  • Like 1
Link to comment
Share on other sites

4 hours ago, Bigchillghost said:

Just using simple check for tran/rot with the type flag (ignoring scenarios of different data types):

(skel)

ashPrams.thumb.png.93362e7e2fc71e46d6e666f993924534.png

(anim)

arcPrams.thumb.png.66a964c0348a07e0bd81f3ba96a97f74.png

anim.gif.61d6e5b51e590deb69c5f6fb6c50d6ca.gif

Can you make a light tutorial on how you did it, or at least the full animation layout code?

Link to comment
Share on other sites

17 hours ago, Sparagas said:

Can you make a light tutorial on how you did it, or at least the full animation layout code?

For short, extract the skeleton with ASH, export it as *.end, then open the anim in ARC and import the *.end skeleton. Code the layout, hit the Compile button to check for any grammar mistakes; press the Execute button to execute the layout context. Pick the correct GUI options and press Convert to convert the read animation data. Then you're free to check the result with the Preview button.

Layout for "henry01_1st_animation" (the original animated bone count is 1-off so there's a fix on it):

seek	address[0x10]
long	boneCnt
calc	boneCnt[+][1]
seek	address[0x48]
begin	loop[boneCnt]
	long	offset
	calc	offset[+][0x40]
	push	offsetList[offset]
end	loop[boneCnt]
begin	loop[boneCnt]
	value	offset[offsetList][boneIdx]
	seek	address[offset]
	word	type
	word	skip
	word	keyCnt
	word	boneIndex
	long	timeOffset
	long	keyOffset
	calc	timeOffset[+][offset]
	calc	keyOffset[+][offset]
	test	type[==][0x10]
	begin	scope
		seek	address[timeOffset]
		word	tKeyIndex[keyCnt]
		seek	address[keyOffset]
		begin	loop[keyCnt]
			short	Translation[4]
		end	loop[keyCnt]
	end		scope
	test	type[==][0xD]
	begin	scope
		seek	address[timeOffset]
		word	rKeyIndex[keyCnt]
		seek	address[keyOffset]
		begin	loop[keyCnt]
			short	Rotation[4]
		end	loop[keyCnt]
	end		scope
end	loop[boneCnt]

Have fun!

  • Like 2
Link to comment
Share on other sites

  • Engineer
On 12/3/2024 at 9:53 AM, Bigchillghost said:

Just using simple check for tran/rot with the type flag (ignoring scenarios of different data types):

OK, you used just two data types for tra/ro(x10, xD), analyzing more henry animations(and other characters) I found more: x1, x2, x4, x7. So why are different data types?

Edited by roocker666
Link to comment
Share on other sites

6 hours ago, roocker666 said:

I found more: x1, x2, x4, x7. So why are different data types?

My guess, some of the bits indicate whether it's tran, rot or scal, the other bits stands for the actual data types and component count. You'll have to compare with different cases to find the rules. Or perhaps check the C code for any suspicious enum types.

  • Like 1
Link to comment
Share on other sites

  • Engineer
19 hours ago, Bigchillghost said:

My guess, some of the bits indicate whether it's tran, rot or scal, the other bits stands for the actual data types and component count. You'll have to compare with different cases to find the rules. Or perhaps check the C code for any suspicious enum types.

I was checking in different C files but I did not found data types 😞 BUT on "Sparagas" Github there is a script for 010 made by "Hunter Stanton" this reads the whole animation code. Well, no all. ID "02 00 FF FF" has pointers to frames but for some reason there is no count for those pointers in animations, weird.. He also found data types but I am not sure if are correct. Here is if you want to take a look: sh4_pc_animation.bt

Use this bt script on individual animations like "henry01_1st_animation"
Oh, one more thing: You used 0x10 as bone count but I think that is incorrect, that is a pointer to ID "03 00 FF FF" Bone count only appears in mesh header not in animations. Henry bone count is "1E"(or 30 Dec), I analyzed more characters and in all animations 0x10 is always 1C so yes, it is a pointer to ID "03 00 FF FF"

Edited by roocker666
Link to comment
Share on other sites

On 12/6/2024 at 4:52 AM, roocker666 said:

Oh, one more thing: You used 0x10 as bone count but I think that is incorrect, that is a pointer to ID "03 00 FF FF" Bone count only appears in mesh header not in animations.

I see. Will have to calculate the count manually in this case.

 

On 12/5/2024 at 3:10 AM, roocker666 said:

I found more: x1, x2, x4, x7. So why are different data types?

What I can tell with some examinations:

1     float quat[4];
2     float quat[4]; float quat2[4];
4     float tran[4];
7     float tran[4]; float tran2[4];
0xD   short quat[4];
0x10  short tran[4];

For type 2 & 7 using the first key component the anim appeared to be shifted to a different origin, but the two anims seem identical:

key1.gif.5b0c14a07610237c7d200d7b0a30a95d.gif

key2.gif.e3ddc895a7b72e47f9bb29ad6deb3855.gif

 

Code for anim 46 in henry01.bin (same GUI options):

calc	animBase[=][0x5EE80]
seek	address[animBase]
byte	skip[0x14]
long	hdrOffset
calc	hdrOffset[+][animBase]
seek	address[hdrOffset]
long	skip[2]
calc	curPos[=][0]
tell	address[curPos]
long	boneCnt
calc	boneCnt[-][0xC]
calc	boneCnt[/][4]
seek	address[curPos]
begin	loop[boneCnt]
	long	offset
	assert	offset[>][0]
	calc	offset[+][hdrOffset]
	push	offsetList[offset]
end	loop[boneCnt]
begin	loop[boneCnt]
	value	offset[offsetList][boneIdx]
	seek	address[offset]
	word	type
	word	skip
	word	keyCnt
	word	boneIndex
	long	timeOffset
	long	keyOffset
	calc	timeOffset[+][offset]
	calc	keyOffset[+][offset]

	typedef	dataType[short]
	calc	eleType[=][-1] // 0 = T, 1 = R
	calc	skipSize[=][0]

	test	type[==][1]
	begin	scope
		typedef	dataType[float]
		calc	eleType[=][1]
	end		scope

	test	type[==][2]
	begin	scope
		typedef	dataType[float]
		calc	eleType[=][1]
		calc	skipSize[=][16]
	end		scope

	test	type[==][4]
	begin	scope
		typedef	dataType[float]
		calc	eleType[=][0]
	end		scope

	test	type[==][7]
	begin	scope
		typedef	dataType[float]
		calc	eleType[=][0]
		calc	skipSize[=][16]
	end		scope

	test	type[==][0xD]
	calc	eleType[=][1]

	test	type[==][0x10]
	calc	eleType[=][0]

	assert	eleType[>=][0] // check for unmatched scenarios

	test	eleType[==][0]
	begin	scope
		seek	address[timeOffset]
		word	tKeyIndex[keyCnt]
		seek	address[keyOffset]
		begin	loop[keyCnt]
			byte	skip[skipSize]
			dataType	Translation[4]
		end	loop[keyCnt]
	end		scope

	test	eleType[==][1]
	begin	scope
		seek	address[timeOffset]
		word	rKeyIndex[keyCnt]
		seek	address[keyOffset]
		begin	loop[keyCnt]
			byte	skip[skipSize]
			dataType	Rotation[4]
		end	loop[keyCnt]
	end		scope
end	loop[boneCnt]

 

  • Thanks 2
Link to comment
Share on other sites

  • Engineer
19 hours ago, Bigchillghost said:

Code for anim 46 in henry01.bin (same GUI options):

Thanks man, I was testing more animation offsets and it seems to work! Just a little detail, last animation(at 0x139280 in henry01.bin) is when Henry dies but it looks different.. In the game he falls on his knees and dies but in ARC tool, the skeleton does not fall on its knees. Maybe this little glitch is present in more animations but it is hard to tell because we need to check every animation and there are A LOT, lol. Here is the comparison:
 

henry_dies_ingame.gif

henry_dies_skeleton.gif

  • Like 1
Link to comment
Share on other sites

  • Engineer

By the way, here is other model "anmix_test.bin". It seems like it is a test model so it has only 2 animations. Main file header has 4 Pointesr: 0x80 mesh, 0x6DB00 textures, 0xB4E80 anim1, 0xBF200 anim2, Maybe it will be more easy, anim1 seems to look fine I guess but anim2 looks weird.. And I noticed that after ID "02 00 01 FF"(in animations) are 4 bytes 00 00 01 00, in Henry those 4 bytes are always 00 00 00 00. Probably it does not matter because you skip those.
 

anmmix_test.rar

Edited by roocker666
Link to comment
Share on other sites

15 hours ago, roocker666 said:

Just a little detail, last animation(at 0x139280 in henry01.bin) is when Henry dies but it looks different.. In the game he falls on his knees and dies but in ARC tool, the skeleton does not fall on its knees. 

There's no new type flags in this anim and the data seem to be converted correctly. From what I've checked, the knee bones are bone 3 and bone 6 and they both have 1 initial rotation key only. But bone 26 to 29 have more keys while they're all connected to the root bone. Either these bones somehow control other bones or there might be something related to inverse kinematics? Just wild guesses. By the way, the structure of the 03 00 01 FF chunk appears to be:

long	sig // 03 00 01 FF
word	parentLinkCnt
word	unkLinkCnt
long	linkOffset
long	linkSize
for i = 0 < parentLinkCnt
	char	boneId
	char	parentId
for i = 0 < unkLinkCnt
	char	boneId // bone 26 to 29
	char	unkBoneId[3]

I'd recommend to check the game logics with a decompiler for further process.

Edited by Bigchillghost
  • Like 1
Link to comment
Share on other sites

  • Engineer
3 hours ago, Bigchillghost said:

There's no new type flags in this anim..

I see, I think I found other different data type in one of the models but I can't remember which one, lol. I will try to find it..
Oh, I forgot. I found 03 00 01 FF structs in C files! So your structure is correct 🙂 just some little differences:
 

struct _anon1// 03 00 01 FF header
{
	unsigned int type_id;
	short n_connects;
	short n_ik_chains;
	int connects_offset;
	int ik_chains_offset;
	
};

struct _anon5// connects
{
	unsigned char bone_no;
	char parent_no;
};

struct _anon6//ik_chains
{
	unsigned char handle_no;
	char ikhandle_type;
	char start_no;
	char effector_no;
};

 

Link to comment
Share on other sites

Well, that make sense. There're 4 IK chains including two arms and two legs. But IK is a field that's a little bit advanced to me. And there doesn't seem to be any simple solution with FBX for such features. And the main purpose for ARC is to focus on simple key-frame animations. So you might have to ignore those glitchy anims for now.

Link to comment
Share on other sites

  • Engineer
5 hours ago, Bigchillghost said:

But IK is a field that's a little bit advanced to me. And there doesn't seem to be any simple solution with FBX for such features.

I understand, We can use those glitchy animations like that, don't worry. Thank you for your time and all the help man!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...