Tuesday, October 18, 2011

Trip Success! + Overdue Post Mortem

Today's art borrowed from the excellent http://soraka.blogspot.com/

Despite a flat tire in the middle of nowhere and very little sleep, I had a wonderful time in Florida last week! Many thanks to our hosts at Ringling College of Art and Design. We had a great turn out for both the presentation and Q&A sessions, and the student work was really impressive. Best of luck to the Seniors with their thesis games. Hopefully we will return in the Spring for some more presentations and portfolio reviews.

Whenever asked, I always advise aspiring tech artists to blog about problems they've solved. I thought it might be finally time that I follow my own advice. What follows is a walk through of the script I wrote as a test while in my last semester at Ringling. This is what got me into Riot as an intern! I'm going to make this walk-through very high-level, trying to focus on steps I'd approach when writing any script. Let's do this.

First off, here is a video that I made back when I first finished the tool demoing the functionality (might need to re-size window to view). Check out that sweet Maya 2009 GUI! I will describe the problem and my thought process below, so don't worry if you don't want to spend fifteen minutes watching through the whole thing. Secondly, here is the script.

The goal of the script was to mimic some XSI weighting functionality that the customer's version of Maya (read: Maya 8) did not have. The problem as described was, "be able to select a set of verts and joints and intuitively weight those points to those joints, either evenly or by distance." This has obvious uses, such as when one has many noodle-y appendages near one another and does not want to hand-paint away all undesired spill-over weighting from nearby joint chains.

So! What do we need to do to make this happen? Whenever I approach a script, I do the following things:
  • Design a work flow/ user experience
  • Write up pseudo-script logic of what the script will do
  • Identify any problem spots I'm not sure how to do
  • Draw some mock-up UI
In the case of this script, the user experience I imagined was:
  1. Select the verts that need to be re-weighted
  2. Select the joints they should be weighted to
  3. Set whatever settings we need (evenly or by distance? max influences? Anything else?)
  4. Push button, receive bacon weighting!
Seems easy enough. Okay, so aside from the UI, what does the script actually do when I run it? Time for some pseudo-code:

joints = list of joints selected
verts = list of verts selected
for vert in verts:
    bonedist = dictionary of distances to each bone
    for joint in joints:
        bonedist.append(distance from vert to joint, paired to bone name)       
    count = user setting for max influences
    while count > 0:
        if even bind:
            lowbone = bone with (count)th lowest distance
            vertweighting(vert, lowbone) = 1/max influences
            count - 1
        if distance bind:
            distSum = sum of all items in bonedist
            lowbone = bone with (count)th lowest distance
            vertweighting(vert, lowbone) = bonedist(lowbone)/distSum
            count - 1
Okay, cool. Less than twenty lines of pseudo-code! It tells us the logic of the work that needs to be done. This will ideally turn into the notes in our script reminding us what we're actually doing.

Next, we need to identify the parts of this script that are difficult. Depending on your experience with Maya or python, you may be hesitant about:

  • How to organize this data elegantly
  • How to use the dictionary data structure for the bone/ distance pairs
  • How Maya stores vertex weighting
  • What command sets the weighting of a specific vertex to a specific bone
Luckily, a bit of internet searching can answer any of these questions! With a bit of digging, you will learn that a dictionary is an unsorted list of key/value pairs that can be searched by key or value. You will discover that Maya polygon objects store a weighting matrix of vertices and joint influences. You will discover that you need the setVertWeights command for this task. Isn't the internet awesome?

Here is the final UI (again in awesome Maya 2009 style) that I arrived at. As you can see, I provided check boxes and radio buttons for all the options we planned for, as well as several that merited addition after some further research. 

Once we have all these things in place, it's time to actually start coding. I'm not going to go into this step as this post is getting a bit long. Suffice it to say that no mater how well we plan, it usually becomes apparent that things are more complicated than we anticipated. In my case, I ended up dividing functions and re-combining them as I struggled to understand python class/ object structure. I learned a lot through this project about the structure of a tool, a lot about object oriented programming, and a lot about vertex weighting in Maya.

