Archive for the ‘Tech’ Category

Maxscript image file handling

When you are working with larger numbers of files in folders you want to be clever about getting them. I used to have a lots of different functions all with their own identical or very similar file processing. Often I’d hardcode in extensions (bad) and sometimes I’d want to search for files with a keyword.

Old:

fn texturehandling texturefolder= (

  image_diff_files = #()
  image_type = ".tga"

  -- Get all the TGA diffuse files
  diff_files = textureFolder  + "*diff*" + image_type
  thefiles = getfiles diff_files	

  for f in thefiles do
  (
    append image_diff_files (uppercase(getfilenamefile f))
  )

  image_diff_files -- return this
)

It works, but it has several issues. It assumes TGA files only, and it’s looking for filenames with “diff” as part of the filename. What if I want to look for specular maps with arbitrary names saved at BMP?

Define this in some common script header (so that it’s easily to find and extend):

textureTypes = #("*.tga","*.png","*.bmp","*.tif")

Then have this useful function:

-- Function to return an array of supported image files in a folder
-- Takes an optional search string
fn returnImageFiles inputFolder optionalFilter:"" = (
  theImageFiles = #()

  if optionalfilter == unsupplied then optionalfilter = ""

  search_files = inputFolder + optionalfilter

  -- Get array of image files in a given folder
  for ft = 1 to textureTypes.count do
  (
    tempfilelist = getfiles (search_files + textureTypes[ft])
    join theImageFiles tempfilelist
  )
  theImageFiles -- return this.
)

Then call it with this:

image_all_files = returnImageFiles textureFolder optionalFilter:""
image_diff_files = returnImageFiles textureFolder optionalFilter:"*diff*"

There are a few minor issues that I should clean up

  • I could have used a better name than optionalFilter, but it does the job.
  • I don’t check that the texture folder name ends with a slash
  • It doesn’t handle recursive folders

By the way, optional parameters in maxscript are very useful, though a little tricky at first.

Everything you need to know about Normal Mapping

Eric Chadwick has been working very hard on the Polycount Wiki, and has just released a massive amount of information about Normal Mapping that pretty much covers all the tech you need to know.

Maxscript wiring function for roll/twist bones

When working with lots of rigs you want to automate as much as possible, especially as they become more complex. I’m working with Character Studio Biped as a base, and then adding custom roll/twist bones on top of this, so it made sense to take the time out to develop a script that could connect up several rollbones in a rig so that I’d get the same results every time. The first and most obvious thing to do was to create these extra bones using script, so I wrote a function called BuildNewBone that builds a new bone between two points and links it to a parent.

The next step was to connect these new bones to the Biped system so that they would behave in the way I wanted, rotating based on the underlying rig. Biped is a relativley closed system, so to query the rotation of Biped bones you need to expose the internal values using expose transform helpers. I set these up via script, so that as well as always having the same name I can position them on screen and even set their colour for easy identification.

Wiring rollbones in max uses the paramwire.connect command, and this takes three variables: the driving or controller bone (in the case of Biped I use the aforementioned Expose Transform Helper as the driver), the bone you want to affect, and a control expression which controls the amount of twisting.

With twist bones like the forearm twist you will most likely want to affect them on the X axis only so that as the hand rotates the rollbone will twist around the forearm bone. Bones like a neck roll however will roll in all three axis. Also in the case of the twist bones like the upper arm twist bone which is parented to the clavicle then you require it to follow the driver bone (in this case the upper arm) 100% in the Y and Z axis.

What I was finding was that I was calling the paramwire command several dozen times to link up an entire skeleton, sometimes calling it 3 times in a row with the same rollbones just to specify a different axis each time.

To makes thing easier for myself, I ended up writing a function to wire rollbones where I could simplify this to a single call:

