Planet Tech Art
Last update: April 19, 2015 03:59 AM
April 12, 2015

Didn't need those eyeballs anyway!

OK, I admit this one is pretty much useless. But it’s still kind of cool :)
Just the other day I discussed setting up ConEmu for use as a direct maya terminal. This is fun, but once you’ve got the console virus the next thing that happens is you start getting obsessed with stupid terminal formatting tricks. It’s almost as if going text modes sends you past the furthest apogee of spartan simplicity and starts you orbiting inevitably back towards GUI bells and whistles.
At least, I know that about 15 minutes after I posted that last one, I was trying to figure out how to get colored text into my maya terminal window.
It turns out it’s pretty easy. ConEmu supports ANSI escape codes, those crazy 1970’s throwbacks that all the VIM kiddies use on their linux machines to make ugly termina color schemes:
all this beauty... in your hands!
This means any string that gets printed to ConEmu’s screen, if it contains color codes, will be in color! You can change background colors, foreground colors, even add bold, dim or (God help us) blinking text to your printouts.
Here’s a quick way to test this out:
Start up a maya command shell in ConEmu (instructions here if you missed them last time).
In your maya session, try this:

import sys
sys.ps1 = "Maya> "

This swaps in the custom prompt Maya> for the generic >>>.
console_prompt
Now, let’s try to make it a bit cooler: try setting sys.sp1 to this:
sys.ps1 = "\033[38;5;2mMaya>\033[0m "

