Home Technical Talk

Max script batch process question

Having issues with a batch process that would remove the modifier "MultiRes" from the stack for a group of .max files. I'm not quite sure which part of it isn't working but I have a feeling its the actual modifier removal part of the process. Any help would be well appreciated.

macroScript ExportAllAnimation category:"WIT" tooltip:"ExportAllAnimation"

(

global W_ExportAllAnimation, RO_ExportAllAnimation


rollout RO_ExportAllAnimation "Batch Export DSQ" width:304 height:80

(

edittext edtSourceDirectory "" pos:[88,8] width:184 height:16

label lbl1 "Source directory" pos:[8,8] width:80 height:16

button ChooseSourceDir ".." pos:[272,8] width:16 height:16

edittext edtExportDirectory "" pos:[88,32] width:184 height:16

label lbl2 "Export directory" pos:[8,32] width:80 height:16

button ChooseExportDirectory ".." pos:[272,32] width:16 height:16

button btnExport "Export" pos:[8,56] width:280 height:16


on ChooseSourceDir pressed do

(

source_dir = getSavePath()

edtSourceDirectory.text = (source_dir as string)

)

on ChooseExportDirectory pressed do

(

export_dir = getSavePath()

edtExportDirectory.text = (export_dir as string)

)

on btnExport pressed do

(

maxfiles = getFiles (edtSourceDirectory.text + "\\*.max")

if edtSourceDirectory.text == "" or edtSourceDirectory.text == "undefined" then

(

messagebox "No source directory."

return 0

)

exportdir = (edtExportDirectory.text + "\\")

if edtExportDirectory.text == "" or edtExportDirectory.text == "undefined" then

(

exportdir = (edtSourceDirectory.text + "\\")

)

for fl in maxfiles do

(

loadMaxFile fl

select obj

deleteModifier obj MultiRes

fname = exportdir + getFilenameFile(fl) + ".max"

exportFile fname

)

)

)


if W_ExportAllAnimation != undefined do

(

try( closeRolloutFloater W_ExportAllAnimation )

catch()

)


W_ExportAllAnimation = newRolloutFloater "ExportAllAnimation" 310 116
addRollout RO_ExportAllAnimation W_ExportAllAnimation

Replies

  • Rob Galanakis
    deleteModifier expects an index (1, 2, 3, etc.), or an instance of a modifier. So, you can change:
    deleteModifier obj MultiRes
    to
    deleteModifier obj obj.modifiers[#Multires]

    However, I don't see where you define 'obj', so the script probably still won't work (it will give you an error like, "no 'select' function for undefined", and will crash on the "select obj" line). If you need further help, just ask.
  • KikiAlex
    fn Cleen_Multi =
    (
    	for i in objects do
    	(
    		if i.modifiers.Count != 0 do
    		(
    			for m in i.modifiers do
    			(
    				if ((classof m) == MultiRes) do
    				(
    					deleteModifier i m
    				)
    			)
    		)
    	)
    )
    
    fn Cleen_MultiRes =
    (
    	for p = 1 to 20 do
    	(
    		Cleen_Multi()
    	)
    )
    
    
    Cleen_MultiRes()
    

    This is how a clean MultiRes function should look like
    I iterate 20 times trough the clean function because in max 9+ sometimes it does not execute
  • Rob Galanakis
    Your code can be simplified to:
    fn Cleen_MultiRes =
    (
    	for o in objects do
    	(
    		while o.modifiers[#Multires] != undefined do
    			deleteModifier o o.modifiers[#Multires]
    	)
    )
    
    Cleen_MultiRes()
    

    That will delete all Multires on all objects in your scene.
  • NeoProfZ
    Thanks much guys, I'll go ahead and give some of this stuff a shot.
  • NeoProfZ
    Much thanks with the help on the MultiRes removal. Looks like its working now.

    However, the script still only runs through a single source directory. Do you guys know if Maxscript could handle a more thorough batch process that includes subdirectories as well?
  • Mark Dygert
    Unfortunately I don't think there is a "include/exclude" sub directories command as part of getsavepath() ?

    Are any part of the names of the sub directories known?
    You could probably patch something together using "getDirectories" and the "PathConfig Struct"

    I'm sure Rob can blow your socks off with a way more awesome reply if not outright write a function for you....
  • NeoProfZ
    Ok, so here's where I am right now. I found a piece of code that looks like it'll recursively go through the existing directory structure of a given folder and collect up all the max files. I'm trying to integrate it with the multires removal code but it just ends up falling apart.
    thePath = getSavePath() --get a path dialog to specify the path
    
    pattern = "*.max"
    
    
    --if thePath != undefined do --if the user did not cancel
    
    --(
    
    --theFiles = getFiles (thePath+"*.max") --collect all max files in the dir.
    
    --for f in theFiles do --go through all of them
    
    --(
    
    
    fn getFilesRecursive root pattern = 
    ( 
    dir_array = GetDirectories (ThePath+"/*") 
    for d in dir_array do 
    join dir_array (GetDirectories (d+"/*")) 
    TheFiles = #() 
    for f in dir_array do 
    join TheFiles (getFiles (f + pattern)) 
    TheFiles 
    ) 
    
    --getFilesRecursive ThePath pattern
    
    for m in theFiles do 
    ---------------------------------------------------------------------------
    
    loadMaxFile m --load the next file
    
     
    
    fn Cleen_MultiRes =
    (
        for o in objects do
        (
            while o.modifiers[#MultiRes] != undefined do
                deleteModifier o o.modifiers[#MultiRes]
        )
    )
    
    Cleen_MultiRes()
    
     
    
    saveMaxFile m --save the file back to disk
    
    )--end f loop
    
    -------------------------------------------------------
    
    resetMaxFile #noPrompt --at the end, you can reset
    
    )--end if
    
    
    While I'm at it (and since I'm still really new to max scripting) is there a better environment to do this sort of thing than wordpad? ultraedit comes to mind but I just want a way to debug this code without so much guess-work.


    edit: Forgot to mention, it'll go through several files before returning an error of "-- Unable to convert: Undefined to type: String". It looks like its not removing the multires modifier either.
  • Rob Galanakis
    Since I won't have time to write up a proper response for a little while, check out Paul Neale's Batch It Max: http://www.paulneale.com/scripts/batchItMax/batchItMax.htm
  • Mark Dygert
    I'm not sure I can test what you have going but lets see if I can help you structure things so they're a little more manageable and readable.
    (--Start of Script
    -------------------------------------------------
    --DECLARATIONS--
    -------------------------------------------------
    thePath = getSavePath() --get a path dialog to specify the path
    pattern = "*.max"
    
    -------------------------------------------------
    --FUNCTIONS--
    -------------------------------------------------
    fn getFilesRecursive root pattern = 
        (--Get sub directories?
            dir_array = GetDirectories (ThePath+"/*") 
            for d in dir_array do 
                join dir_array (GetDirectories (d+"/*")) 
                TheFiles = #() 
            for f in dir_array do 
                join TheFiles (getFiles (f + pattern)) 
                TheFiles 
        ) 
    
    fn Clean_MultiRes =
        (--Delete MultiRes Modifier
            for o in objects do
            (
                while o.modifiers[#MultiRes] != undefined do
                    deleteModifier o o.modifiers[#MultiRes]
            )
        )
    
    -------------------------------------------------
    --MEAT--
    -------------------------------------------------
    if thePath != undefined do
        (--collect all max files in the dir.
            theFiles = getFiles (thePath+"*.max") 
            for f in theFiles do --go through all of them
                (
                    getFilesRecursive ThePath pattern
                )
        )
            
    for m in theFiles do 
        (--Load, Clean & Save
            loadMaxFile m --load the next file
            Clean_MultiRes() --Call clean function
            saveMaxFile m --save the file back to disk
        )
    
    resetMaxFile #noPrompt --at the end, you can reset
    
    )--end of script
    
    (This is more cleaning up the script and offering organizational suggestions then it is actually making the script work...)

    Declarations, Functions and Meat works best for me but not always, there are times I'll write functions in other places but in general I try to keep each piece in its section. As well as adhering to some kind of indenting rule(s).

    Also 3dsmax2008-09 have a pretty good Maxscript editor. Main Menu > MAXScript > MAXScript Editor.
    If your on older versions Notepad++ is pretty good.
  • NeoProfZ
    I did get it working, but the fact that there are missing map files is making it still click intensive. (from the missing map file dialog)

    I'm trying to set

    logsystem.quietmode or setquietmode() , but I don't know why they don't work. any idea why max 5 would have an issue with these, or how they are meant to be used?
  • Mark Dygert
    humm that will cause some issues. I'm not sure switching to quitemode will get you past the problem. You might have better luck updating the bitmap paths. Might come in handy to update automate the path update anyway. I guess if you have to set it back you can temporarily update them and set it back...

    http://www.scriptspot.com/3ds-max/relink-bitmaps
    This relink bitmap script might have some good pointers if you decide to go that route.
  • NeoProfZ
    Thanks vig,

    but this is over 2000 files, , we just need to strip the multires out of them. Many of the textures don't even exist anymore. It loops and gets rid of the multires, but someone has to sit there and click "continue" for each file.
  • Mark Dygert
    Ahh in that case, it gets difficult. The reason I don't think it will work is because quite mode is very specific to what triggers the error. In this case I don't think quitemode has an option for export (you're exorting right?), but the render "missingExtFilesAction:" might work, but I doubt it because its not triggered at render time but exporting, which means it might just be ignored...
    Quiet Mode
    missingExtFilesAction: <actions>
    Actions to take on Missing External Files, where <actions> is: #logmsg, #logToFile, #abort, #default and/or an integer, or an array of one or more of those items.
    I think you'll run into more trouble because the #default action option was added into 3dsmax8 and higher. So theres a slim chance it would work in 8 or higher and hardly a chance at all to work in 5. But the maxscript help doc for 5 might have a work around... maybe...

    Do you even need to worry about the map paths? Maybe just applying a standard material to the object and clear the material editor. In which case you might want to take a peak at this material cleaner script I wrote for some useful functions.
    macroScript MatClean
    Category:"HITools"
    toolTip:"Material Cleaner"
    buttontext:"MatClean"
    (--Used to clean and prep scenes for animation (I not need ur puny textors fumans!)
        rollout MatClean "MatClean" width:128 height:136
        (--Rollout and script
            button btn_RstSM "Clean Objects" pos:[8,32] width:112 height:24 toolTip:"Removes materials from selected objects, or from all objects if nothing is selected"
            button btn_WrClr "Wire Color" pos:[8,56] width:72 height:24 toolTip:"Sets selected objects to the same custom wire color or all objects if nothing is selected (materials do not change)"
            button btn_RstME "Clean Editor" pos:[8,8] width:112 height:24 toolTip:"Resets all material editor slots (does not pay attention to selection)"
            button btn_Mat1WrClr "Mat1 + Wire Color" pos:[8,104] width:112 height:24 toolTip:"Applies Mat Slot 1 to selected objects or for all objects if nothing is selected (Sets the wire color to the current custom color)"
            button btn_RndmWrClr "Random Wire Color" pos:[8,80] width:112 height:24 toolTip:"Applies random wire colors to selected objects, or to all objects if nothing is selected. (materials do not change)"
            colorPicker cp1 "" pos:[72,56] width:48 height:24 color:(color 0 0 0) title:"Choose a color"
    
    --Functions
        fn clear_all_meditSlots =
                (--Resets all material samples in the material editor to default standard.
                    macros.run "Medit Tools" "clear_medit_slots"
                )
            
        fn kill_materials =
                (--Removed all materials from the scene (checks and operates on selection only if something is selected)
                    if $ == Undefined then 
                        (
                            max select all
                            $.material = noMaterial()
                        )
                    else 
                        (
                            $.material = noMaterial()
                        )
                    
                )
            
        fn dull_materials =
                (--Sets all objects to the material material slot 1, and changes the wire color to black
                    clear_all_meditSlots()
                    kill_materials()
                )
                
        fn wire_color =
                (--sets the wire color on all objects to the specified color
                    if $ == Undefined then
                        (
                            max select all
                            $.wirecolor = cp1.color
                        )
                    else
                        (                    
                            $.wirecolor = cp1.color
                        )
                    )        
                
        --Button Actions
        on btn_RstSM pressed do
                (    
                    kill_materials()
                )
    
        on btn_WrClr pressed do
                (
                    wire_color()
                )
    
        on btn_RstME pressed do
                (
                    macros.run "Medit Tools" "clear_medit_slots"
                )
                
        on btn_Mat1WrClr pressed do
                
                if $ == undefined then
                    (
                        dull_materials()
                        wire_color()
                        max select all
                        $.material = meditMaterials[1]
                    )
                else 
                    (
                        dull_materials()
                        wire_color()
                        $.material = meditMaterials[1]
                    )
                    
        on btn_RndmWrClr pressed do
            if $ == undefined then 
                (
                    for obj in objects do
                    obj.wirecolor = color (random 0 255) (random 0 255) (random 0 255)
                    clearSelection()
                )
            else
                (
                    for obj in selection do
                    obj.wirecolor = color (random 0 255) (random 0 255) (random 0 255)
                    clearSelection()
                )
    
        )
        (--U makem pretty window now k!?
            createdialog MatClean
        )
    )
    
  • Rob Galanakis
    We had a similar problem, but because Max was coming up with memory problems. I'll post the solution later tonight, requires some explanation.
  • Rob Galanakis
    http://tech-artists.org/forum/showthread.php?p=1831#post1831

    There you go. That should get you over your design hurdles and technical workarounds- the rest of the work is coming up with the actual code, but it is not difficult and it will be a good learning experience.
  • Mark Dygert
    Hey, that's slick!
Sign In or Register to comment.