-- Wire up a Local rotation rollbone given a bone to roll, a controller object and a roll amount per axis.
-- If any of x, y or z are 0, skip the wiring for that axis (inherits parent rotation)
fn wireRoll theRollbone theDriver xr yr zr = (
if xr != 0 then
(
controlExp = "Local_Euler_X*" + (xr as string)
paramWire.connect theDriver.baseObject[#Local_Euler_X] theRollBone.rotation.controller[#X_Rotation] controlexp
)
if yr != 0 then
(
controlExp = "Local_Euler_Y*" + (yr as string)
paramWire.connect theDriver.baseObject[#Local_Euler_Y] theRollBone.rotation.controller[#Y_Rotation] controlexp
)
if zr != 0 then
(
controlExp = "Local_Euler_Z*" + (zr as string)
paramWire.connect theDriver.baseObject[#Local_Euler_Z] theRollBone.rotation.controller[#Z_Rotation] controlexp
)
)

So with a calf roll that is parented to the calf bone, I want it to make it rotate 50% in the X axis as the foot rotates in the X axis:

wireRoll $'L Calf Roll' $eTM_LFoot 0.5 0 0

The EEE PC

I’ve had the EEE PC for a few weeks now, and I’m writing this in the pub (no wifi signal so I can’t browse the net).

It’s an exceptional little machine. It’s tiny, dinky even – which is both it’s greatest strength and weakness. The keyboard is very small, but more on that later. It’s so light that I hardly notice it in my bag, whereas my old Toshiba was like carrying round a couple of bricks.

Although the screen is small (800 x 480), it’s fine for most purposes (I’d bought it purely as a thin client/dumb terminal to connect to the internet. Of course this pub has no wifi). By most purposes, I mean using the internet, and that means Firefox. By running Firefox in full screen it’s perfectly usable.

If I wanted a serious laptop, I’d have bought a serious laptop, however I made the conscious decision to buy the EEE PC because it wasn’t an expensive, powerful computer. Although I’m a computer artist, if I wanted to do any art I’d not want to work on ANY laptop, especially since I have a 24 inch monitor on my powerful iMac. Over the last year I’ve moved most of my computing software to Google – email, RSS reading, document editing, calendar et al., so all a I wanted was Firefox, a screen and a keyboard.

Since there is no wifi here, I’ve switched off the Wifi mode (Function key+F2), which seems to make a huge difference to the battery life – indeed the battery life is my second biggest issue after the keyboard size. I get about 2.5 hours withWiFi enabled, and just over 3 hours with it disabled.

The keyboard is what takes the most getting used to. It’s not ultra tiny, and it’s certainly much more usable than the soft keyboard on my iPod touch. It’s comparable in size to the iGo Stowaway Bluetooth keyboard, and to be perfectly honest, after 2 to 3 minutes of typing each time I use it my hands adjust. It’s similar to the switch I had to make when I switched to playing guitar after playing bass for a few hours. The biggest bugbear is actually the arrow keys, which are placed so close to the right shift that I continually hit the up arrow when I try to use shift. Again, after a few minutes this becomes less of an issue.

I’m writing this is Google Docs – but as I mentioned I have no Wi-Fi here. Thankfully Google have brought their Google Gears technology to Docs, which means I can create new documents and edit existing ones offline. When I get home (or find any network signal), the documents will sync again. Google Reader also works fantastically well with no network thanks to Gears. I’d been away for a few days, so I’d built up 600-700 unread feed items. Google Gears downloaded all these and I was then able to read them offline.

If only Google mail had an offline mode…

My EEE PC is finally here!

EEE PC green

I’ll get around to installing a load of rubbish on it, swearing at Linux, then reverting it back to a base install with 1 week*.

*Edit: 2 days.

Update on the maxscript controllers

A small post to say that I managed to write some fairy nice code that links my joysticks to bones, allowing me to specify angle limits. It all works as planned in my tests at home, but breaks on certain real world hierarchies.

This is something I need to figure out before I post a breakdown of it, but for those interested, the code is available here:

http://forums.cgsociety.org/showthread.php?f=98&t=563367

Where’s the Google Address book?

Google has some of the greatest services around, though I wish they’d bought Flickr instead of what they are doing with Picasa web albums.

I’m also surprised that they are missing a Google Address Manager too – not for email addresses, but for real addresses. In Google Calendar, I’ve created a Birthdays calendar. I’ve shared that with several family members so we can all add and keep tracks of family birthdays. Imagine the same features in an addressbook, available from and computer or handheld device. Want to send a postcard to Auty Mable while you are in Tokyo?

Group addresses as Public, Private, Friends, Family.
Create new groups, and assign viewing and editing privileges to other google users.

Scripting streamlines your 3d workflow

I think a lot of 3D artists overlook the power that scripting with their 3D application provides them.

“I’m an artist – so why do I care about scripting?” I hear you cry. Scripts are great for automating repetitive tasks, and you don’t need to be a superb programmer to take advantage of them. That being said, if you understand a few of the basic aspects of programming like loops and variables then scripting becomes even more powerful.

I predominantly use 3d Studio Max at work (along with Silo for modelling), and I’ve found that maxscript is relatively easy to learn. I’m not a Maya user, but I understand that it’s scripting language, Mel, is fantastic.

How about some examples of where scripting is useful?

I know that all the characters I build in my current project have the same bones, so rather than creating them from scratch each time, I have a script that loads them from an external file. After the bones are loaded, it creates 2 selection sets – 1 for all the bones (but no nubs), and another set with a drastically reduced bone list for the LOD model (no fingers, toes, helper bones or face bones for example). The script finds all the components that need a skin modifier applied, applies it and assigns the correct bone set (thats the benefit of a sensible naming convention for you).

I like all my renders to look the same, so I’ve written a render script – it loads a scene with my preferred lights, floor and camera, sets the background colour of the scene to be neutral and changes the lighting tint. It selects the camera, sets the output size, grabs the name of the model from the max filename so that it can name the image, then renders and saves the image to the same folder as the model. It also renders Front, Back and 3/4 views.

Sound useful? How about a batch script? It loads a list of models in turn and executes another script. So if I need to render out all my work, I just point my batch script at my models and tell it to execute my render script – then I can bugger off for a coffee, or leave it running overnight.

Setting up all your shaders? Press a button and maxscript converts all my max materials to shaders, with all the shader values set to our correct defaults.

So where do you start?
The best thing to do is to pick a simple task and try to script it. I learned to script not by doing abstract examples, but by just grabbing the bull by the horns and trying to write something useful. But where can I START? The first step?

3DSMax has a tool called the Maxscript Listener, which records almost everything you do in max. This is usually my first step – I open the listener, then I perform the entire task manually. The listener records all the steps (usually, sometimes the listener has selective hearing), and I can simply copy and paste them to a new script document where I can then edit until I’m content.

It’s worth mentioning that not just 3d applications that can have their workflow improved by scripts – Photoshop is a good example of a 2d package that allows you to create actions to automate repetitive actions – such as resizing and sharpening an entire folder of textures.

Resources:
These are a few things I could think of to help you along the way.

  • The Maxscript help files that come with max are very, very good. I’ve gotten most of my help from these.
  • Search Google for ‘Learn Maxscript
  • Scriptspot has got thousands of 3DS Max scripts online – there is a good chance that you get something to suit your needs, or tear them apart to learn how they work.