hey howfie! could you please explain what exactly you did with those bone id's xDD
Sure. Now, I only extracted Kitana_A model, so I'll explain that one. In her SkeletalMesh file, the blending information (blend indices and blend weights) are stored at offset 0xB91D4. Reading them is simple:
//
// VERTEX BUFFER #3
// BLENDING
//
struct MKXBLENDWEIGHT {
uint08 bytes[8];
};
// move to vertex buffer
ifile.seekg(vb3_offset);
if(ifile.fail()) return error("Seek failure.", __LINE__);
// read info
uint16 vb3_h01 = LE_read_uint32(ifile); // bytes per vertex
uint16 vb3_h02 = LE_read_uint32(ifile); // number of vertices
uint16 vb3_h03 = LE_read_uint32(ifile); // number of vertices
if(ifile.fail()) return error("Read failure.", __LINE__);
if(vb3_h02 != n_verts) return error("Unexpected number of vertices.", __LINE__);
if(vb3_h03 != n_verts) return error("Unexpected number of vertices.", __LINE__);
// read data
boost::shared_array<MKXBLENDWEIGHT> bwlist(new MKXBLENDWEIGHT[n_verts]);
for(uint32 i = 0; i < n_verts; i++) {
bwlist[i].bytes[0] = LE_read_uint08(ifile); // blendindex
bwlist[i].bytes[1] = LE_read_uint08(ifile); // blendindex
bwlist[i].bytes[2] = LE_read_uint08(ifile); // blendindex
bwlist[i].bytes[3] = LE_read_uint08(ifile); // blendindex
bwlist[i].bytes[4] = LE_read_uint08(ifile); // blendindex
bwlist[i].bytes[5] = LE_read_uint08(ifile); // blendweight
bwlist[i].bytes[6] = LE_read_uint08(ifile); // blendweight
bwlist[i].bytes[7] = LE_read_uint08(ifile); // blendweight
if(ifile.fail()) return error("Read failure.", __LINE__);
}
First thing to notice is that of the 8 bytes per vertex, 5 of them (not 4) are for blendindices and 3 of them (not 4) are for blendweights. Here is an example:
vtx 0x1bb6: [12 68 90 c1 03] - [7d 38 32] a point on her shirt, near her left boob.
The last 3 numbers: 7D, 38, 32, do not sum to FF so there are 4 blendweights. However, there are 5 indices.
If you view indices as single bytes, you look up 0x12 in the joint map and see it remaps to bone 0x04, which is fine (it's a spine bone). But now you look up 0x68 but can't the joint map only has 0x47 elements in it. chrrox and I noticed that the second number is "almost always divisible by 4." So if you divide 0x68 by 0x04 to get 0x1A and look up 0x1A in the joint map, the second index remaps to bone 0x05, which is also good (another spine bone).
Now try 0x90. The third number is "almost always divisible by 0x10." So we get 0x09 and look it up in the joint map to see it remaps to bone 0xAF, which is a bone in the FOOT! This is wrong, and moving the ankle bone will also move part of her left boob as well lol.
So we know 0x90 is wrong. What is the correct value? Well, in the joint map, her boob bone is bone 0xA3, which is index 0x19. Multiply that index by 0x10 and we get 0x0190. Where do we get that extra 01 from? From the next byte, 0xC1. You get the 1 from the 4 LSB in 0xC1.
jointmap[0x47] =
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
07 00 06 00 10 00 27 00 28 00 A8 00 A7 00 A9 00 AA 00 AF 00 AE 00 B0 00 B1 00 01 00 02 00 03 00
AB 00 A4 00 04 00 A5 00 AC 00 B5 00 B4 00 B3 00 A2 00 A3 00 05 00 63 00 64 00 82 00 83 00 7B 00
68 00 7C 00 7D 00 7E 00 7F 00 80 00 81 00 75 00 74 00 76 00 71 00 77 00 72 00 73 00 6C 00 6D 00
69 00 6E 00 6A 00 6B 00 78 00 79 00 7A 00 9A 00 87 00 9B 00 9C 00 9D 00 9E 00 9F 00 A0 00 94 00
93 00 95 00 90 00 96 00 91 00 92 00 8B 00 8C 00 88 00 8D 00 89 00 8A 00 97 00 98 00 99 00
So this is what you do for these indices:
[12 68 90 c1 03] hex = [00010010 01101000 10010000 11000001 00000011] binary
Take two LSB from 68 (00) and move them to front of 12 (00010010).
So first index is 0000010010 = 0x12.
Take four LSB from 90 (0000) and move them to front of 68 (01101000).
So second index is 000001101000 = 68 / 04 = 0x1A.
Take 6 LSB from c1 (000001) and move them to front of 90 (10010000).
So third index is 00000110010000 = 190 / 10 = 0x19.
Finally, take all 8 bits from 03 (00000011) and move them to front of c1 (11000001).
So final index is 0000001111000001 = 3C1 / 40 = 0x0F.
0x0F index remaps to bone 0x03, which is also a spine bone and now everything is correct.
I use the following code to process the 5 indices, where i1, i2, i3, i4, and i5 are the original indices:
uint16 final_index1 = (i1 | ((i2 & 0x03) << 8));
uint16 final_index2 = (i2 | ((i3 & 0x0F) << 8)) >> 2;
uint16 final_index3 = (i3 | ((i4 & 0x3F) << 8)) >> 4;
uint16 final_index4 = (i4 | (i5 << 8)) >> 6;