I have coded an application which can export and import data into the yukes model format (yobj). I am exporting and importing using the wavefront model format and am limited to importing the uv's and verts.
With the pc version of the game I am having issues with editing the heads of the models. Any changes causes the head to get corrupted in game as follows:

If I disable the facial animations it looks fine in game but the models have no expressions:

I am assuming that the issue is with the weights?
I took a look the weights of the model when imported with brienj's import script but it seems like the weights are not being imported correctly into 3ds max.
I then looked at chrrox's script in this thread viewtopic.php?f=16&t=6183&hilit=Rumble+Roses
and rewrote parts of it to read the new model format. After making the modifications, the xbox 360 models are imported with the correct weights.
The new PC models have up to 7 bones assigned to each vert whereas the old format had a maximum of 4 bones per vert. I have modified the script to add the additional bones but it crashes when trying to load the newer models with the error: Exceeded the vertex countSkin:Skin
I am not an expert in max script as I code in C#, if someone can help me with the script it would be appreciated.
The modified script looks like this:
Code: Select all
if (heapSize < 200000) then
heapSize = 2000000 -- allow ~ 40 MB instead of just 7.5 MB. Prevents "Runtime Error: Out of scripter memory"
fname = getOpenFileName \
caption:"WWE2012 upwards Model File" \
types:"WWEModel File(*.yobj)|*.yobj" \
historyCategory:"WWE Object Presets"
f = fopen fname "rb"
fn ReadBEShort fstream = (
short = readshort fstream #unsigned
short = bit.swapBytes short 2 1
b = (bit.get short 16)
for i = 17 to 32 do short = bit.set short i b
return short
)
fn PrintOffset Var =
(
local Var = Var
print ("This is the offset 0x" + (bit.intAsHex Var) as string)
Var
)
fn floatSwap2 f =
(
i = bit.floatAsInt f
h = bit.intashex i
while h.count < 8 do h = "0" + h
s = (substring h 7 2) + (substring h 5 2) + (substring h 3 2) + (substring h 1 2)
bit.intAsFloat (bit.hexasint s)
)
fn ReadBEword fstream = (
return (bit.swapBytes (readshort fstream #unsigned) 1 2)
)
fn convertTo32 input16 = (
inputAsInt = input16
sign = bit.get inputAsInt 16
exponent = (bit.shift (bit.and inputAsInt (bit.hexasint "7C00")) -10) as integer - 16
fraction = bit.and inputAsInt (bit.hexasint "03FF")
if sign==true then sign = 1 else sign = 0
exponentF = exponent + 127
--Ouput 32 bit integer representing a 32 bit float
outputAsFloat = bit.or (bit.or (bit.shift fraction 13) (bit.shift exponentF 23)) (bit.shift sign 31)
--Output Check
return bit.intasfloat outputasfloat
)
fn ReadBEHalfFloat fstream = (
return convertTo32(ReadBEword fstream)
)
fn ReadHalfFloat fstream = (
return convertTo32(readshort fstream#unsigned)
)
fn ReadBElong fstream = (
long = readlong fstream
long = bit.swapBytes long 1 4
long = bit.swapBytes long 2 3
return long
)
fn ReadBEfloat fstream = (
return floatSwap2(readfloat fstream)
)
fn ReadFixedString bstream fixedLen =
(
local str = ""
for i = 1 to fixedLen do
(
str += bit.intAsChar (ReadByte bstream #unsigned)
)
str
)
struct weight_data
(
boneids,weights
)
Idstring = ReadFixedString f 4
Totalsize = ReadBElong f
Unk001 = ReadBElong f
Unk002 = ReadBElong f
Unk003 = ReadBElong f
Unk004 = ReadBElong f
MeshCount = ReadBElong f
MeshOff = ReadBElong f + 8
BoneCount = ReadBElong f
TexCount = ReadBElong f
BoneOffset = ReadBElong f + 8
TexOff = ReadBElong f + 8
MnameOff = ReadBElong f + 8
MnameCount = ReadBElong f
Unk013 = ReadBElong f
Unk014 = ReadBElong f
Unk015 = ReadBElong f
Unk016 = ReadBElong f
fseek f BoneOffset#seek_set
tarr = #()
rarr = #()
qarr = #()
Barr = #()
Parr = #()
for a = 1 to BoneCount Do (
BoneName = ReadFixedString f 16
tx = ReadBEfloat f
ty = ReadBEfloat f
tz = ReadBEfloat f
tw = ReadBEfloat f
rx = (ReadBEfloat f * 180) / pi
ry = (ReadBEfloat f * 180) / pi
rz = (ReadBEfloat f * 180) / pi
rw = ReadBEfloat f
parent = ReadBElong f
fseek f 0xC#seek_cur
qx = ReadBEfloat f
qy = ReadBEfloat f
qz = ReadBEfloat f
qw = ReadBEfloat f
tfm = (eulerangles rx ry rz) as matrix3
append tarr [tx,ty,tz]
append rarr tfm
append qarr [qx,qy,qz,qw]
append Barr BoneName
append Parr parent
)
BNArr = #()
for a = 1 to BoneCount Do (
if isvalidnode (getNodeByName Barr[a]) != true then (
tfm = rarr[a]
tfm.row4 = tarr[a]
if (Parr[a] != -1) do (
tfm = tfm * BNArr[(Parr[a] + 1)].objecttransform
)
newBone = bonesys.createbone \
tfm.row4 \
(tfm.row4 + 0.01 * (normalize tfm.row1)) \
(normalize tfm.row3)
newBone.name = Barr[a]
newBone.width = 0.01
newBone.height = 0.01
newBone.transform = tfm
newBone.setBoneEnable false 0
newBone.wirecolor = yellow
newbone.showlinks = true
newBone.pos.controller = TCB_position ()
newBone.rotation.controller = TCB_rotation ()
)
if isvalidnode (getNodeByName Barr[a]) == true then (
newBone = getNodeByName Barr[a]
)
if (Parr[a] != -1) then
newBone.parent = BNArr[(Parr[a] + 1)]
append BNArr newBone
)
struct Mesh_Info_Struct
(
Objname,VertOff,WeightOff,UVOff,MatPCount,matPOff,FaceOff,FaceSec,VertCount,WeightCount,BtableStart
)
fseek f MeshOff#seek_set
Mesh_Info_Arr = #()
for a = 1 to MeshCount Do (
VCount1 = ReadBElong f
FaceSec = ReadBElong f
BtableStart = (ftell f)
UsedBoneID = ReadBElong f
fseek f 0x50#seek_cur
WeightCount = ReadBElong f
Unk102 = ReadBElong f
Unk103 = ReadBElong f
VertOff = ReadBElong f + 8
WeightOff = ReadBElong f + 8
UVOff = ReadBElong f + 8
Unk999 = ReadBElong f
Unk107 = ReadBElong f
Objname = ReadFixedString f 16
Unk108 = ReadBElong f
Unk109 = ReadBElong f
MatPCount = ReadBElong f
matPOff = ReadBElong f + 8
FaceOff = ReadBElong f + 8
VertCount = ReadBElong f
Unk114 = ReadBElong f
fseek f 0x10#seek_cur
append Mesh_Info_Arr (Mesh_Info_Struct Objname:Objname VertOff:VertOff WeightOff:WeightOff UVOff:UVOff MatPCount:MatPCount matPOff:matPOff FaceOff:FaceOff FaceSec:FaceSec VertCount:VertCount WeightCount:WeightCount BtableStart:BtableStart )
)
print Mesh_Info_Arr
for a = 1 to MeshCount Do (
Vert_array = #()
Normal_array = #()
UV_array = #()
Face_array = #()
Weight_array = #()
fseek f Mesh_Info_Arr[a].VertOff#seek_set
--scale1 = ReadBEfloat f
scale1 = 10
VertOff = ReadBElong f + 8
print VertOff
fseek f VertOff#seek_set
--print scale1
for b = 1 to Mesh_Info_Arr[a].VertCount Do (
vx = ReadBEfloat f
vy = ReadBEfloat f
vz = ReadBEfloat f
fseek f 0x10#seek_cur
append Vert_array [vx,vy,vz]
)
fseek f Mesh_Info_Arr[a].UVOff#seek_set
for b = 1 to Mesh_Info_Arr[a].VertCount Do (
tu = ReadBEfloat f
tv = ReadBEfloat f * -1
append UV_array [tu,tv,0]
)
fseek f Mesh_Info_Arr[a].WeightOff#seek_set
for b = 1 to Mesh_Info_Arr[a].VertCount Do (
Bone1 = -1
Bone2 = -1
Bone3 = -1
Bone4 = -1
Bone5 = -1
Bone6 = -1
Bone7 = -1
if Mesh_Info_Arr[a].WeightCount == 1 do (
Bone1 = readbyte f
fseek f 0x3#seek_cur
Weight1 = ReadBEfloat f
)
if Mesh_Info_Arr[a].WeightCount == 2 do (
Bone1 = readbyte f
fseek f 0x3#seek_cur
Weight1 = ReadBEfloat f
Bone2 = readbyte f
fseek f 0x3#seek_cur
Weight2 = ReadBEfloat f
)
if Mesh_Info_Arr[a].WeightCount == 3 do (
Bone1 = readbyte f
fseek f 0x3#seek_cur
Weight1 = ReadBEfloat f
Bone2 = readbyte f
fseek f 0x3#seek_cur
Weight2 = ReadBEfloat f
Bone3 = readbyte f
fseek f 0x3#seek_cur
Weight3 = ReadBEfloat f
)
if Mesh_Info_Arr[a].WeightCount == 4 do (
Bone1 = readbyte f
fseek f 0x3#seek_cur
Weight1 = ReadBEfloat f
Bone2 = readbyte f
fseek f 0x3#seek_cur
Weight2 = ReadBEfloat f
Bone3 = readbyte f
fseek f 0x3#seek_cur
Weight3 = ReadBEfloat f
Bone4 = readbyte f
fseek f 0x3#seek_cur
Weight4 = readfloat f
)
if Mesh_Info_Arr[a].WeightCount == 5 do (
Bone1 = readbyte f
fseek f 0x3#seek_cur
Weight1 = ReadBEfloat f
Bone2 = readbyte f
fseek f 0x3#seek_cur
Weight2 = ReadBEfloat f
Bone3 = readbyte f
fseek f 0x3#seek_cur
Weight3 = ReadBEfloat f
Bone4 = readbyte f
fseek f 0x3#seek_cur
Weight4 = readfloat f
Bone5 = readbyte f
fseek f 0x3#seek_cur
Weight5 = readfloat f
)
if Mesh_Info_Arr[a].WeightCount == 6 do (
Bone1 = readbyte f
fseek f 0x3#seek_cur
Weight1 = ReadBEfloat f
Bone2 = readbyte f
fseek f 0x3#seek_cur
Weight2 = ReadBEfloat f
Bone3 = readbyte f
fseek f 0x3#seek_cur
Weight3 = ReadBEfloat f
Bone4 = readbyte f
fseek f 0x3#seek_cur
Weight4 = readfloat f
Bone5 = readbyte f
fseek f 0x3#seek_cur
Weight5 = readfloat f
Bone6 = readbyte f
fseek f 0x3#seek_cur
Weight6 = readfloat f
)
if Mesh_Info_Arr[a].WeightCount == 7 do (
Bone1 = readbyte f
fseek f 0x3#seek_cur
Weight1 = ReadBEfloat f
Bone2 = readbyte f
fseek f 0x3#seek_cur
Weight2 = ReadBEfloat f
Bone3 = readbyte f
fseek f 0x3#seek_cur
Weight3 = ReadBEfloat f
Bone4 = readbyte f
fseek f 0x3#seek_cur
Weight4 = readfloat f
Bone5 = readbyte f
fseek f 0x3#seek_cur
Weight5 = readfloat f
Bone6 = readbyte f
fseek f 0x3#seek_cur
Weight6 = readfloat f
Bone7 = readbyte f
fseek f 0x3#seek_cur
Weight7 = readfloat f
)
w = (weight_data boneids:#() weights:#())
maxweight = 0
if(Bone1 != -1) then
maxweight = maxweight + weight1
if(Bone2 != -1) then
maxweight = maxweight + weight2
if(Bone3 != -1) then
maxweight = maxweight + weight3
if(Bone4 != -1) then
maxweight = maxweight + weight4
if(Bone5 != -1) then
maxweight = maxweight + weight5
if(Bone6 != -1) then
maxweight = maxweight + weight6
if(Bone7 != -1) then
maxweight = maxweight + weight7
if(maxweight != 0) then (
if(Bone1 != -1) then (
w1 = weight1 as float
append w.boneids (bone1 + 1)
append w.weights w1
)
if(Bone2 != -1) then (
w2 = weight2 as float
append w.boneids (bone2 + 1)
append w.weights w2
)
if(Bone3 != -1) then (
w3 = weight3 as float
append w.boneids (bone3 + 1)
append w.weights w3
)
if(Bone4 != -1) then (
w4 = weight4 as float
append w.boneids (bone4 + 1)
append w.weights w4
)
if(Bone5 != -1) then (
w5 = weight5 as float
append w.boneids (bone5 + 1)
append w.weights w5
)
if(Bone6 != -1) then (
w6 = weight6 as float
append w.boneids (bone6 + 1)
append w.weights w6
)
if(Bone7 != -1) then (
w7 = weight7 as float
append w.boneids (bone7 + 1)
append w.weights w7
)
)
append Weight_array w
)
fseek f Mesh_Info_Arr[a].FaceOff#seek_set
Ftmp = #()
for b = 1 to Mesh_Info_Arr[a].FaceSec Do (
FSize = ReadBElong f as float
FCount = ReadBElong f as float
FStart = (ReadBElong f + 8) as float
append Ftmp [FSize,FCount,FStart]
)
for b = 1 to Mesh_Info_Arr[a].FaceSec Do (
fseek f Ftmp[b].z#seek_set
FaceEnd = ((ftell f) + (2 * Ftmp[b].y))
StartDirection = 1
Face_array2 = #()
f1 = ReadBEword f + 1
f2 = ReadBEword f + 1
FaceDirection = StartDirection
do (
f3 = ReadBEword f
if (f3==0xFFFF) then (
f1 = ReadBEword f + 1
f2 = ReadBEword f + 1
FaceDirection = StartDirection
) else (
f3 += 1
FaceDirection *= -1
if (f1!=f2)AND(f2!=f3)AND(f3!=f1) then (
append Face_array2 [(f1),(f2),(f3)]
if FaceDirection > 0 then append Face_array [(f1),(f2),(f3)]
else append Face_array [(f1),(f3),(f2)]
)
f1 = f2
f2 = f3
)
)while (ftell f) < (FaceEnd)
)
fseek f Mesh_Info_Arr[a].BtableStart#seek_set
usedID = ReadBElong f
Used_Bone_array = #()
for b = 1 to usedID do (
bid = ReadBElong f
append Used_Bone_array bid
)
msh = mesh vertices:Vert_array faces:Face_array
msh.numTVerts = UV_array.count
buildTVFaces msh
--msh.name = Mesh_Name_array[a]
--msh.material = meditMaterials[1].materialList[(MatSlotTexID[a])]
for j = 1 to UV_array.count do setTVert msh j UV_array[j]
for j = 1 to Face_array.count do setTVFace msh j Face_array[j]
for j = 1 to Normal_array.count do setNormal msh j Normal_array[j]
max modify mode
select msh
skinMod = skin ()
addModifier msh skinMod
print "skinOps.getNumberVertices"
format "vCnt skinMod %\n" (skinOps.getNumberVertices skinMod)
for i = 1 to Used_Bone_array.count do
(
maxbone = BNArr[(Used_Bone_array[i])]
if i != Used_Bone_array.count then
skinOps.addBone skinMod maxbone 0
else
skinOps.addBone skinMod maxbone 1
)
modPanel.setCurrentObject skinMod
print "weight array count"
print Weight_array.count
for i = 1 to Weight_array.count do
(
w = Weight_array[i]
bi = #()
wv = #()
print "bone id's count"
print w.boneids.count
for j = 1 to w.boneids.count do
(
boneid = w.boneids[j]
weight = w.weights[j]
append bi boneid
append wv weight
)
skinOps.ReplaceVertexWeights skinMod i bi wv
)
max create mode
)
fclose f
Secondly, what is the easiest way to export the weight data from 3ds max. The yobj files have the weight data in the format:
boneId weight, etc
I am looking into the collada model format but it doesn't seem to contain the weight data in this format.