Hey guys, been pretty busy the last couple of days, certainly with the D3 Expansion coming along.
I've taken every piece of code I could find, dropped it into a max script and now I'm able to import the app files into max, completely rigged and skinned.
It took quit some time to figure out how to apply all these things in Max, cause exporting it to obj does not involve bones, vertex weights etc...
it's not completed yet, just a wip..
I need some way to find the texture/material
in the code I took the example of Adria, so if you want to use the script ( as of Max 2011) you need to change the hard coded file of adria.app and here dds files to make it work
Code: Select all
/*
Import Diablo III App format
by Taylor Mouse (c) 12.2013
*/
/* CLEAN UP */
ClearListener()
max select all
max delete
/********************/
/* Helper functions */
/********************/
fn ReadBytes stream val =
(
for i=1 to val do ReadByte stream
)
fn ReadFixedString stream val =
(
local str = ""
for i=1 to val do
(
s= bit.IntAsChar(ReadByte stream)
if(s!="\0") then str+=s
)
return str
)
/********************/
/* STRUCTS */
/********************/
struct AABB
(
A,
B
)
struct D3Bone
(
ID,
Name,
ParentID,
Position,
TheBone
)
struct GeoSet
(
Name,
theMesh,
Verts,
VertexWeights,
Normals,
UVWs,
Indices,
nVerts,
ofVerts,
sizeVerts,
ofVertexWeights,
sizeWeights,
nIndices,
ofIndices,
sizeIndices
)
struct VertexWeight --> Influence
(
BoneID1,Weight1,
BoneID2,Weight2,
BoneID3,Weight3
)
/********************/
/********************/
file = @"..\Exported\Appearance\Adria.app"
stream = fOpen file "rb"
-- Skip 36 bytes
ReadBytes stream 36
-- Bones
nBones = ReadLong stream
ofBones = ReadLong stream
sizeBones = ReadLong stream
-- Skip 120 bytes
ReadBytes stream 120
-- Subsets
nSubset = ReadLong stream
ofSubset = ReadLong stream
sizeSubset = ReadLong stream
-- Skip 36 bytes
ReadBytes stream 36
-- Collision Sphere
sph = sphere pos:[ReadFloat stream , ReadFloat stream , ReadFloat stream] radius:(ReadFloat stream) name:"CollisionSphere"
sph.xray = true
-- Colission Capsules
nCollCap = ReadLong stream
offCollCap = ReadLong stream
sizeCollCap = ReadLong stream
allBones = #()
/* BONES */
if(ofBones > 0 ) then
(
fSeek stream (ofBones + 16) #seek_set
for b=1 to nBones do
(
aBone = D3Bone()
aBone.ID = b
aBone.Name = ReadFixedString stream 64
aBone.ParentID = (ReadLong stream) + 1 --> 0 is the root
-- Bounding Boxes
ab = AABB()
ab.A = [ReadFloat stream , ReadFloat stream , ReadFloat stream]
ab.B = [ReadFloat stream , ReadFloat stream , ReadFloat stream]
x = ab.A.X - ab.B.X
y = ab.A.Y - ab.B.Y
z = ab.A.Z - ab.B.Z
-- Box length:x width:y height:z wirecolor:(color c 0 0)
-- Bounding Spheres
radius = ReadFloat stream
position = [ReadFloat stream , ReadFloat stream , ReadFloat stream]
-- Sphere radius:0.2 pos:position wirecolor:(Color 0 c 0)
-- PRSTransform
q1 = quat (ReadFloat stream) (ReadFloat stream) (ReadFloat stream) (ReadFloat stream)
v1 = Point3 (ReadFloat stream) (ReadFloat stream) (ReadFloat stream)
aBone.Position = v1
append allBones aBone
ReadBytes stream 100 ---> not required,... yet
)
/* Build the bones*/
for b=1 to nBones do
(
if( allBones[b].ParentID == 0 ) then
(
allBones[b].TheBone = BoneSys.CreateBone allBones[b].Position allBones[b].Position [0,0,1]
)
else
(
parentID = allBones[b].ParentID
allBones[b].TheBone = BoneSys.CreateBone allBones[b].Position allBones[b].Position [0,0,1]
allBones[b].TheBone.Parent = allBones[parentID].TheBone
)
allBones[b].TheBone.Name = allBones[b].Name
allBones[b].TheBone.ShowLinks = true
allBones[b].TheBone.Width = 0.05
allBones[b].TheBone.Height = 0.05
)
)
/* GEOSETS */
fSeek stream (ofSubset + 16) #seek_set
geosets= #()
for subset=1 to nSubset do
(
g = GeoSet()
ReadLong stream -- ?
g.nVerts = ReadLong stream
g.ofVerts = ReadLong stream
g.sizeVerts = ReadLong stream
ReadLong stream -- ?
g.ofVertexWeights = ReadLong stream
g.sizeWeights = ReadLong stream
ReadLong stream -- ?
g.nIndices = ReadLong stream
g.ofIndices = ReadLong stream
g.sizeIndices = ReadLong stream
ReadBytes stream 28
g.name = ReadFixedString stream 128
name2 = ReadFixedString stream 128
ReadBytes stream 44
append geosets g
)
/* GEO Data */
for i=1 to nSubset do
(
verts = #()
vertexWeights = #()
normals = #()
uvws = #()
indices = #()
/* Vertices, normals, texture coordinates */
fSeek stream ( geosets[i].ofVerts + 16 ) #seek_set
for v=1 to geosets[i].nVerts do
(
-- vertex
vert = [ ReadFloat stream, ReadFloat stream, ReadFloat stream ]
append verts vert
-- normal
nx = ReadByte stream
ny = ReadByte stream
nz = ReadByte stream
ReadBytes stream 9
rnx = (nx - 127.0)/127.0
rny = (ny - 127.0)/127.0
rnz = (nz - 127.0)/127.0
normal = [rnx, rny, rnz]
append normals normal
-- Texture Coordinate
texU = ReadShort stream #unsigned
texV = ReadShort stream #unsigned
ReadBytes stream 16
tu = float
tv = float
tu = 32767.0 - texU
tv = 32767.0 - texV
tu /= 512.0
tv /= 512.0
tv +=1.0
tu *=-1.0
uv = [tu, tv, 0.0]
append uvws uv
)
/* Vertex Weights */
fSeek stream ( geosets[i].ofVertexWeights + 16 ) #seek_set
for v=1 to geosets[i].nVerts do
(
vw = VertexWeight()
vw.BoneID1 = ReadLong stream
vw.Weight1 = ReadFloat stream
vw.BoneID2 = ReadLong stream
vw.Weight2 = ReadFloat stream
vw.BoneID3 = ReadLong stream
vw.Weight3 = ReadFloat stream
append vertexWeights vw
)
/* Indices */
fSeek stream ( geosets[i].ofIndices + 16 ) #seek_set
for f=1 to geosets[i].nIndices / 3 do
(
index = [ReadShort stream #unsigned +1 , ReadShort stream #unsigned + 1, ReadShort stream #unsigned + 1]
append indices index
)
geosets[i].Verts = verts
geosets[i].UVWs = uvws
geosets[i].Normals = normals
geosets[i].Indices = indices
geosets[i].VertexWeights = vertexWeights
)
/* BUILD THE MESHES */
for i=1 to nSubset do
(
-- Create the mesh
theMesh = mesh vertices:geosets[i].Verts faces:geosets[i].Indices name:geosets[i].Name tverts:geosets[i].UVWs vnorms:geosets[i].Normals
meshOp.setMapSupport theMesh 1 true
for t = 1 to geosets[i].Verts.count do
meshop.setMapVert theMesh 1 t geosets[i].UVWs[t]
update theMesh
-- create the materials
meditMaterials[i] = Standard()
meditMaterials[i].name = geosets[i].Name
meditMaterials[i].diffuseMapEnable = on
meditMaterials[i].selfillumMapEnable = on
meditMaterials[i].useSelfIllumColor = on
meditMaterials[i].opacityMapEnable = on
meditMaterials[i].specularLevel = 50
meditMaterials[i].selfIllumColor = color 255 255 255
meditMaterials[i].diffuseMap = Bitmaptexture fileName:"..\Adria_A_DiffCON.dds"
meditMaterials[i].specularMap = Bitmaptexture fileName:"..\Adria_A_SpecCON.dds"
meditMaterials[i].selfillumMap = Bitmaptexture fileName:"..\Adria_A_SpecCON.dds"
meditMaterials[i].opacityMap = Bitmaptexture fileName:"..\Adria_A_DiffCON.dds"
meditMaterials[i].opacityMap.monooutput = 1
showTextureMap meditMaterials[i] true
theMesh.material = meditMaterials[i]
update theMesh
geosets[i].theMesh = theMesh
/*
TODO:
Find the matching texture using an algorithm
*/
)
for i=1 to nSubset do
(
msh = geosets[i].theMesh
-- Apply skin modifier
select msh
max modify mode --> VERY IMPORTANT!!!
modPanel.addModToSelection(skin())
skinMod = msh.Modifiers["skin"]
modPanel.setCurrentObject skinMod
-- add all the bones
for b=1 to nBones do
(
skinOps.addBone skinMod allBones[b].TheBone 0
)
update msh
-- Apply vertex weights
--disableSceneRedraw()
select msh
max modify mode
bones_total_count = skinops.getnumberbones skinMod
vertex_count = getNumverts msh
for v = 1 to vertex_count do
(
--vertex_bone_count = skinOps.GetVertexWeightCount msh.modifiers[#skin] v
for b = 1 to bones_total_count do
(
boneId1 = geosets[i].VertexWeights[v].BoneId1 + 1
weight1 = geosets[i].VertexWeights[v].Weight1
boneId2 = geosets[i].VertexWeights[v].BoneId2 + 1
weight2 = geosets[i].VertexWeights[v].Weight2
boneId3 = geosets[i].VertexWeights[v].BoneId3 + 1
weight3 = geosets[i].VertexWeights[v].Weight3
if (b == boneId1) then
skinOps.ReplaceVertexWeights skinMod v boneId1 weight1
else if (b == boneId2) then
skinOps.SetVertexWeights skinMod v boneId2 weight2
else if (b == boneId3) then
skinOps.SetVertexWeights skinMod v boneId3 weight3
)
-- apply the new bone weights
update msh
)
--enableSceneRedraw()
update msh
redrawviews()
)
/* Clean up */
fFlush stream
fClose stream
clearselection()
GC()
/* Zoom into the selected model */
max zoomext sel all
T.