color_console
Whoa!
Here’s what the gobbledygook means:
\033 is the ascii code for ‘escape’, which terminals use to indicate a non-printable character. The square bracket - number - m sequences are displayc ommands which will affect the output. In this case we said “set the text mode to color index 2’ (probably green on your system), type out ‘Maya> ‘, then revert to the default color”.
Here’s a few of the formatting codes that ConEmu supports:
  • \033[0m resets all escapes and reverts to plain text.
  • \033[1m and \033[2m start or end bold text
  • \033[4m turns on ‘inverse’ mode, with foreground and background colors reversed
  • \033[2J clears the terminal screen and sets the prompt and cursor back to the top. You probably don’t want to use this as your prompt, since it clears the screen after every key press! However it can be useful for paging through long results, Unix-more style.
  • 033[38;5;<index>m sets the text color to the color <index>. Colors are defined in the ConEmu settings dialog (Features > Colors). There are 16 color; here you identify them by index number (Color #0 is the default background, color #15 is the default foreground) This allows you to swap schemes – several well known codiing color schemes such as Zeburn and Solarized are included in ConEmu.
  • 033[48;5;<index>m sets the background color to the color <index>. The background colors are a bit hard to spot: if you check the colors dialog you’ll see a few items have two numbers next to them (such as ‘1/4’ or ‘3/5’). The second number is the background index. Yes, it’s wierd – it was the 70’s. What do you expect?
  • \033[39m resets any color settings.

These codes work sort of like HTML tags; if you “open” one and don’t “close” it you’ll find it stays on, so while you’re experimenting you’ll probably experience a few odd color moments.
But still… how cool is that? Now if we could only get it to syntax highlight… or recognize maya objects in return values… hmm. Things to think about :)
The Full list of escape codes supported by ConEmu is here

by Steve Theodore (noreply@blogger.com) at April 12, 2015 05:22 PM


April 09, 2015

Peanuts Movie Poster SnapFrame Lightbox

FullSizeRender38

The finished product

Step 1: Gather Materials

hardware

snap frame – found prices as low as $50-$60

aluminum tape

power adapter

leds

4×1 wood 9 ½’ or 136”

plywood 4 X 4

finishing nails

½ inch wood screws

cleat picture hanger - I didn’t actually use, but cool heavy picture hanging device

2 cans black primer+paint

Acetone

Isopropyl or Denatured Alcohol

WD-40

60/40 rosin core solder

hookup wire, black and red

heat shrink tubing

hot glue

blue painters tape

protection

glasses/goggles

earmuffs

respirator

tools

drill w/ phillips head and ¼” drill bit

circular saw

40-60W soldering iron

hot glue gun

heat gun

hammer

helping hand magnifier

wire stripper pliers

mini bar clamps

heavy duty scissors

straight edge/cutting guide/drywall t square

small carpenter square

dimms

vertical frame pieces – 41 ¼”

horizontal frame pieces – 26 ¾”

total horizontal dimm – 28 ¼”

frame made out of 3 ¾”w X ¾”d (1 X 4s)

plywood back is cut from a piece of 4 X 4

5 X 33 ¾” vertical LED strips

4 X 4 ½”- 5” horizontal LED strips

 

The Build Step-By-Step

mantra: measure THRICE cut once (I don’t trust myself)

Mark both sides of plywood. Plywood has ugly side, face it inwards and cover with aluminum tape. Medium sized Irwin Quick Grips are like two more hands, much needed. Use a nice straight edge and clamp it and the work down and cut with circular saw. Eyes and ears are a must when working in enclosed areas. The Black and Decker Matrix is ideal for small projects, so many useful adapters such as jig saw, circular saw, impact drill, router. An extra 20v lithium battery is a good idea to stay juiced up.

Make frame out of 1 x 4′s and clad with aluminum tape. The tape is tricky, there are a few techniques that might help manage it since it is super sticky. Peel the backing but just the very beginning. Secure that end to the ‘top’ of the board. Stretch and lay the tape down with the backing still on it. Align and hold the loose end of the tape to the ‘bottom’ of the board. While one hand is holding the bottom end against the surface use the other hand to peel the backing slowly. The tape will adhere and stay uniformly even and smooth.

Smooth out with sturdy paper towel or lintless cloth and wear gloves of some type to prevent getting cut.  Acetone or Isopropyl alcohol will clean dirt and skin oils from shiny aluminum surface but avoid cleaning too much as there’s much to do.

Check the fit of the frame pieces by arranging them on the plywood while it’s laying down. Attach the frame to the back by nailing down the longer pieces and then the smaller cross pieces with finishing nails.

Seal up all crevices so there’s no light leakage. This part is easier said than done. Try folding the tape with backing in half, unfold it, score the backing very lightly down the middle. Keep the tape folded at a 90 degree angle. Get the peel started for two sides of backing adjacent to the score and press that end into the corner. Brace it lightly with a spare piece of wood.  Remove the backing of one side while sliding the block of wood keeping very light pressure against the frame and back of the box.  This makes for a more consistently smooth surface of the tape.  The technique for the corners is kind of the same as far as scoring and folding but it’s better to remove the backing entirely and with the tips of the fingers keep it folded. Very carefully avoiding the frame walls insert the spine if the tape into the corner spread the halves and press them against the walls.

Take the piece of plastic that served as packaging and seal the box opening using blue painter’s tape. Strap on a 3M paint project respirator and eye protection. Run an orbital sander over the edges and faces. Primer is good for less coats of paint but not completely necessary. Paint + primer works well too.

Paint exterior a black matte, the first coat is a light one so don’t worry about filling all the nooks and crannys. Use smooth back and forth motion 6-8 inches away from surface and work in on small area at a time for the frame. The back has a larger surface area so start at the top and go smoothly back and forth like a printer head. Let dry for 30 mins to 1 hour. Paint another coat laying it on a little thicker.

Let dry overnight. Don’t remove the plastic until absolutely sure you’re happy with the paint job. Use a UV resistant matte clear finish to protect it. The finish will require more drying time but will protect from scratches and the sun.

Place LED strip inside and cover box with snap frame. Check light intensity,  coverage and that it is in working order. Plus admire how it will look when it is complete. Keeping the strip away from the walls lay it out in a back and forth pattern. Guage the length that will be measured for each row of leads that will need to be cut from the main coil. Remember that where the wire will feed into the interior will be the bottom and make sure the wire is long enough to go through the frame providing enough length so the terminal will be located external to the enclosure. The jack can also be embedded in the frame but it takes more time and milling.

It just so happens the manual that comes with the respirator makes a perfect layout guide for the LED strips. Unfold it and lay it out flat on the back or inside the enclosure. Line up each row with a fold and each smaller bend segment with the edge of the paper. Snake the lights around to get a sense of the length of each piece.

This isn’t a guide on how to solder but follow these steps to avoid the pitfalls when cutting and joining the pieces with hookup wire.  It is tempting to clean the inside, of course do so if it is filthy, but resist all urges to skip ahead until this process is complete. It may require most of a day to finish as it is technical and demanding of concentration.

Mark the end points of each row. Cut the pieces into their proper lengths with great care to get each measurement accurate so soldering will be no more than necessary. Peel the protective covering for the adhesive only a little and cut it off with scissors. This exposes a liitle of the adhesive but it also prevents burning of the paper once soldering begins.

Fingernails are mans first tool so use them or something similar to carefully pry up the flexible water proof encasing on either end of the trimmed strips. It is imperative that this is done cautiously as the metal the LEDs are attached to is very brittle. As soon as the clear coating is freed up take the scissors and cut a tab off it to expose the copper connectors on the metal. Now it should be easy to access them and use a soldering iron of appropriate power, 30-40W, to tin the connections and some wire.

First, stick the strips on the aluminum clad back face. It may seem desirable to join them together first but the connections are flimsy and will break with little intention.

Touch the wire to a bead of solder placed on the connector and heat them up to fuse the wire to the connector. Use heat shrink tubing to close up the end, double checking it is on the wire before finalizing the joints. Test with power on and then unplug and only then use a heat gun or blow dryer to shrink the tubing down. The most thorough job includes heat shrinking each wire, a dab of hot glue where the missing clear coating has been cut off and another larger piece of heat shrink over the whole thing to clean it all up and strengthen it to its maximum potential. If time is of the essence just two heat shrinks, one for each wire and that will suffice.

Do all of the soldering steps one end at a time very methodically and test it by plugging in the power after successfully joining another length of LEDs. If they fail to light completely, retrace your steps and strengthen any solder joints. When debugging electrical problems have a set of alligator clips to double check a set of LEDs will work or worse case a multimeter to check current. It’s pretty obvious which strip is the culprit after plugging in the power but not so obvious when a “fixed” connection doesn’t work. Have a spare length of lights that should be left over after cutting the initial pieces nearby just in case a connection is damaged beyond repair.

When the lights are all on and tested to satisfactory levels use hot glue to pin down the ends if the adhesive has worn off the back of each strip. Drill a small hole in the frame for the wire to feed into. Cut a small piece of aluminum tape to cover the hole and make a smaller incision in the tape and feed the wire through to the exterior. Put the anode and cathode wires into their respective screw terminals and tighten them down.

Place the SnapFrame on top of the enclosure and secure it with small screws. Attach a wall hanging device on the back, a length of picture hanging wire or saw tooth hanger or two will do nicely. The whole thing is a bit heavy, luckily the frame comes with drywall anchors encluded.

Clean the snap frame with alcohol and coat with thin layer of WD-40. Acetone is too strong for plastic poster covering. Plug it in one final time admire the lighting and have fun with the settings!

FullSizeRender FullSizeRender01 FullSizeRender02 FullSizeRender03 FullSizeRender04 FullSizeRender05 FullSizeRender06 FullSizeRender07 FullSizeRender08 FullSizeRender09 FullSizeRender10 FullSizeRender11 FullSizeRender12 FullSizeRender13 FullSizeRender14 FullSizeRender15 FullSizeRender16 FullSizeRender17 FullSizeRender18 FullSizeRender19 FullSizeRender20 FullSizeRender21 FullSizeRender22 FullSizeRender23 FullSizeRender24 FullSizeRender25 FullSizeRender26 FullSizeRender27 FullSizeRender28 FullSizeRender29 FullSizeRender30 FullSizeRender31 FullSizeRender32 FullSizeRender33 FullSizeRender34 FullSizeRender35 FullSizeRender36 FullSizeRender37 FullSizeRender38

 

 

by Jonas Avrin at April 09, 2015 04:18 PM


April 07, 2015

Do you want to play a game?

My Chrome browser split in half last night and asked me if I wanted to play a game. Saying yes turned my browser into a pseudo python console. Apparently Google has been tracking my search history and seen that, yeah, I like Python. Ok, having the browser window suddenly split open because someone is watching your search history is vaguely creepy, but what the hey, I do like Python!

Why do they want to play a game with me? I don't know, its Google. Why did they make Google maps into Pac Man? Its Google. They do stuff like that.

The first challenge was to take an equation as a string and parse it into reverse polish notation. After thinking about it today I was able to write a passable parser that will probably make any real mathematician twitch- but it works and the code doesn't make me twitch.

The challenge was, well, challenging, but fun! It reminds me a bit of the Project Euler challenges, except this one gives you a hopping bunny when you succeed. An animated ASCII hopping bunny.

Why?

Pac Man

Hop little bunny. Hop for joy!

by Peter Hanshaw (noreply@blogger.com) at April 07, 2015 04:02 AM


April 06, 2015

Con Job


If you do a lot of tools work in maya – particularly if you’re working one something that integrates with a whole studio toolset, instead of being a one-off script – you spend a lot of time restarting. I think I know every pixel of the last five Maya splash screens by heart at this point. A good knowledge of the python reload() command can ease the pain a bit, but there are still a lot of times when you want to get in and out quickly and waiting for the GUI to spin up can be a real drag.
If this drives you nuts, mayapy - the python interpreter that comes with Maya - can be a huge time saver. There are a lot of cases where you can fire off a mayapy and run a few lines of code just to validate that things are working and you don’t need to watch as all the GUI widgets draw in. This is particularly handy if you do a lot of tools work or script development, but’s also a great environment for doing quickie batch work – opening a bunch of files to troll for out of date rigs, missing textures, and similar annoyances.
All that said, the default mayapy experience is a bit too old-school if you’re running on Windows, where the python shell runs inside the horrendous CMD prompt, the same one that makes using DOS so unpleasant. If you’re used to a nice IDE like PyCharm or a swanky text editor like Sublime, the ugly fonts, the monochrome dullness, and above all the antediluvian lack of cut and paste are pretty offputting.
However, it’s not too hard to put a much more pleasant face on mayapy and make it a really useful tool.

Con Ed

obligatory "con" joke here.

The first thing to do is find a good console program. A console provides the window and display services for command-line programs; CMD.exe does the same thing, it just does it very badly. There are several good options depending on your taste (good roundup here)). I’m going to walk through the setup for my favorite emulator, ConEmu, but the same ideas should adapt to the other emulators pretty simply.
First, here’s a quick round up of what ConEmu is going to be doing for us and mayapay:
Cut and paste
Ctrl+C, Ctrl+V. Worth the price of admission all by itself!
Customizable fonts
A killer feature for those of us with old, weak eyes and/or aspirations to style
Command history
If you’re testing out a bit of syntax, or doing something that repetitive but not worth really automating you’ll get a lot of value out of the command history: you can use the up and down arrows to scroll through your recently issued commands and repeat them. Especially when you’re testing a script over and over this takes the bite out of those two or three lines of setup you need to enter again and again.
Startup options
We’ll want to pass a few flags and instructions to mayapy every time.
Multiple consoles in one window
ConEmu allows you to run different shells in different tabs. This can be invaluable if you’re doing things like checking the contents of multiple folders, but it’s also a great way to compare the results of your maya scripts side-by-side in two different sessions
Transparency
A palliative for OSX envy.

Setup basics

Again, these instructions are for ConEmu – if you try this with a different console, add your experience in the comments for others!
ConEmu is a great little tool, and it’s free, but it is a bit… overeager?… in its efforts to let you control everything. The interface is a bit old school, so it’s worth walking through the setup process step by step.
First you’ll want to download and install ConEmu (the installation instructions are down at the botton of the linked page, and the setup is basically ‘unzip into a folder’).
Once you’ve got ConEmu up and running, you’ll want to open the settings dialog and select the Tasks option from the tree list at left. This will show you a dialog like this:

Like I said, old school
For starters going to create a startup preset that launches mayapy. ConEmu calls these ‘tasks’. To create a new one, click that + botton under the list of predefined tasks. That will create a blank preset with a name like “Group #”, you can rename it by typing a better name in the text box just to the left of the word “Hotkey”.
The actual command you’ll type goes into the large text box on lower right. Just as test, enter the path to your mayapy in quotes, (usually it’s in Program files\Autodesk\MayaXXXX\bin\mayapy.exe) followed by a space and -i. The -i flag is important: it makes sure that mayaypy launches in interactive mode so you can actually use it – without the flag the application will launch and immediately quit! For maya 2015, for example, you can do:
"%ProgramFiles%/Autodesk/maya2015/bin/mayapy.exe" -i
Test out this minimal version by saving the settings (the Save Settings…) button at lower right and making a new console using the green plus button at the upper right. Select the preset; if all goes right you’ll get a python prompt like this:



If it doesn’t work, go back and make sure that you surrounded the path to maypy.exe with quotes. <insert rant about making an operating system with spaces in the paths that doesn't support spaces by default here!>

More cowbell

With just these options, you’ve got a working python intepreter, but it’s doesn’t have any maya-specific features. To get an actual maya session you could manually start a maya standalone by typing
import maya.standalone; maya.standalone.initialize()
at the prompt. This works, but it’s a bit tedious. You can automate the process in ConEmu by editing your task description: Go back to the task settings in ConEmu add this to your configuration:
"%ProgramFiles%/Autodesk/maya2015/bin/mayapy.exe" -i -c "import maya.standalone; maya.standalone.initialize()"
making sure again to check your quotes.
When you launch a new ConEmu session for your preset you’ll probably notice a pause on startup: that’s Maya starting up in the backgrdound. If your maya loads tools or scripts at startup via userSetup.py, you may see printouts or debug information scroll by as well. You should now be working in a standalone session, so you should be able to try something like:


Avoiding userSetup.py

If your startup scripts do something dependent on the maya GUI you may get an error instead. The Right ThingTM to do is to fix that: you don’t want GUI in your startup routine because it hampers your ability to do batch jobs or renders.
However as a stopgap measure you can suppress your userSetup.py and load a completely vanilla Maya. This requires setting an environment variable called MAYA_SKIP_USERSETUP_PY to 0, which unfortunately is something ConEmu can’t do for you. However, you can work around that by creating a .BAT file that sets the environment before launching mayapy. The bat will look like this:
set MAYA_SKIP_USERSETUP_PY  = 1
"%ProgramFiles%/Autodesk/maya2015/bin/mayapy.exe" -i -c "import maya.standalone; maya.standalone.initialize()"

exit
You can point your ConEmu task at the .BAT file instead of directly at mayapy and you should get a no-userSetup session.
This trick can also be used to launch mayapy with different environment variables – for example, I use to maintain different mayapy’s for different projects based on a set of project-specific env vars.

Con Air

I’ve been using mayapy in the terminal window as a key part of my work for about a year now, and I’m sure I’ve saved many, many hours of waiting when I noodle on various bits of code, one-off batch tasks, and general noodling. In addition to speedier startup, running mayaPy in the console also gives you a more customizable view and command history, so it’s also a great replacement for many things you might otherwise want to do by starting up Maya and popping open the listener.
Of course, on the meta-meta-level it is a bit odd to by running a text only version of the most powerful graphics tool on the planet. But hey, that’s how we roll in techart land.

by Steve Theodore (noreply@blogger.com) at April 06, 2015 02:30 PM


April 05, 2015

WYG > WYS

Update 4/4/2015:  I've got a much improved pipeline for markdown blogging using Sublime Text, as detailed here.  I'm also having a lot of luck with MDWiki for static sites on github.io

First off, a confession. I’ve become a plaintext nazi. 30 years since I first hit Ctrl+I to italicise a piece of text, I’ve pretty much abandoned fancy-pants text edtors for the hardcore geek chic of plain text and Markdown.
To be honest, this makes me uncomfortable, because plain-text-chauvinism is the techie equivalent of skinny jeans and ironical facial hair; it’s definitely a thing for the Cool Kids,tm a demographic which is not really my native habitat.
 But I’m willing to be cool if that’s what it takes.



Markdown is just a great tool for writing web or wiki content. If you spend a lot of time typing - particularly if you’re a TA who spends a lot of typing Python! – it becomes natural really quickly.
The great thing about markdown is that it’s not dependent on the vagaries of a particular editor or application. There’s no need to worry about the layout of the menus or the mnemonics of the hotkeys - you just type. You just tap away without taking your hands off the keyboard to hit special key combinations for formatting (eg bold, italic), so you go a lot faster.
In markdown, the emphasis is on the structure of what you’re writing instead of the presentation. You don’t format, you ‘mark up’ - that is you indicate what the job of a particular bit of text, is but you don’t describe it’s appearance. You can create headings, lists, block quotes, and even code snippets just using some simple conventions. Moreover the conventions are pretty readable in plain text. For example, you this little snippet of text
heading
========
This is some plain text

### subheading
* list item
* other list item
Produces this formatted output:

heading

text goes here

subheading

  • list item
  • other list item
The actual look of the output is going to be controlled down stream something else. Most markdown is processed into HTML using CSS to control things like fonts, line-spacing, and alignment.
I’ve found that markdown makes me a lot more productive than traditional WYSWIG editing. In part that’s because I can write markdown in a very stripped-down editor like Sublime Text on the PC or Ulysses on the Mac. These stripped-down editors are really qick and responsive, since they do so much next to nothing in the realm of document layout. Most important for me, they include far fewer distractions than Word or even Google Docs, so I can focus on the job at hand instead of fiddling around with styles and formatting.
In cases where the layout actually matters I can take the finished text and export it via HTML or PDF to a traditional layout program, but nowadays that almost never happens: I literally cannot remember the last time I worried about the layout of words and images on a printed page (which is a pretty odd reflection for me, since I only got into computers because of desktop publishing, back when that was a thing.). Some flavors of markdown include the ability to inline html directly in the text for special purposes - for example, I got the superscript after Cool Kids tm by typing
Cool Kids <sup>tm</sup> 
99 times out of 100, however, this level of specificity isn’t important until the real work of writing is done and I’m just polishing up - I’m much happier focusing on the actual content and tweaking the visuals at the very last minute. That’s what a lifetime of game devlopment does to a person.
Nowadays I do all my writing in plain text and markdown, with two exceptions. The wiki we use at work, Confluence, doesn’t support markdown and to be perfectly frank it drives me nuts: The editor feels sluggish and the workflow constantly distracts me from what I’m supposed to be actually writing. And, unfotunately, Blogger doesn’t support md either. Blogger is at least not quite as sluggish as Confluence, but it definitely feels like wearing a deep-sea diver suit compared to blazing away in a plain text editor with markdown.
Luckily I’ve found an option that at least looks pretty good. This post was written entirely in StackEdit, a free online markdown editor which also allows publishing directly to Blogger. I followed these instructions by Gianluca Casati which seem to work pretty well.
On the upside, this feels a lot more productive and focused than the usual Blogger writing process. In particular, it’s way easier to include short bits of code in markdown. Including code snippets into blogger, on the other hand, is a huge pain in the patootie; In the past I’ve used Gists, which are not to hard to embed and produce nicely highlighted code in lots of languages. For long format code it’s still a great tool. However it’s not ideal for small snippets of a few lines - there’s a lot of hopping around between editors and it’s very disjointed, which tends to get in the way of good flow when writing. For short jobs I will often just hand-edit the HTML produced by Blogger, which works but is, frankly, BS.
One the downside, the StackEdit > markdown > html > Blogger pipeline is precisely the sort of jury-rigged song and dance that drives me crazy in my day job. Translations are rarely perfect in any case, and inserting three of them along the way to do a single job offends my sense of Pipeline Fu. I have yet to figure out how to tweak the final results to stay in line with the established style of the blog, and it’s particularly tough to tweak the final results directly in Blogger if I need to make a tweak. The last straw is blogger's maddening habit of replacing <p> tags with <br/> tags, even if you paste HTML right into the HTML editor.  It all feels a lot like a complex MEL pipeline. It works... but it feels wrong.
So, apologies for any wierd fomatting here - this is a very beta version of a new process. I’m still not satisfied that this is the ‘right’ way to write for the web (Santa, if you’re reading this, I’d kill for a good markdown blogging platform that also did Python syntax highlighting!).

by Steve Theodore (noreply@blogger.com) at April 05, 2015 06:43 PM


April 04, 2015

Optimizing Unity Renderer Part 2: Cleanups

With the story introduction in the last post, let’s get to actual work now!

As already alluded in the previous post, first I try to remember / figure out what the existing code does, do some profiling and write down things that stand out.

Profiling on several projects mostly reveals two things:

1) Rendering code could really use wider multithreading than “main thread and render thread” that we have now. Here’s one capture from Unity 5 timeline profiler:

In this particular case, CPU bottleneck is the rendering thread, where majority of the time it just spends in glDrawElements (this was on a MacBookPro; GPU-simplified scene from Butterfly Effect demo doing about 6000 draw calls). Main thead just ends up waiting for the render thread to catch up. Depending on the hardware, platform, graphics API etc. the bottleneck can be elsewhere, for example the same project on a much faster PC under DX11 is spending about the same time in main vs. rendering thread.

The culling sliver on the left side looks pretty good, eventually we want all our rendering code to look like that too. Here’s the culling part zoomed in:

2) There are no “optimize this one function, make everything twice as fast” places :( It’s going to be a long journey of rearranging data, removing redundant decisions, removing small things here and there until we can reach something like “2x faster per thread”. If ever.

The rendering thread profiling data is not terribly interesting here. Majority of the time (everything highlighted below) is from OpenGL runtime/driver. Adding a note that perhaps we do something stupid that is causing the driver to do too much work (I dunno, switching between different vertex layouts for no good reason etc.), but otherwise not much to see on our side. Most of the remaining time is spent in dynamic batching.

Looking into the functions heavy on the main thread, we get this:

Now there are certainly questions raised (why so many hashtable lookups? why sorting takes so long? etc., see list above), but the point is, there’s no single place where optimizing something would give magic performance gains and a pony.

Observation 1: material “display lists” are being re-created often

In our code, a Material can pre-record what we call a “display list” for the rendering thread. Think of it as a small command buffer, where a bunch of commands (“set this raster state object, set this shader, set these textures”) are stored. Most important thing about them: they are stored with all the parameters (final texture values, shader uniform values etc.) resolved. When “applying” a display list, we just hand it off to the rendering thread, no need to chase down material property values or other things.

That’s all well and good, except when something changes in the material that makes the recorded display list invalid. In Unity, each shader internally often is many shader variants, and when switching to a different shader variant, we need to apply a different display list. If the scene was setup in such a way that caused the same Materials to alternate between different lists, then we have a problem.

Which was exactly what was happening in several of the benchmark projects I had; short story being “multiple per-pixel lights in forward rendering cause this”. Turns out we had code to fix this on some branch, it just needed to be finished up – so I found it, made to compile in the current codebase and it pretty much worked. Now the materials can pre-record more than one “display list” in them, and that problem goes away.

On a PC (Core i7 5820K), one scene went from 9.52ms to 7.25ms on the main thread which is fairly awesome.

Spoilers ahead: this change is the one that brought the largest benefit on the affected scenes, from everything I did over almost two weeks. And it wasn’t even the code that “I wrote”; I just fished it out from a somewhat neglected branch. So, yay! An easy change for a 30% performance gain! And bummer, I will not get this kind of change from anything written below.

Observation 2: too many hashtable lookups

Next from the observations list above, looked into “why so many hashtable lookups” question (if there isn’t a song about it yet, there should be!).

In the rendering code, many years ago I added something like Material::SetPassWithShader(Shader* shader, ...) since the calling code already knows with which shader material state should be setup with. Material also knows it’s shader, but it stores something we call a PPtr (“persistent pointer”) which is essentially a handle. Passing the pointer directly avoids doing a handle->pointer lookup (which currently is a hashtable lookup since for various complicated reasons it’s hard to do an array-based handle system, I’m told).

Turns out, over many changes, somehow Material::SetPassWithShader ended up doing two handle->pointer lookups, even if it already got the actual shader pointer as a parameter! Fixed:

Ok so this one turned out to be good, measurable and very easy performance optimization. Also made the codebase smaller, which is a very good thing.

Small tweaks here and there

From the render thread profiling on a Mac above, our own code in BindDefaultVertexArray was taking 2.3% which sounded excessive. Turns out, it was looping over all possible vertex component types and checking some stuff; made the code loop only over the vertex components used by the shader. Got slightly faster.

One project was calling GetTextureDecodeValues a lot, which compute some color space, HDR and lightmap decompression constants for a texture. It was doing a bunch of complicated sRGB math on an optional “intensity multiplier” parameter which was set to exactly 1.0 in all calling places except one. Recognizing that in the code made a bunch of pow() calls go away. Added to a “look later” list: why we call that function very often in the first place?

Some code in rendering loops that was figuring out where draw call batch boundaries need to be put (i.e. where to switch to a new shader etc.), was comparing some state represented as separate bools. Packed a bunch of them into bitfields and did comparisons on one integer. No observable performance gains, but the code actually ended up being smaller, so a win :)

Noticed that figuring out which vertex buffers and vertex layouts are used by objects queries Mesh data that’s quite far apart in memory. Reordered data based on usage type (rendering data, collision data, animation data etc.).

Also reduced data packing holes using @msinilo’s excellent CruncherSharp (and did some tweaks to it along the way :)) I hear there’s a similar tool for Linux (pahole). On a Mac there’s struct_layout but it was taking forever on Unity’s executable and the Python script often would fail with some recursion overflow exception.

While browsing through the code, noticed that the way we track per-texture mipmap bias is very convoluted, to put it mildly. It is set per-texture, then the texture tracks all the material property sheets where it’s being used; notifies them upon any mip bias change, and the bias is fetched from property sheets and applied together with the texture each and every time a texture is set on a graphics device. Geez. Fixed. Since this changed interface of our graphics API abstraction, this means changing all 11 rendering backends; just a few fairly trivial changes in each but can feel intimidating (I can’t even build half of them locally). No fear, we have the build farm to check for compile errors, and the test suites to check for regressions!

No significant performance difference, but it feels good to get rid of all that complexity. Adding to a “look later” list: there’s one more piece of similar data that we track per-texture; something about UV scaling for non-power-of-two textures. I suspect it’s there for no good reason these days, gotta look and remove it if possible.

And some other similar localized tweaks, each of them is easy and makes some particular place a tiny bit better, but does not result in any observable performance improvement. Maybe doing a hundred of them would result in some noticable effect, but it’s much more possible that we’ll need some more serious re-working of things to get good results.

Data layout of Material property sheets

One thing that has been bothering me is how we store material properties. Each time I’d show the codebase to a new engineer, in that place I’d roll my eyes and say “and yeah, here we store the textures, matrices, colors etc. of the material, in separate STL maps. The horror. The horror.”.

There’s this popular thought that C++ STL containers have no place in high performance code, and no good game has ever shipped with them (not true), and if you use them you must be stupid and deserve to be ridiculed (I don’t know… maybe?). So hey, how about I go and replace these maps with a better data layout? Must make everything a million times better, right?

In Unity, parameters to shaders can come from two places: either from per-material data, or from “global” shader parameters. Former is typically for things like “diffuse texture”, while the latter is for things like “fog color” or “camera projection” (there’s slight complication with per-instance parameters in form of MaterialPropertyBlock etc., but let’s ignore that for now).

The data layout we had before was roughly this (PropertyName is basically an integer):

1
2
3
4
5
6
map<PropertyName, float> m_Floats;
map<PropertyName, Vector4f> m_Vectors;
map<PropertyName, Matrix4x4f> m_Matrices;
map<PropertyName, TextureProperty> m_Textures;
map<PropertyName, ComputeBufferID> m_ComputeBuffers;
set<PropertyName> m_IsGammaSpaceTag; // which properties come as sRGB values

What I replaced it with (simplified, only showing data members; dynamic_array is very much like std::vector, but more EASTL style):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct NameAndType { PropertyName name; PropertyType type; };

// Data layout:
// - Array of name+type information for lookups (m_Names). Do
//   not put anything else; only have info needed for lookups!
// - Location of property data in the value buffer (m_Offsets).
//   Uses 4 byte entries for smaller data; don't use size_t!
// - Byte buffer with actual property values (m_ValueBuffer).
// - Additional data per-property in m_GammaProps and
//   m_TextureAuxProps bit sets.
//
// All the arrays need to be kept in sync (sizes the same; all
// indexed by the same property index).
dynamic_array<NameAndType> m_Names;
dynamic_array<int> m_Offsets;
dynamic_array<UInt8> m_ValueBuffer;

// A bit set for each property that should do gamma->linear
// conversion when in linear color space
dynamic_bitset m_GammaProps;
// A bit set for each property that is aux for a texture
// (e.g. *_ST for texture scale/tiling)
dynamic_bitset m_TextureAuxProps;

When a new property is added to the property sheet, it is just appended to all the arrays. Property name/type information and property location in the data buffer are kept separate so that when searching for properties, we don’t even fetch the data that’s not needed for the search itself.

Biggest external change is that before, one could find a property value and store a direct pointer to it (was used in the pre-recorded material display lists, to be able to “patch in” values of global shader properties before replaying them). Now the pointers are invalidated whenever resizing the arrays; so all the code that was possibly storing pointers has to be changed to store offsets into the property sheet data instead. So in the end this was quite some code changes.

Finding properties has changed from being an O(logN) operation (map lookup) into an O(N) operation (linear scan though the names array). This sounds bad if you’re learning computer science as it is typically taught. However, I looked at various projects and found that typically the property sheets contain between 5 and 30 properties in total (most often around 10); and a linear scan with all the search data right next to each other in memory is not that bad compared to STL map lookup where the map nodes can be placed arbitrarily far away from one another (if that happens, each node visit can be a CPU cache miss). From profiling on several different projects, the part that does “search for properties” was consistently slightly faster on a PC, a laptop and an iPhone.

Did this change brought magic performance improvements though? Nope. It brought a small improvement in average frame time and slightly smaller memory consumption, especially when there are lots of different materials. But does “just replace STL maps with packed arrays” result in magic? Alas, no. Well, at least I don’t have to be roll my eyes anymore when showing this code to people, so there’s that.

Upon my code review, one comment that popped up is that I should try splitting up property data so that properties of the same type are grouped together. A property sheet could know which start and end index is for a particular type, and then searching for a particular property would only need to scan the names array of that type (and the array would only contain an integer name per property, instead of name+type). Adding a new property into the sheet would become more expensive, but looking them up cheaper.

A side note from all this: modern CPUs are impressively fast at what you could call “bad code”, and have mightily large caches too. I wasn’t paying much attention to mobile CPU hardware, and just realized that iPhone 6 CPU has a 4 megabyte L3 cache. Four. Megabytes. On a phone. That’s about how much RAM my first PC had!

Results so far

So that was about 2 weeks of work (I’d estimate at 75% time - the rest spent on unrelated bugfixes, code reviews, etc.); with a state where all the platforms are building and tests are passing; and a pull request ready. 40 commits, 135 files, about 2000 lines of code changed.

Performance wise, one benchmark project improved a lot (the one most affected by “display lists being re-created” issue), with total frame time 11.8ms -> 8.50ms on PC; and 29.2ms -> 26.9ms on a laptop. Other projects improved, but nowhere near as much (numbers like 7.8ms -> 7.3ms on PC; another project 15.2ms -> 14.1ms on iPhone etc.).

Most of the performance improvements came from two places really (display list re-creation; and avoiding useless hashtable lookups). Not sure how to feel about the rest of the changes - it feels like they are good changes overall, if only because I now have a better understanding of the codebase, and have added quite many comments explaining what & why. I also now have an even longer list of “here are the places that are weird or should be improved”.

Is spending almost two weeks worth the results I got so far? Hard to say. Sometimes I do have a week where it feels like I did nothing at all, so it’s better than that :)

Overall I’m still not sure if “optimizing stuff” is my strong area. I think I’m pretty good at only a few things: 1) debugging hard problems – I can come up with plausible hypotheses and ways to divide-and-conquer the problem fast; 2) understanding implications of some change or a system – what other systems will be affected and what could/would be problematic interactions; and 3) having good ambient awareness of things done by others in the codebase – I can often figure out when several people are working on somewhat overlapping stuff and tell them “yo, you two should coordinate”.

