LastRenderRamPlay - Tutorial & Script |
MAXScript Release 0.1.1 Tutorial and Source for 3ds max 5 (05/02/2003)Code by Borislav PetrovOnline Tutorial Text Last Edited on 05/02/2003, 3:00am CET |
| SHORT DESCRIPTION |
| LastRenderRamPlay is a
rather simple macroScript which will load the output
file defined in the Renderer dialog in the RAMplayer for review. |
| I WANT TO DOWNLOAD THE READY SCRIPT AND SKIP THE TUTORIAL... |
| .Click here to get the final script.. |
| WHAT DO WE WANT TO ACHIEVE? |
|
| 1. DEFINING THE MACROSCRIPT |
| macroScript
LastRenderRAMplay
category:"Bobo_s Tools" tooltip:"Load Render Output To RAM Player" ( --The body of the macroScript will be placed here... ) |
| A macroScript defines a
so-called ActionItem in 3ds max lingo. ActionItems are all the tools you can find in the Customize UI dialog. They can be dragged to a toolbar, placed in a Menu or QuadMenu or can be assigned to keyboard shortcuts. ActionItems (and macroScripts) were introduced with 3ds max R3 in 1999. |
| A macroScript starts
with the constructor keyword macroScript followed by
the internal name of the ActionItem. This name will appear on the toolbar unless you specify a buttontext parameter to replace it. |
| The category property defines where in the Customize UI dialog the ActionItem will be located. |
| The tooltip property defines the description text to be displayed in the Customize UI dialog and when the mouse rolls over the ActionItem's button. |
| Inside the () brackets, we will enter the actual body of the script. |
| NOTE
that in reality, the developer usually writes the body of the script first
and then encapsulates it in a macroScript when the code works. It is easier to test the script by just evaluating the body without the need to press a toolbar button. |
| 2. PREPARATION WORKS |
| renderSceneDialog.commit()
if rendOutputFilename != "" then ( rend_path = getFileNamePath rendOutputFilename rend_name = getFileNameFile rendOutputFilename rend_type = getFileNameType rendOutputFilename is_avi = matchPattern rend_type pattern:".avi" ignoreCase:true is_mov = matchPattern rend_type pattern:".mov" ignoreCase:true is_flc = matchPattern rend_type pattern:".flc" ignoreCase:true ) |
| In this code block, we will do
some preparations before we can decide what type of output we have to deal
with. We will make sure the output file name is valid and updated. Then we will collect the different parts of the file name (path, name and extension) and check the file type by the extension. |
| renderSceneDialog.commit() |
| This line updates the Render
Scene Dialog in case it is open.
NOTE that this method has been implemented in VIZ 4 and 3ds max 5 but is not available in 3ds max 4. Here is a case this would be useful:
|
| if rendOutputFilename != "" then |
| This line should make sure
that the output file name set in the Render Scene Dialog is not empty. The rest of the utility code will be execured only if the system global variable rendOutputFilename contains some string. |
| rend_path
= getFileNamePath rendOutputFilename
rend_name = getFileNameFile rendOutputFilename rend_type = getFileNameType rendOutputFilename |
| These 3 lines split the output
file name to path, base name and extension. The results will be stored in 3 user variables. These variables are implicitly local, this means that they are valid and seen by the code only inside of this macroScript even without typing "local" in front of them! |
| is_avi
= matchPattern rend_type pattern:".avi" ignoreCase:true
is_mov = matchPattern rend_type pattern:".mov" ignoreCase:true is_flc = matchPattern rend_type pattern:".flc" ignoreCase:true |
| These 3 lines will check
whether the extension of the output file is one of the known multiframe
formats - Video For Windows AVI, QuickTime MOV or Autodesk FLC Using the matchPattern function on the variable containing the file extension, we compare with the specified pattern string while ignoring the case. matchPattern returns true
when the supplied string matches the pattern string, or false when it
doesn't. |
| 3. LOADING A MULTIFRAME FILE FORMAT |
| if
is_avi or is_mov or is_flc then
( try ( ramPlayer rendOutputFilename "" format "Opening RAM Player for Movie [%]\n" rendOutputFilename )catch() )
|
| In case the output file name points at an AVI, MOV or FLC file, we will try to load this file in the 3ds max RAMplayer. . |
| Using if and
logical or, we tell the utility to only execute the code
inside the () brackets when any of the 3 variables is true. In other words, if the matchPattern has successfully detected an AVI, MOV or an FLC in the code block before, the following code will be executed. |
| MAXScript provides access to
the RAMplayer by calling the ramPlayer function with two
string parameters - the movie to be loaded in the left and right channel. Since we want only one movie, we set the second parameter to empty string "" which means "do nothing with this channel". |
| After opening the RAMplayer,
we output a single line of text to the MAXScript Listener to tell the user
what happened. The format function expects a formatting string which can contain control characters like \n (New Line), \t (Tabulator) etc. The control symbol % means an occurrence of a parameter inside the format string. Each % character will be replaced with the next parameter specified after the formatting string. There must be as many parameters as % characters. The parameter will be converted to string automatically, there is no need to call as string for numeric values! In our case, a text like "Opening
RAM Player for Movie [c:/3dsmax5/images/myanimation.avi]"
will be printed to the Listener, |
| The complete code is
encapsulated in a try()catch() context which is there to
catch any errors that might occur. This is just a general precaution to avoid unexpected crashes in case the file name is not valid after all. |
| 4. LOADING A FRAME SEQUENCE AS A SINGLE ANIMATION FILE |
|
else ( try ( check_for_digits = substring rend_name (rend_name.count-3) 4 if classof (execute check_for_digits) == Integer then rend_name = substring rend_name 1 (rend_name.count-4) )catch() image_files = getFiles (rend_path+ rend_name +"*"+rend_type) if image_files.count > 0 then ( ram_player_ifl = ((getDir #image)+ "/LastRender.ifl") temp_ifl = createFile ram_player_ifl sort image_files for f in image_files do format "%\n" f to:temp_ifl close temp_ifl ramPlayer ram_player_ifl "" format "Opening RAM Player for Sequence [%]\n" rendOutputFilename ) ) |
| This is the code executed when
none of the multiframe movie formats has been detected. In this case, we have to assume we are dealing with a sequence of single frames. Now we will have to detect all frames from this sequence, generate an IFL listing these files, and load the IFL in the RAMplayer. |
| try
( check_for_digits = substring rend_name (rend_name.count-3) 4 if classof (execute check_for_digits) == Integer then rend_name = substring rend_name 1 (rend_name.count-4) )catch() |
| There are two
possible cases
for single frame file names - the base file name is specified in the
output, or a single frame name including 4 digits is specified. In the latter case, we will have to remove the digits to get the actual base name we need to look for. The code above takes the last 4 characters of the base file name using the substring function, starting with the length of the name minus 3. Then it tries to convert this substring to a value by calling execute. If the four characters are a number inside a string, like "1234" or "0001", the result will be a number value 1234 resp. 1. Checking the class using classof of
the result tells us whether the characters are a number or not. The whole code is inside a
try()catch() context to avoid crashes, for example in the case the
length of the base file name is less than 4 characters. |
| image_files
= getFiles (rend_path+ rend_name +"*"+rend_type)
if image_files.count > 0 then ( ram_player_ifl = ((getDir #image)+ "/LastRender.ifl") temp_ifl = createFile ram_player_ifl |
| Now we get all
files at the path that start with the base name and end with the extension
of the render output file. The getFiles function expects a file name pattern where "*" stands for any number of characters. The result is a list of all files matching the pattern. In case the number of returned files is higher than 0, we will generate a new IFL file and load it in the RAMplayer. Next we get the Images path defined in the
3ds max path configuration and add the fixed name "LastRender.ifl" |
|
sort image_files for f in image_files do format "%\n" f to:temp_ifl close temp_ifl ramPlayer ram_player_ifl "" format "Opening RAM Player for Sequence [%]\n" rendOutputFilename ) |
| The file list
will be originally in the creation order as returned by the OS. To get a correct IFL, we will need to sort the files in ascending order. Since they have the same base name, they will be sorted by their four-digit number. To sort the files, we call the sort function with the file list as parameter. Then we use a for loop to go through all files in the list and output them to the temp_ifl FileStream value using the format function. When we are ready with the output, we have to close the FileStream so it can be accessed. Now we can open this new IFL file in the RAMplayer just like we did with AVI, MOV and FLC files. Finally, we will report the result to the user by printing a message to the Listener. |
| COMPLETE SOURCE: |
| macroScript
LastRenderRAMplay
category:"Bobo_s Tools" tooltip:"Load Render Output To RAM Player" ( renderSceneDialog.commit() if rendOutputFilename != "" then ( rend_path = getFileNamePath rendOutputFilename rend_name = getFileNameFile rendOutputFilename rend_type = getFileNameType rendOutputFilename is_avi = matchPattern rend_type pattern:".avi" ignoreCase:true is_mov = matchPattern rend_type pattern:".mov" ignoreCase:true is_flc = matchPattern rend_type pattern:".flc" ignoreCase:true if is_avi or is_mov or is_flc then ( try ( ramPlayer rendOutputFilename "" format "Opening RAM Player for Movie [%]\n" rendOutputFilename )catch() ) else ( try ( check_for_digits = substring rend_name (rend_name.count-3) 4 if classof (execute check_for_digits) == Integer then rend_name = substring rend_name 1 (rend_name.count-4) )catch() image_files = getFiles (rend_path+ rend_name +"*"+rend_type) if image_files.count > 0 then ( ram_player_ifl = ((getDir #image)+ "/LastRender.ifl") temp_ifl = createFile ram_player_ifl sort image_files for f in image_files do format "%\n" f to:temp_ifl close temp_ifl ramPlayer ram_player_ifl "" format "Opening RAM Player for Sequence [%]\n" rendOutputFilename ) ) ) )
|