Tuesday, November 5, 2013

Senior Capstone: Pixel Art and UDK

Updated 20 Nov, 2013
Updated 7 Jan, 2014
Updated 26 Jan, 2014

Some people consider Minecraft to be an ugly game.  I, however, am fascinated by the way it combines a 3D world with 2D pixel art.  In fact, I love that combination so much that I decided to try to implement it in my capstone project!  This has been a bigger pain in the neck than I could have possibly imagined before I started, so I would like to share some of what I have learned so far.  Please note that I am still developing this process, so your results may vary.  I will be sure to update this post as I glean new information, and mark said updates as best I can for anyone who might wish to revisit this post.

This guide covers implementing pixel art textures on low-poly, blocky models that have been made in Maya 2013, textured using Photoshop CS6, and imported into UDK.  I have not tried this process in other programs, so I cannot say for sure it is universally applicable.  If anyone is willing to give it a shot in traditional indie tools like Unity or Blender, please share your results!

An example of my current results can be seen below.  I also have an imgur album going which I will update periodically, for those who might be interested.

WIP screenshot from 4 November 2013

Part One: figure out your scaling

Scaling has probably been the biggest source of confusion for me.  Without approaching it carefully and methodically, you will end up with a mess of textures that don't appear to have the same sized pixels or are inexplicably blurry.  Trust me, I know from experience!

To get started, it's important to understand (or in some cases, establish) the relationship between the units used by your various programs.  Luckily, units in Maya and units in UDK scale one-to-one, so there is no real guesswork there.  Using these two programs together means you simply have to choose the size of one "pixel" in relation to this scale.  To keep things simple, I just went with a 1:1:1 ratio, meaning one pixel equals one Maya unit equals one UDK unit.  Easy enough, right?

Keep in mind that the default UDK player is 96 units tall as you begin designing and then blocking out your environment.  Make everything a power of 2-- or even better, divisible by a certain power of 2, like 16-- to ensure your models and textures will all be uniform.  Below is an example of the scaling of the player and a couple key meshes.  Precise diagrams will potentially save you a lot of time, but making a couple rough meshes and textures to see how things fit together is a good place to start if you're not sure what you want yet-- things look ridiculously huge in my diagram, but actually look and feel comfortable when implemented.

This is why I stick to pixel art, by the way


Part Two: modeling within your scale

Once you have a decent understanding of what size to make an object, you're almost ready to model.  Remember how earlier I said it'd be good to pick a specific power of 2 number to use for division?  This is where you'll first use that number-- I'll call it the scaling number for reference.  The best scaling number is one that makes it very easy to accurately model your object when snap-to-grid is turned on, but can also be used to the same effect with as many of your models as possible.  I highly recommend choosing such a number and just designing all of your models around it-- 16 has been working well for me, but your needs may differ.  Divide your width, height, and depth by this scaling number and write those results down.  If any of them aren't a whole number, you either need to adjust your design to fix it or choose a new scaling number.  Fractions kind of defeat the purpose of using snap-to-grid, after all-- you can get away with the occasional half, but whole numbers will make things less painful.

Use your calculated width, height, and depth to model the object.  Stick to the grid with every change you make.  Inserting and edge loop?  Align it to the grid.  Extruding something?  Align it to the grid.  Mending meshes together?  Align that seam to the grid.  It can be tedious at first if you're used to the freedom of organic modeling, but the blockier the model, the easier unwrapping and texturing will be.  That being said, you don't need to be overzealous with dividing your surfaces into grid units.  If your 4-units-wide object doesn't need inner edge loops, take them out.

Below is an example of one of my objects, a torch.  In-game it is only 32 units tall, so I used a scaling number of 4 to allow me to actually add some detail to the model.  Note that each piece aligns with a whole number of units in the grid-- the top piece is 2 tall, the middle 2 tall, and the bottom 4 tall.

Note that the top does need to be completely divided, but the side doesn't need as many
horizontally-running edges, thus they were omitted.