Is any of that a useful skill for optimization? I don’t know. I certainly can’t juggle instruction latencies and execution ports and TLB misses in my head. But maybe I’ll get better at it if I practice? Who knows.

Not quite sure which path to go next at the moment; I see at least several possible ways:

  1. Continue doing incremental improvements, and hope that net effect of a lot of them will be good. Individually each of them is a bit disappointing since the improvement is hard to measure.
  2. Start looking at the bigger picture and figure out how we can avoid a lot of currently done work completely, i.e. more serious “reshaping” of how things are structured.
  3. Once some more cleanup is done, switch to helping others with “multithread more stuff” approaches.
  4. Optimization is hard! Let’s play more Rocksmith until situation improves.

I guess I’ll discuss with others and do one or more of the above. Until next time!

by at April 04, 2015 11:54 AM


April 03, 2015

April 02, 2015

April Rigging Dojo’s Artist in Residence (A.I.R) : John Hood

April 8th 10pm eastern: John Hood – Pipeline Supervisor at Sony Pictures Imageworks We are so happy to have John Hood as our Artist in Residence (A.I.R) for April. John is one of the few among us who is truly both a great artist and programmer. He’ll be speaking with us about Maya UI and […]

The post April Rigging Dojo’s Artist in Residence (A.I.R) : John Hood appeared first on Rigging Dojo.

