3DS MAX Importing the "SMD" Files ((2013))

Hey! I’ve decompiled and got the IDF VariantC From CS:GO And I Dont Know how Import it into 3DS MAX.

There is currently no smd imported for Max 2013.

you can either use a previous version of max
Or you can download blender, there is a smd importer addon. Then you just export it to a obj file and use it in max.

Blenders exporters are really broken though, last I tried about half of the exporters fell apart when I used them
I think that the COLLADA exporter works fine though

use 3ds max 2011 instead, any versions after 11 are a hassle to deal with.

I use 2012 and it seems to work fine.

I finally wrote a SMD import script for 3dsmax :slight_smile:

Because maxscript is supported in all versions of 3dsmax you’ll never have to wait for wunderboy to support the next 3dsmax version XXXX

scripts are slower than compiled plugins, but If this is well received maybe I’ll write a GUI and add SMD export.

to use the script open 3dsmax go at the top where it says maxscript. and click on “New Script” to open a blank script.
paste the code from below into the editor and press CTRL+E to run the script. it’ll ask you to open a SMD etc…

from the editor you can press CTRL+S to save the script for later use.
After which you can just drag and drop the script into 3dsmax.
Or assign it to a button within max, or just goto maxscript > Run… its very flexible…

Let me know if there are any problems


SOURCE - SMD Importer
By: Mario_Kart64n
Date: January 13, 2013

Core of importer written :D

-- fsource="D:\\MaxScripts\\SMD (Studio Model Data)\\ref.smd"
-- fsource="D:\\MaxScripts\\SMD (Studio Model Data)\\skl.txt"

-- obj=$*;delete obj
buildMsh = true
buildSkn = true
buildSkl = true

