READ THE RULES: Click here

Follow us on Facebook: https://www.facebook.com/xentax/ :)

Approaches of Parsing Bone Representations

Read or post any tutorial related to file format analysis for modding purposes.
jayn23
beginner
Posts: 29
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 12 times
Been thanked: 11 times

Re: Approaches of Parsing Bone Representations

Post by jayn23 » Sun Aug 18, 2019 9:25 pm

Thanks for all the great tips :)

i feel kind of stupid with this but i cant seem to get the correct numbers for world transformation, and was hoping you could look at the numbers and maybe tell me what i am doing wrong:
I have a picture of debug console of noesis where first line(bones1) is original 4x3 matrix while second line(bones2) in world transformation.
up until i = 2 i get the correct answer by multiplying bone * bone[i-1] etc..
from i =3 no matter what combination i do i dont get the same result.
what i am doing is Matrix[3]*matrix[2]*matrix[1]*matrix[0], i tried a few other combinations including matrix[3]*matrix[2]-world transformation but none give the same result as noesis.

i dont know how important it is to understand this if noesis does this , but it bugs the hell out of me that i cant figure it out :D
You do not have the required permissions to view the files attached to this post.

jayn23
beginner
Posts: 29
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 12 times
Been thanked: 11 times

Re: Approaches of Parsing Bone Representations

Post by jayn23 » Sun Aug 18, 2019 9:27 pm

couldn't add a second attachment before, here are my matrices:
if i understood correctly:

for i =3
Bones[3] * Bones[2] * Bones[1]* Bones[0] = answer
You do not have the required permissions to view the files attached to this post.

User avatar
Bigchillghost
ultra-veteran
ultra-veteran
Posts: 501
Joined: Tue Jul 05, 2016 9:37 am
Has thanked: 22 times
Been thanked: 425 times

Re: Approaches of Parsing Bone Representations

Post by Bigchillghost » Mon Aug 19, 2019 5:51 am

jayn23 wrote:
Sun Aug 18, 2019 9:25 pm
what i am doing is Matrix[3]*matrix[2]*matrix[1]*matrix[0]
It should be matrix[0]*matrix[1]*matrix[2]*matrix[3] since it's row-major matrix.
noe.png
jayn23 wrote:
Sun Aug 18, 2019 9:25 pm
i dont know how important it is to understand this if noesis does this , but it bugs the hell out of me that i cant figure it out :D
Theoretically to convert a parent space tree to world space, you need to premultiply each node in a level with its parent recurrently from the root level down to the last level, or use other methods that have the same effect. So it doesn't matter how Noesis does it, so long as it works as expected. But you should know at least one way to convert it yourself.
You do not have the required permissions to view the files attached to this post.
May you find peace in this puzzle-solving game. Say it with action: click the Image when you get helped.:)

jayn23
beginner
Posts: 29
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 12 times
Been thanked: 11 times

Re: Approaches of Parsing Bone Representations

Post by jayn23 » Mon Aug 19, 2019 9:11 am

Ill take a look at the numbers when i get home, but i am sure ill get it to work now.

Thanks a lot for all your help and fast reply's i really appreciate it.

723119159
advanced
Posts: 43
Joined: Sun Dec 02, 2018 4:27 pm
Has thanked: 1 time

Re: Approaches of Parsing Bone Representations

Post by 723119159 » Fri Aug 23, 2019 7:17 am

Hello,and sorry to disturb you.
Could you analysis the bigworld engine model?I can't find any ather idears.
http://www.mediafire.com/file/g432vuf89 ... 05408/file
this is a sample. bone file is .visual
Thanks

User avatar
Bigchillghost
ultra-veteran
ultra-veteran
Posts: 501
Joined: Tue Jul 05, 2016 9:37 am
Has thanked: 22 times
Been thanked: 425 times

Re: Approaches of Parsing Bone Representations

Post by Bigchillghost » Wed Oct 09, 2019 9:12 am

chr_body_rank_104_a_slender.zip

Code: Select all

# Dump Name: chr_body_rank_104_a_slender.o4a
# From Game: IDOLM@STER One For All
# Platform: PS3
# Bone Format: 4x4 Matrices (inversed)
# Coordinate System: Left-Hand
# Endian: Big
Bone data structure:

Code: Select all

long	boneCount
for i = 0 < boneCount
	long	boneID
	long	structSize
	long	unknown
	char	boneName[0x20]
	long	parentID
	byte	skip[0x9C]
	float	boneMat[4][4] // Column-major
	byte	skip2[0xC]
Same procedure as for Iron Man 2. Probably some kind of "feature" of PS3 games?

Noesis code(lack convertion to right-handed):

Code: Select all

#load the model
def noepyLoadModel(data, mdlList):
	bs = NoeBitStream(data, NOE_BIGENDIAN)
	boneCount = bs.readInt()
	bones = []
	for i in range(0, boneCount):
		boneID = bs.readInt()
		bs.seek(8, NOESEEK_REL)
		boneName = noeStrFromBytes(bs.readBytes(0x20), "UTF8")
		if boneName == "":
			boneName = "Scene Root"
		parentID = bs.readInt()
		bs.seek(0x9C, NOESEEK_REL)
		Mat44 = NoeMat44.fromBytes( bs.readBytes(0x40), NOE_BIGENDIAN )
		boneMat = Mat44.toMat43().inverse()
		bs.seek(0x10, NOESEEK_REL)
		bones.append( NoeBone(boneID, boneName, boneMat, None, parentID) )
	
	mdl = NoeModel()
	mdl.setBones(bones)
	mdlList.append(mdl)
	return 1