by Rigging Dojo at April 02, 2015 05:12 PM


April 01, 2015

#hyperlapse been trying to finish this book a while. It’s...

A video posted by Shawn (@shawnkirsch) on Apr 1, 2015 at 8:01am PDT



#hyperlapse been trying to finish this book a while. It’s been a while since I’ve done much drawing. I finished this book a few months ago, and haven’t really drawn since. I was looking in my journal and. A year ago today, Stephen silver told me sometimes you just need a break.

by at April 01, 2015 03:01 PM


Optimizing Unity Renderer part 1: Intro

At work we formed a small “strike team” for optimizing CPU side of Unity’s rendering. I’ll blog about my part as I go (idea of doing that seems to be generally accepted). I don’t know where that will lead to, but hey that’s part of the fun!

Backstory / Parental Warning

I’m going to be harsh and say “this code sucks!” in a lot of cases. When trying to improve the code, you obviously want to improve what is bad, and so that is often the focus. Does not mean the codebase in general is that bad, or that it can’t be used for good things! Just this March, we’ve got Pillars of Eternity, Ori and the Blind Forest and Cities: Skylines among top rated PC games; all made with Unity. Not too bad for “that mobile engine that’s only good for prototyping”, eh.

The truth is, any codebase that grows over long period of time and is worked on by more than a handful of people is very likely “bad” in some sense. There are areas where code is weird; there are places that no one quite remembers how or why they work; there are decisions done many years ago that don’t quite make sense anymore, and no one had time to fix yet. In a big enough codebase, no single person can know all the details about how it’s supposed to work, so some decisions clash with some others in subtle ways. Paraphrasing someone, “there are codebases that suck, and there are codebases that aren’t used” :)