When you're done modeling, don't forget that you need to move your pivot and rescale your model.  For the pivot, I recommend placing it in a spot that will make it easy to place the object within UDK.  The pivot on this torch is kind of arbitrary considering the way I'm using it.  For my pillars, however, I placed the pivot at the bottom corner of one side, placed in such a way as to ensure snapping it to the grid in UDK will make the bottom meet my floor.  After you place the pivot, snap the entire object to the very center of your grid.  Then scale it on all axes by your scaling number so that it will become the size you want it to be in UDK.  I've been exporting my models as FBX files-- if you do, too, make sure that "smoothing groups" is checked in the export options.

Finally, import the model into the UDK editor.  If you need to make changes, updating the model is as simple as re-exporting it, right-clicking on the mesh in the Content Browser of UDK, and selecting "re-import."  We will most likely be using this extensively in the texturing phase.


Part Three: how the hell do I texture this thing?

This is the part of my overview where I still do things wrong from time to time, so please bear with me as I revise the section for clarity.

Remember that magical scaling number I keep carrying on about?  This section will make it clear as to why you might want it to be consistent for every model you make.  However, it may also confuse you as to what this number actually means, as it seems that our assumption that 1 UDK unit equals 1 Maya unit equals 1 pixel was not quite accurate.  I'll try to explain as best I can despite not fully understanding it myself.

Using our assumption of a 1:1:1 unit ratio, our scaling number becomes the number of pixels wide and high each unit square in Maya is equal to.  Below is an example using a pillar.  The background is a grid of 8 x 8 pixel squares in a 256 x 256 image.  In-game, this pillar is approximately 64 x 64 x 256 units.  I used a scaling number of 16 when modeling it, so I modeled it as a 4 x 4 x 16 and then scaled it up when exporting it for UDK.

Using the entirety of your UV space doesn't really work when you want things
a uniform size.  That's my story and I'm sticking to it.

If everything is 1:1:1, shouldn't one square on the grid be 16 x 16 pixels-- in this case, a 2 square x 2 square chunk of our grid image-- considering our scaling number was 16?  I thought so too.  Unfortunately, BSP seems to use a different scale, where each unit is only 8 x 8 pixels when compared to my 16 x 16.  In other words, pixels seem to appear twice as big on BSP as they do on your meshes.  If you're not using BSP, this is pretty much irrelevant and you can continue along your merry way without worry.  If, like me, you are using it, you just need to decide which way looks better to you.

To continue my explanation, I'll choose the scaling number 16 to be the correct representation of how many pixels high and wide a Maya unit square should be.  Open up Photoshop and make a grid image like the one shown, except using 16 x 16 pixel blocks.  Use this to scale your UVs so that each Maya unit square aligns properly with a square in said grid image.  Below is an example using a sconce.  In UDK, it is 64 x 48 x 64; using my scaling number of 16, it became 4 x 3 x 4 as I modeled it in Maya.  Each square in the grid image should be 16 x 16-- here it's 8 because I was doing it wrong and didn't realize it until I had figured out the inconsistency I discussed in the previous paragraph, so just pretend it's 16.  I modeled it as a series of Maya unit cubes since the design was simple.  Since our scaling number says each of those units should be 16 x 16, we needed to scale the UV map so that each unit matched the squares in the image grid, like so.

These UVs will be twice the size when I revisit this mesh, as I was scaling incorrectly-- the image grid
uses 8 x 8 when it should be 16 x 16.

If you run into a situation where your scaling number is different for a certain mesh, you'll need to keep this in mind while adjusting its UVs.  For example, the torch had a scaling number of 4, so each of its Maya units are 4 x 4 pixels.  Compared to the sconce above, where a Maya unit is 16 x 16 pixels, the units are 1/16 the size.

The sconce is on the left, and the torch on the right.  The torch UV is a fraction of the size of the
sconce UV, but the pixels in the end result appear the same size.

You may have noticed that I'm overlapping a lot of UVs here.  With some of my meshes, this will be necessary to ensure everything can be scaled properly.  With others, it's to save me time when I actually make the texture.  This is one of those decisions that depends on what suits your needs best.