When writing any tool, it's important to not lose sight of your goal. Think of the person that you're designing for, and try to imagine what it will feel like to use the tool you've created. Is it intuitive? Does it do all the things it should do? Is it fast? Could you make this tool simpler? For anyone who might want to improve upon your work, did you comment your code sufficiently that another programmer could follow your thought process?

I heard a great piece of advice from a co-worker: when you code, you have three customers. The first is the end-user, who will use your work. The second is other coders, who may have to edit and maintain it. The third is the hardware, which will have to process it as efficiently as possible. Making just one or two of these customers happy is not enough. Weigh principle against pragmatism, and invest your efforts where they'll be most beneficial to the project.

That concludes this post mortem of the jpWeightsTool. I hope you got as much out of reading it as I did out of writing it! Cheers, and happy coding.

Friday, October 7, 2011

def HelloWorld(newContext):

Hello internet! Since I last posted here, many things have happened... most of them incredible.

I not only had a fantastic internship at Riot Games, but since became a full-time technical animator. I have seen our product, League of Legends, evolve from a pretty popular online game to a multi-award-winning, international, multi-million-player sensation. I have a GDC award sitting on my desk. I love my job. Everything went... way better than expected.

I also had a bit of a career re-focusing. When I last posted here, I listed my skills as "animator and concept artist." While I still love to draw and animate, my career path has strayed almost entirely into technical art. This is actually awesome. For the past year, I've become involved with a very smart and passionate group of people focused on helping others on their teams be effective. Though I've animated a few characters for LoL (Swain, Urgot, and Jarvan IV!), I've touched every character in the game by re-making their rigs, fixing problems, making tools, and generally filling that all-important support role. I'm learning more about rigging and programing (so far, mostly Python with a smidgen of C++) and a lot about game production. I'm really excited to see what sorts of problems I try to solve next!

The switch from student to industry professional happens incredibly fast. It was bizarre for me to go back and read my first couple of post on this blog; I was totally focused on the goal of getting hired and, as soon as it happened, I needed to totally re-contextualize my idea of success. I'm sure most Rioters who have been part of this ride from the beginning are stunned constantly by how far the company has come.

I'm excited to say I've had a few opportunities to help other students make the switch to industry professional as well. I've looked at dozens (hundreds?) of portfolios at GDC and SIGGRAPH. I've made a presentation with my co-workers to student volunteers just a year after I was sitting right where they were. Next week, I'm going to have the incredibly surreal experience of making a "how to get into the industry" talk at Ringling, speaking to many of the people I've known as a student! I'm incredibly excited for this trip. I've got my slides ready and a follow up Q&A lined up with the Game Design Club. It's going to be sweet.

I don't know how often I'll update this blog. Ideally, I start posting some work related to tech art; none of my internet presence currently suggests what I actually do. This is terribly hypocritical, seeing as I encourage every student I speak with to demonstrate their work and thought processes through blogs or websites. Historically my interests have been incredibly fickle; I start and stop side projects all the time. Within the last couple months I've started D&D campaigns, Warhammer 40K leagues, music jam sessions, indie games... tonight alone I painted miniatures for a co-worker, edited an article that'll be coming out soon in Game Developer magazine (super excited!), watched SoloMid livestreams, and wrote this blog post. I'm not sure I'll be able to stuff everything I want to do into the nights and weekends, so expect updates to be sporadic as usual.

For most of my life, I've felt guilty about the projects I keep starting and stopping. I'm starting to think, however, that it doesn't really matter; all of this is valuable. Even if I can't maintain focus on one problem for months on end, it's exactly this desire to stick my hands into everything that's allowed me to grow into a support role across many different projects. I'm excited for seeing where it all goes next.