It is important to try to improve the codebase though! Always keep on improving it. We’ve done lots of improvements in all the areas, but frankly, the rendering code improvements over last several years have been very incremental, without anyone taking a hard look at the whole of it and focusing on just improving it as a fulltime effort. It’s about time we did that!

A number of times I’d point at some code and say “ha ha! well that is stupid!”. And it was me who wrote it in the first place. That’s okay. Maybe now I know better; or maybe the code made sense at the time; or maybe the code made sense considering the various factors (lack of time etc.). Or maybe I just was stupid back then. Maybe in five years I’ll look at my current code and say just as much.

Anyway…

Wishlist

In pictures, here’s what we want to end up with. A high throughput rendering system, working without bottlenecks.

Animated GIFs aside, here’s the “What is this?” section pretty much straight from our work wiki:

Current (Unity 5.0) rendering, shader runtime & graphics API CPU code is NotTerriblyEfficient(tm). It has several issues, and we want to address as much of that as possible:

  • GfxDevice (our rendering API abstraction):
    • Abstraction is mostly designed around DX9 / partially-DX10 concepts. E.g. constant/uniform buffers are a bad fit now.
    • A mess that grew organically over many years; there are places that need a cleanup.
    • Allow parallel command buffer creation on modern APIs (like consoles, DX12, Metal or Vulkan).
  • Rendering loops:
    • Lots of small inefficiencies and redundant decisions; want to optimize.
    • Run parts of loops in parallel and/or jobify parts of them. Using native command buffer creation API where possible.
    • Make code simpler & more uniform; factor out common functionality. Make more testable.
  • Shader / Material runtime:
    • Data layout in memory is, uhm, “not very good”.
    • Convoluted code; want to clean up. Make more testable.
    • “Fixed function shaders” concept should not exist at runtime. See [Generating Fixed Function Shaders at Import Time].
    • Text based shader format is stupid. See [Binary Shader Serialization].