fsource = GetOpenFileName \
caption:"SMD File Importer" \
types: "Studio Model Data (*.smd)|*.SMD|All files (*.*)|*.*|"
if (fsource!=undefined) AND ((doesFileExist fsource)==true) then(
LOCAL f=MemStreamMgr.openFile fsource

fn parseblock fstream = (
string_array = #()
tag = fstream.readLine()
while tag != "end" AND fstream.eos() != true do (
append string_array tag;tag = fstream.readLine()
return string_array

fn relativetoworld obj obj2 idx = ( -- realtive to world positions
pos = obj.matrix[idx]
par = obj2.parent[idx]
if par!=0 then (
while par != 0 do (
pos*= obj.matrix[par]
par = obj2.parent[par]
-- pos*=(rotateX pos 90)
return pos

struct smd_format (header,nodes,skeleton,bones,triangles)
struct smd_header (version)
struct smd_nodes (index,name,parent)
struct smd_skeleton (frame,bone)
struct smd_bone (index,matrix)
struct smd_triangles (material,geometry)
struct smd_vertex (parent,position,normal,texture,count,boneid,weight,faces)

smdArray = (smd_format header:#() nodes:#() skeleton:#() bones:#() triangles:#())
smdArray.header = (smd_header version:(f.readLine()))
smdArray.nodes = (smd_nodes index:#() name:#() parent:#())
smdArray.skeleton = (smd_skeleton frame:#() bone:#())
smdArray.triangles = (smd_triangles material:#() geometry:#())

face_lookup = #()

if smdArray.header.version == "version 1" then (
while f.eos() != true do (
smd_element = f.readLine()
strArray = parseblock f
case smd_element of (
for i = 1 to strArray.count do (
smdArray.nodes.index* = (readDelimitedString (strArray* as stringstream) "\"")
smdArray.nodes.name* = (strArray* as stringstream);skipToString (smdArray.nodes.name* as stringstream) "\""
smdArray.nodes.name* = readDelimitedString (smdArray.nodes.name* as stringstream) "\""
smdArray.nodes.parent* = (strArray* as stringstream)
skipToString (smdArray.nodes.parent* as stringstream) "\""
skipToString (smdArray.nodes.parent* as stringstream) "\""
smdArray.nodes.parent* = (execute (readDelimitedString (smdArray.nodes.parent* as stringstream) ""))+1
cnt = 1
while cnt<=strArray.count do (
delimited = filterString strArray[cnt] " ";cnt+=1
frame_index = (delimited[2] as integer)+1
smdArray.skeleton.frame[frame_index]=(smd_bone index:#() matrix:#())
do (
delimited = filterString strArray[cnt] " "
if delimited[1]!="time" then (
bone_index = (delimited[1] as integer)+1
bone_matrix = (eulerAngles \
(radToDeg (execute delimited[5])) \
(radToDeg (execute delimited[6])) \
(radToDeg (execute delimited[7]))) as matrix3
bone_matrix.row4 = [(execute delimited[2]),(execute delimited[3]),(execute delimited[4])]
frame_index = delimited[2] as integer
) while delimited[1]!="time" AND cnt<=strArray.count
cnt = 0
mat_id = 0

for i = 1 to (strArray.count/4) do (
cnt = ((i-1)*4)+1
tex_name = strArray[cnt];cnt+=1

find = findItem smdArray.triangles.material tex_name
if find!=0 then (mat_id=find) else(
smdArray.triangles.geometry[mat_id]=(smd_vertex parent:#() position:#() normal:#() texture:#() count:#() boneid:#() weight:#() faces:#())

for x = 1 to 3 do (
delimited = filterString strArray[cnt] " ";cnt+=1
boneid = delimited[1] as integer
position = [(execute delimited[2]),(execute delimited[3]),(execute delimited[4])]
normal = [(execute delimited[5]),(execute delimited[6]),(execute delimited[7])]
texture = [(execute delimited[8]),(execute delimited[9]),0]
bone_id_count = delimited[10] as integer
id_index = 11
bi = #();bw = #()
for y = 1 to bone_id_count do (
bi[y]=((delimited[id_index] as integer)+1);id_index+=1
bw[y]=(execute delimited[id_index]);id_index+=1
str = (position+normal+texture)*bone_id_count
find = findItem face_lookup[mat_id] str
if find == 0 then (
find = smdArray.triangles.geometry[mat_id].position.count
append face_lookup[mat_id] str
append smdArray.triangles.geometry[mat_id].faces (find+1)
append smdArray.triangles.geometry[mat_id].parent boneid
append smdArray.triangles.geometry[mat_id].position position
append smdArray.triangles.geometry[mat_id].normal normal
append smdArray.triangles.geometry[mat_id].texture texture
append smdArray.triangles.geometry[mat_id].count bone_id_count
append smdArray.triangles.geometry[mat_id].boneid bi
append smdArray.triangles.geometry[mat_id].weight bw
append smdArray.triangles.geometry[mat_id].faces find
-- print smdArray.triangles.material
bone_count = smdArray.skeleton.frame[1].matrix.count
for i = 1 to bone_count do (
bone_transform = relativetoworld smdArray.skeleton.frame[1] smdArray.nodes i
bone_ext = bone_transform.row4+[0,0,4]
find = findItem smdArray.nodes.parent i

if find!=0 do (
bone_ext = relativetoworld smdArray.skeleton.frame[1] smdArray.nodes find
bone_ext = bone_ext.row4


bb=(BoneSys.createBone bone_transform.row4 bone_ext [0,0,1])
bb.showLinks = true
bb.showLinksOnly = true
bone_size = 2
bb.width = bone_size
bb.height = bone_size
bb.transform = bone_transform
bb.boneEnable = true
bb.name = smdArray.nodes.name*
append boneArray bb
for i = 1 to bone_count do (
par = smdArray.nodes.parent*
if par!=0 do (
boneArray*.parent = boneArray[par]
-- boneArray*.realignBoneToChild() -- poo dont work, grr

if buildMsh == true do (
num_elements = smdArray.triangles.material.count
mat = multimaterial numsubs:num_elements
mat.numsubs = num_elements
meditMaterials[1] = mat
for i = 1 to num_elements do (
basename = getFilenameFile smdArray.triangles.material*

submat = mat.materialList*
submat.diffuseMap = Bitmaptexture fileName:smdArray.triangles.material*
submat.name = basename

faceArray = #()
vertArray = smdArray.triangles.geometry*.position
normArray = smdArray.triangles.geometry*.normal
uvwArray = smdArray.triangles.geometry*.texture
vert_count  = smdArray.triangles.geometry*.position.count
face_count = smdArray.triangles.geometry*.faces.count/3

cnt = 0
for x = 1 to face_count do (
fa = smdArray.triangles.geometry*.faces[(cnt+1)]
fb = smdArray.triangles.geometry*.faces[(cnt+2)]
fc = smdArray.triangles.geometry*.faces[(cnt+3)]
faceArray[x]=[fa,fb,fc];cnt += 3

msh = mesh vertices:vertArray faces:faceArray-- materialIDs:matidArray
msh.numTVerts = vert_count
buildTVFaces msh
msh.displayByLayer = false
msh.backfacecull = on
msh.wirecolor = random (color 0 0 0) (color 255 255 255)
msh.material = submat
for j = 1 to uvwArray.count do setTVert msh j uvwArray[j]
for j = 1 to faceArray.count do setTVFace msh j faceArray[j]
for j = 1 to normArray.count do setNormal msh j normArray[j]

if buildSkn == true do(
skinMod = skin ()
addModifier msh skinMod
max modify mode
select msh
for x = 1 to bone_count do (
if x!=bone_count
then (skinOps.addbone skinMod boneArray[x] 0)
else (skinOps.addbone skinMod boneArray[x] 1)
boneIDMap = #()
for x = 1 to bone_count do (
boneNameIdx = findItem smdArray.nodes.name (skinOps.GetBoneName skinMod x 0)
if boneNameIdx==0 do (boneNameIdx=1);boneIDMap[x]=boneNameIdx
modPanel.setCurrentObject skinMod
for x = 1 to vert_count do (
bi = smdArray.triangles.geometry*.boneid[x]
bw = smdArray.triangles.geometry*.weight[x]
for j = 1 to smdArray.triangles.geometry*.count[x] do (
bi[j]= findItem boneIDMap bi[j]

skinOps.ReplaceVertexWeights skinMod x bi bw
print ""



)else(messagebox "Error
SMD Not Compatible with this Script")
Print "Done!"
MemStreamMgr.close f
) else (Print "Aborted.")

I can tell why. I’m currently using the 2012 version. I was stuck on whether I should get the 2013 vs 2012. Boy was I wrong on both terms.

I use 3dsmax8, and anything after 8 is bugged

yes to the people who disagree that max past 11 are good, I’ve tried all versions and 12/13 have the most errors on release and problems with plug ins, its not a opinion thats just facts, you can get hot fixes but whats the point when max 2008 to 11 can accomplish the same thing on release with zero errors?

Thank you mario for the script It really is helpful if your stuck using higher versions of max and the other plug-in isnt supported.

like I said I use max8, which is from 2006. its the most stable version out there :smiley:

you guys think your missing out not upgrading to 2013. hell downgrade to max8 and feel the oldskool power!

been using 09 for years, suits me the best, but I only use max for rigging and importing, XSI for modeling.
infact max 12 has broken skinning, sure is a nice feature to break :confused:

tried out the script, works great, one thing I love is the fact that it doesnt weld everything together like the plug in, very useful. thanks again.

You know you can fix the broken skinning with a fix released a loooong time ago.

Or some people are stuck with 2013 because they only have a license for 2013.

Mario_Kart64n … people have been asking me to do this for Wall Worm for the last year… I’d like to add this to Wall Worm with your permission.

Also, feel free to contact me directly if you are interested in updating the Wall Worm SMD Exporter so that it properly supports CAT and Biped. There is some set of logic in my exporter that fails with CAT/Biped systems and I just don’t have time to get to the bottom of it.

Thanks to MarioKart for permission to include the SMD importer into Wall Worm. I’ve updated the script slightly and packaged it into Wall Worm. See the changelog.

After loading the update, you’ll be able to find it in the WW menu under Wall Worm > Wall Worm Importers > SMD Importer .

So much for getting 3dsmax 08-09, I’m stuck with versions 10-13.