When scaling and aligning to the grid image, be careful of the edges.  They should fall as precisely between each square as possible, or else you risk having the edges bleed a little because they'll be encroaching on additional pixels.  This is where UDK's ability to re-import a mesh with a couple clicks becomes very useful.  If your texture doesn't look quite right in your UDK preview because a UV is slightly askew, you can fix it, export the changed file to save over the old one, and then re-import it pretty quickly.  I did this a dozen times while working on my torch texture, as its parts were too small for my grid image to be useful and I kept misplacing the UVs.

Updated 20 Nov, 2013  I have discovered a way to make aligning the UVs a lot more precise.  Thanks to this tutorial on lightmaps from World of Level Design, I was able to set my UV editor grid to actually do something useful and represent pixels.  This information is at the bottom of their tutorial.  Once you have a pixel-sized grid set up, you simply need to snap all your UV edges to said grid.  If you used square/blocky models like I did, this will be super easy-- you can resize everything just by snapping instead of trying to uniformly scale all the UVs in one go.  Nifty, eh?  I'm still getting the occasional edge bleeding, but I suspect this is inevitable with UVs.

Updated 26 Jan, 2014  So it turns out that while snapping the UVs to the grid gets you most of the way there, snapping to pixels is actually an option in the UV editor and it seems to take you the rest of the way.  Once you've sized everything properly using the above technique, come back through for one more pass, this time with "snap to grid" turned off and "pixel snap" on, like so:

Note that "pixel snap" is inside the UV editor window

Once you have the UVs aligned so that they won't chop any pixels in half, you can save them out for use in Photoshop.  If you haven't already, don't forget to export the updated model and re-import it in UDK, or the UV mapping won't be there.  Here it is also important to pick a resolution that won't require stretching.  For example, I have one large mesh that is nearly 512 x 512 units.  Using a texture on it with a resolution of 256 resulted in blurry pixels because of the way the texture had to be stretched across the mesh.  However, the rest of my meshes so far have been fine with textures of a 256 resolution, as they are all 256 units or smaller along their 3 axes or have UVs that can be arranged to fit a 256 comfortably.

Hopefully I don't have to tell you how to use Photoshop.  Just give it a lovely pixel texture and save it out.  I am still not sure what the best file type to use is.  Some textures have looked fine using .TGA at 32 bits/pixel, but others suffered from noticeable artifacting that only went away when saved as a .PNG with no compression.

Getting the texture into UDK is just as easy as with any other.  There is one setting you need to change on each one, however.  Double-click on the texture in your Content Browser to pull up its info menu.  The option labeled "filter" needs to be set to "nearest" to prevent it from making your pixels all blurry.

The only setting I have messed with so far.

With a little luck-- and if you're clumsy like me, a lot of cursing-- you should now be able to add the texture to your model using a material and then step back and admire your handiwork!


A quick note on particles

I find particles to be a lot of fun, so I can't imagine skipping them in this overview.  Pixel art particles don't take much more than regular particles, really-- just remember to set the filter to nearest on the texture and you're good to go.  I personally have been using .PNG files ranging from 1 pixel to 8 x 8 pixels, adjusting the size as needed within the particle effect's options menu to make it look pretty.  If you haven't made a particle effect before or need a refresher, this really brief video series covered everything I needed to get a fire particle up and running.  My "flames" are just a tear-drop shaped red-orange-yellow thing and my "smoke" is just a 3 shades of grey block.

Simple yet effective, I'd say.

Wow, this was a long-winded post.  Congratulations for those of you who made it through.  I hope this helps someone out there get some awesome-looking pixel art into their UDK project.  If you have questions or comments, please let me know!

Updated 7 Jan, 2014  Rendering these models in Maya

If you've tried to render any of these models in Maya, you may have noticed that they are horribly blurry no matter what rendering settings you try-- in vain-- to change.  This is because Maya is dumb and just assumes you want an ugly filter on any images you use in your shaders.  To remedy this, click on the shader you're using as your texture and follow its color node until you find the file settings.  At the top of these settings, there is an option called "filter type."  Set that bastard to "off" and you should suddenly have nice, crisp renders!  To get the same effect in your viewport, hit the "shading" menu in the viewport's options, click on the little box next to "hardware texturing," and set the filter there to "unfiltered."  Better?  Good!  (I now have a blog post dedicated to this problem-- click here to see some diagrams showing where these settings are!)



No comments:

Post a Comment