Constraints

Whatever we do to optimize / cleanup the code, we should keep the functionality working as much as possible. Some rarely used functionality or corner cases might be changed or broken, but only as a last resort.

Also one needs to consider that if some code looks complicated, it can be due to several reasons. One of them being “someone wrote too complicated code” (great! simplify it). Another might be “there was some reason for the code to be complex back then, but not anymore” (great! simplify it).

But it also might be that the code is doing complex things, e.g. it needs to handle some tricky cases. Maybe it can be simplified, but maybe it can’t. It’s very tempting to start “rewriting something from scratch”, but in some cases your new and nice code might grow complicated as soon as you start making it do all the things the old code was doing.

The Plan

Given a piece of CPU code, there are several axes of improving its performance: 1) “just making it faster” and 2) make it more parallel.

I thought I’d focus on “just make it faster” initially. Partially because I also want to simplify the code and remember the various tricky things it has to do. Simplifying the data, making the data flows more clear and making the code simpler often also allows doing step two (“make it more parallel”) easier.

I’ll be looking at higher level rendering logic (“rendering loops”) and shader/material runtime first, while others on the team will be looking at simplifying and sanitizing rendering API abstraction, and experimenting with “make it more parallel” approaches.

For testing rendering performance, we’re gonna need some actual content to test on. I’ve looked at several game and demo projects we have, and made them be CPU limited (by reducing GPU load - rendering at lower resolution; reducing poly count where it was very large; reducing shadowmap resolutions; reducing or removing postprocessing steps; reducing texture resolutions). To put higher load on the CPU, I duplicated parts of the scenes so they have way more objects rendered than originally.