Image
You do not have the required permissions to view the files attached to this post.
May you find peace in this puzzle-solving game. Say it with action: click the Image when you get helped.:)

User avatar
Bigchillghost
ultra-veteran
ultra-veteran
Posts: 501
Joined: Tue Jul 05, 2016 9:37 am
Has thanked: 22 times
Been thanked: 425 times

Re: Approaches of Parsing Bone Representations

Post by Bigchillghost » Fri Oct 11, 2019 11:53 am

g_uec.zip

Code: Select all

# Dump Name: g_uec.ve1
# From Game: Ben 10 Ultimate Alien: Cosmic Destruction
# Platform: XBOX 360
# Bone Format: Quaternion Rotation, Translation
# Coordinate System: Right-Hand
# Engine: Vicious Engine
# Endian: Big
Bone data structure:

Code: Select all

word	boneCount
word	boneCount
byte	itemBoneCount
byte	itemBoneCount
word	skip
for i = 0 < boneCount
	float	Rotation[4] // Quaternion Rotation
	float	Translation[3]
	float	Scaling[3]
	char	parentID
	byte	skip[3]
for i = 0 < itemBoneCount
	float	Rotation[4] // Quaternion Rotation
	float	Translation[3]
	char	parentID
	byte	skip[3]
Similar procedures as previous examples. Just with an extra bone list.

Noesis code:

Code: Select all

#load the model
def noepyLoadModel(data, mdlList):
	bs = NoeBitStream(data, NOE_BIGENDIAN)
	boneCount = bs.readUShort()
	bs.seek(2, NOESEEK_REL)
	itemBoneCount = bs.readUByte()
	bs.seek(7, NOESEEK_REL)
	bones = []
	for i in range(0, boneCount):
		Rot = NoeQuat.fromBytes(bs.readBytes(16), NOE_BIGENDIAN)
		Tran = NoeVec3.fromBytes(bs.readBytes(12), NOE_BIGENDIAN)
		Scal = NoeVec3.fromBytes(bs.readBytes(12), NOE_BIGENDIAN)
		bonePIndex = bs.readByte()
		bs.seek(3, NOESEEK_REL)
		boneMat = Rot.toMat43(transposed = 0)
		boneMat[3] = Tran
		bones.append( NoeBone(i, "bone%03d"%i, boneMat, None, bonePIndex) )
	for i in range(0, itemBoneCount):
		Rot = NoeQuat.fromBytes(bs.readBytes(16), NOE_BIGENDIAN)
		Tran = NoeVec3.fromBytes(bs.readBytes(12), NOE_BIGENDIAN)
		bonePIndex = bs.readByte()
		bs.seek(3, NOESEEK_REL)
		boneMat = Rot.toMat43(transposed = 0)
		boneMat[3] = Tran
		idx = boneCount + i
		bones.append( NoeBone(idx, "bone%03d"%idx, boneMat, None, bonePIndex) )
	totalBoneCount = boneCount + itemBoneCount
	# Converting local matrix to world space
	for i in range(0, totalBoneCount):
		j = bones[i].parentIndex
		if j != -1:
			bones[i].setMatrix( bones[i].getMatrix() * bones[j].getMatrix() )
			
	mdl = NoeModel()
	mdl.setBones(bones)
	mdlList.append(mdl)
	return 1
Image
You do not have the required permissions to view the files attached to this post.
May you find peace in this puzzle-solving game. Say it with action: click the Image when you get helped.:)

User avatar
Bigchillghost
ultra-veteran
ultra-veteran
Posts: 501
Joined: Tue Jul 05, 2016 9:37 am
Has thanked: 22 times
Been thanked: 425 times

Re: Approaches of Parsing Bone Representations

Post by Bigchillghost » Fri Oct 11, 2019 12:08 pm

Time for some clarification.

Why would the following method of converting a parent-space bone tree to world space work within Noesis?

Code: Select all

for i in range(0, boneCount):
	j = bones[i].parentIndex
	if j != -1:
		bones[i].setMatrix( bones[i].getMatrix() * bones[j].getMatrix() )
It has nothing to do with Noesis' feature but simply because it's logically correct for any organized bone list.

Let's see how the bone nodes are usually stored.

(bone tree of g_uec.ve1 from Ben 10 Ultimate Alien: Cosmic Destruction)
Image

The number of each node equals to its index in the node list, the same below.

And this diagram shows how the nodes are traversed.

Image

As you can see, the traversal order of the nodes is exactly aligned to how they're stored in the bone list.

Bones stored as above are in the so-called depth-first traversal order. However it can also apply to bone list in breadth-first storage.

(bone tree of mermaid_normal.model from GuJian3)
Image

The traversal order of the list:

Image

So long as the bone nodes in the list are organized in a way where any node is stored after its parent node, this method will work correctly.
May you find peace in this puzzle-solving game. Say it with action: click the Image when you get helped.:)

Post Reply