Page 2 of 2
Re: Approaches of Parsing Bone Representations
Posted: Sun Aug 18, 2019 9:25 pm
by jayn23
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 
Re: Approaches of Parsing Bone Representations
Posted: Sun Aug 18, 2019 9:27 pm
by jayn23
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
Re: Approaches of Parsing Bone Representations
Posted: Mon Aug 19, 2019 5:51 am
by Bigchillghost
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
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.
Re: Approaches of Parsing Bone Representations
Posted: Mon Aug 19, 2019 9:11 am
by jayn23
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.
Re: Approaches of Parsing Bone Representations
Posted: Fri Aug 23, 2019 7:17 am
by 723119159
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
Re: Approaches of Parsing Bone Representations
Posted: Wed Oct 09, 2019 9:12 am
by Bigchillghost
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

Re: Approaches of Parsing Bone Representations
Posted: Fri Oct 11, 2019 11:53 am
by Bigchillghost
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

Re: Approaches of Parsing Bone Representations
Posted: Fri Oct 11, 2019 12:08 pm
by Bigchillghost
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)
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.
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)
The traversal order of the list:
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.
Re: Approaches of Parsing Bone Representations
Posted: Wed Apr 01, 2020 3:18 pm
by EPYCSPYDER
Can you read the bones from forza 4 car? It has 75 bones
Re: Approaches of Parsing Bone Representations
Posted: Tue May 26, 2020 3:17 pm
by Bigchillghost
anakinhooddown.zip
Code: Select all
# Dump Name: anakinhooddown.sw3
# From Game: Star Wars: Episode III – Revenge of the Sith
# Platform: Xbox
# Bone Format: 4x3 Matrices
# Coordinate System: Left-Hand
# Endian: Little
Bone data structure:
Code: Select all
long boneCount
for i = 0 < boneCount
char boneName[0x20]
float boneMat[4][3] // Rotation[3][3](column-major), Translation[3]
short parentID
The rotation matrices are in column-major so transposes are required.
Also similar to
Iron Man 2 and
IDOLM@STER One For All, they need to be inversed.
Noesis code (lack convertion to right-handed):
Code: Select all
#load the model
def noepyLoadModel(data, mdlList):
bs = NoeBitStream(data)
boneCount = bs.readUInt()
bones = []
for i in range(0, boneCount):
pos = bs.tell() + 0x20
boneName = bs.readString()
bs.seek(pos, NOESEEK_ABS)
boneMat = NoeMat43.fromBytes(bs.readBytes(48)).transpose().inverse()
bonePIndex = bs.readShort()
bones.append(NoeBone(i, boneName, boneMat, None, bonePIndex))
mdl = NoeModel()
mdl.setBones(bones)
mdlList.append(mdl)
return 1

Re: Approaches of Parsing Bone Representations
Posted: Tue May 26, 2020 8:01 pm
by jayn23
Hi Bigchillghost,
Thanks for updating this thread all the time, i still find my self checking it out every now and then to give me ideas how to do things its very useful
Noesis code (lack convertion to right-handed):
apparently rich thought about this to, yesterday i found a built in function for swapping from left to right hand and thought you might be interested.
Code: Select all
boneMat = NoeMat43.fromBytes(bs.readBytes(48)).transpose().inverse().swapHandedness(0)
swapHandedness (axis) while axis can be 0,1,2
for anakin it worked with 0
Re: Approaches of Parsing Bone Representations
Posted: Wed May 27, 2020 4:15 am
by Bigchillghost
jayn23 wrote: ↑Tue May 26, 2020 8:01 pm
i still find my self checking it out every now and then to give me ideas how to do things its very useful
Good to know.
yesterday i found a built in function for swapping from left to right hand and thought you might be interested.
Yeah I noticed that long time ago but never get it working. It appears that I mistook that function as one that affects the object itself and didn't overwrite the original matrix with the swapped one. I tested the other left-handed formats posted in this thread but some of them seem to be in right-handed already(Aavtar The Game, Iron Man 2 and IDOLM@STER). Not sure if it's because they use a different naming aspect from the others so I'll leave them as they are. Thanks for the hint anyway.