It’s very easy to test rendering performance on something like “hey I have these 100000 cubes”, but that’s not a very realistic use case. “Tons of objects using exact same material and nothing else” is a very different rendering scenario from thousands of materials with different parameters, hundreds of different shaders, dozens of render target changes, shadowmap & regular rendering, alpha blended objects, dynamically generated geometry etc.

On the other hand, testing on a “full game” can be cumbersome too, especially if it requires interaction to get anywhere, is slow to load the full level, or is not CPU limited to begin with.

When testing for CPU performance, it helps to test on more than one device. I typically test on a development PC in Windows (currently Core i7 5820K), on a laptop in Mac (2013 rMBP) and on whatever iOS device I have around (right now, iPhone 6). Testing on consoles would be excellent for this task; I keep on hearing they have awesome profiling tools, more or less fixed clocks and relatively weak CPUs – but I’ve no devkits around. Maybe that means I should get one.

The Notes

Next up, I ran the benchmark projects and looked at profiler data (both Unity profiler and 3rd party profilers like Sleepy/Instruments), and also looked at the code to see what it is doing. At this point whenever I see something strange I just write it down for later investigation:

Some of the weirdnesses above might have valid reasons, in which case I go and add code comments explaining them. Some might have had reasons once, but not anymore. In both cases source control log / annotate functionality is helpful, and asking people who wrote the code originally on why something is that way. Half of the list above is probably because I wrote it that way many years ago, which means I have to remember the reason(s), even if they are “it seemed like a good idea at the time”.

So that’s the introduction. Next time, taking some of the items from the above “WAT?” list and trying to do something about them!

Update: next blog post is up. Part 2: Cleanups.

by at April 01, 2015 07:01 AM


March 31, 2015

Namespace packages for shared DCC’s code & tools

We do quite a few shared Python DCC tools and lib’s. With 3dsMax in the mix, this has recently gotten way easier with official Python and PySide support (though MaxPlus is pretty immature, but that’s another story).

One thing we wave have been using is a “namespace package”. This allow’s several folders on disk to merge into one logical namespace, using package utils (pkgutil). So we have something like the following folder structure:

shared_code/my_package
max_code/my_package
mobu_code/my_package
maya_code/my_package

Here Maya’s Python Path will include both “shared_code/my_package” and “maya_code/my_package”.

This way, anything in “shared_code/my_package” and “maya_code/my_package” is available in the same namespace and can import freely from one another etc. Works for sub packages too and PyCharm totally get’s it, unlike with other methods I’ve tried, where introspection and code completion broke down.

If something is defined in both folder locations, it’s the order of these folders on the Python Path, that dictates which module takes precedence. You can use this to create “local overrides” and I’ve set set it up, so the application specific folder overrides the shared folder. This detail has turned out to be pretty useful.

The only issue I found, is that a *.pyc file in one folder might “override” a *.py file in another folder. This can can cause unintentional “local overrides”, say you have removed a *.py file from source control, but the user still has the *.pyc file on disk. The solution was to delete any *.pyc files from disk as each application launches. Seems a little dirty, but has worked so far.

I’m pretty pleased with this setup.

by sune at March 31, 2015 12:45 PM


Free Software

Free And Open Source Software

There is an awful lot of really nice free software and utilities out there. This is a list that is compiled against a great thread on CgSociety. I pulled things that I am looking forward to try out as well as things I have been using myself. All of the links on this page are Windows compatible as that is my main work environment.

As far as general free software, check out Ninite – a fantastic installer. Gather and install them all at once. It will skip toolbars and other junk that comes with installers. It will also get you the 64 bit version if available.
Tech artists in the 3d field today are enjoying life thanks to Python, Eclipse and a host of free libraries that empowers us (see my Eclipse Python and Maya post).

Now to the lists:

3D
NameDescription
SculptrisZ-Brushy
An Ivy GeneratorIvy Generator
Arbaro Tree GeneratorTree Generator
ngPlantPlant Modeler
BlenderThe most popular open source 3d package out there…
Wings3dSub D modeler
LuxRenderPhysically based, unbiased render engine
MeshmixerCompose new 3d models from existing meshes
ShapeShopDrag-and-drop 3d parts to quickly assemble seamless smooth surfaces.
RenderManRenderman is now free for non-commercial purposes
3D Utilities
NameDescription
sIblSmart Image Based Lighting. Rocks!
nDoLegacy version is free. Create normal maps inside Photoshop.
xNormalNormal map, AO, displacement generation/baking
PapagayoLip Sync Reference
2D
NameDescription
GimpLike Photoshop
PS Shortcuts for GIMPMake it even more like Photoshop
MapZoneOwned by Allegorithmic. Procedural Compositing Graph Editor for file texture building.
Paint.netImage Editor
SumopaintOpen Sumo Paint – upload and paint right in the browser
MyPaintPaint program
IrfanviewImage Viewer and utility
PicasaImage viewer and utility
Luminance HDROpen source GUI that provides workflow for HDR imaging
GiftedMotionSimple to use Gif animation
IncscapeLike Illustrator
DJV ImagingProfessional movie playback for film production, VFX and computer animation
VLCMultimedia Player (It plays everything)
AvidemuxFree video editor for simple cutting, filtering and encoding tasks.
MediaInfoHandy utility to display technical and tag info about a video or audio file
MiroVideoConverterSuper simple video converter. Easily get your stuff into Android, iOS
FusionHigh end node based compositor. Now free...
Game Engine
NameDescription
UnrealEngine4Now free...
UnityAlso Free...
Sound
NameDescription
AudacityFree cross platform sound editor
Documentation
NameDescription
Google DocsIn the cloud documents , spreadsheets, presentations, drawings and forms
Open OfficeOffice software suite for word processing, spreadsheets, presentations, graphis, databases and more
OS Utilities
NameDescription
CD BurnerXPBurns CDs, DVDs, Blue Ray’s, Create ISOs
FileZillaFTP
HyperCamScreen Capture & Recording
SyncToyGreat tool for file syncing. Can be scheduled and command line run. Don’t back off because it is MS – it is good
Areca BackupOpen source back up utility
FileRenamerMulti file re-namer
Bulk Rename UtiliityPowerful multi file re-namer with a staggering amount of options

I will do my best to maintain this list as I come across new, interesting (and free) software.
/Christian Akesson

The post Free Software appeared first on The Art & Tech of Christian Akesson.

by cakesson at March 31, 2015 06:58 AM