Depth editing and imminent update

Hi folks. Just another Sprite Lamp progress report. Before I go into that, I want to give a shout out to two projects that are on Kickstarter right now that are making use of Sprite Lamp. First off, Hive Jump – a 2D shooter with local co-op, and with plenty of dynamic lighting to show off. Secondly, Elysian Shadows, an RPG with some next-gen lighting techniques – they’re not as far along with their Sprite Lamp usage but I’ve been in touch with them about it and they’ve got some sweet stuff planned. Both projects seem to be kicking some arse already funding-wise but you should still go and check them out.

Next Sprite Lamp release

So, I said in my last update that it would be the last time I do an update via the moderately dodgy dropbox link method, as I’d be moving to Steam. I was hoping to make good on that plan, but getting up on Steam is taking me a little longer than expected, and I’m currently sitting on some features that I want to put into backers’ hands sooner rather than later. As such, there’s going to be one last pre-Steam release, and it will be some time over the next few days. This also means one more release with a dodgy not-so-useful Mac version, unfortunately, but see below for some more encouraging news on that front. I’ve been hard at it on the features though, so this next update should be a good one. For everyone, it will contain the Spine integration that I mentioned a couple of posts ago, which is already pretty cool. For pro users, it will also contain the long-promised depth editing system, which I’m about to talk about. There are also a couple of other small improvements and tweaks to things I noticed needed fixing along the way.

Depth editing tools

As mentioned, this is a pro-only feature. Just wanted to get that in early to avoid any disappointment. One of the major things I’ve been working on is a system for editing and fine-tuning depth maps after Sprite Lamp has created them. As you might know, Sprite Lamp is primarily for creating normal maps, but can also create depth maps from them. However, there isn’t enough information in a normal map to create perfectly accurate depth maps, and in some cases the results could use some tweaking (particularly for elaborate character art or other complex objects). Drawing depth maps from scratch is a pain, though, so I wanted to add tools to build on what Sprite Lamp has created so you can get good results without loads of work. Sprite Lamp’s workflow for tweaking depth maps is roughly as follows:

1. Select edges between pixels where there is a depth discontinuity.

2. Select pixels in the depth map – a process which is aided by the edges from step 1 – that are at the wrong depth (say, the pixels of an arm that need to be brought forward).

3. Move the selected pixels forward or back until they’re in the right place.

4. Repeat until things are as you want them to be.

The depth editing interface looks like this:

DepthEditor

In the preview window you can see the place where you actually interact with the image. The red lines are the edges between the pixels. The cyan lines are contours (their display can be toggled) which helps you see problems with the depth map. Edges can be detected based on various things (such as sharp changes in the normal map or the diffuse colour), or painted directly with the mouse. Selection is also painted with the mouse, although factors such as softness can be controlled, as well as only selected pixels of similar depth to where you started (important for selecting creases and the like). Selection is necessarily soft, because if you have a hard-edged selection and pull bits of it forward and back, you’ll get a big step in the depth function, which isn’t usually what you want.

You’ll also notice that there’s an undo and redo button, which kind of goes without saying with tools like this, but I still wanted to mention it because it was such a pain to implement.

I’ve since gone back to some of the Sprite Lamp test artwork that caused problems for the depth generation algorithm and done some work with the depth editing tools, and so far it has taken me very little time (usually five to ten minutes of messing about) to get things to a good state. I admit I’m not all that sure how many of Sprite Lamp’s userbase will be making extensive use of this feature but I think those that want it will be pleased with the results.

Progress on the Mac port

One of the reasons I haven’t been super talkative about features recently is that I’ve been working on some major refactoring. For the non-programmers reading this, ‘refactoring’ is another word for ‘working really hard and producing no visible results’ – in other words, I’ve been reorganising the guts of Sprite Lamp rather than adding features. This is to make things as quick and painless for the Mac port, which I’m pleased to say is now underway. I mentioned it was underway last time I think, which it was in the sense that I’d confirmed with Rob that he wanted to work on the project and he was looking over the code. Now it’s underway in the sense of code is being written and the MacOS UI is being built. This is pretty exciting for us over here, since Halley (who you may remember as the artist who has done pretty much all of Sprite Lamp’s sample art from the Kickstarter and these blog posts) is a Mac user and is very much looking forward to getting a real copy of Sprite Lamp up and running on her machine. I know there have been some people hanging out for the native Mac version, so I hope the news is good for them too.

Remaining features

The list of tasks remaining on Sprite Lamp isn’t empty, but it is getting pretty short (note that I’m not talking about engine integration stuff for the moment – there’s certainly plenty of work left to do there). I’ve still go a few things I still want to add, though, and I wanted to give people some idea of stuff that is still coming. Two major-ish features that remain on the list, both pro features, are the ability to load custom shaders for the preview window, and the ability to export a mesh based on the depth map you’ve created. Another feature that I really want in is the ability for all the map generation functions to be interruptible – currently they just block Sprite Lamp, which is fine for pixel art because they take a fraction of a second, but it’s a bit awkward having Sprite Lamp basically hang for ten seconds or so while a higher resolution image processes – I’d much rather there was a progress bar and a cancel button. That one’s a substantial task, but I think it would seriously improve the user experience and the usefulness of Sprite Lamp, especially when you’re experimenting with different settings. I also have a few features that aren’t accessible to the command line interface yet that I need to add, namely anisotropy map and palette creation. Finally, if people want it, I’m still up for making a native-looking UI for the Linux build. I feel less urgency on this one, because the Linux implementation of Winforms is actually really stable and responsive as it turns out, but unless people overwhelmingly don’t care, I’ll get to it.

At this point, though, I think that as far as 90% of users are going to care, Sprite Lamp is feature complete, and for the other 10% of users, Sprite Lamp is very close to feature complete. For that reason, I’m going to focus on getting everything aligned for the Steam release and the mac port, and then dive into the more complete engine integration – the features I’ve just mentioned will come after that. I just wanted to mention them in case anyone was worried I’d forgotten about them.

Posted in Sprite Lamp | Tagged , | 1 Comment

Sprite Lamp release plans

This is the post where I talk about the near future of Sprite Lamp and releasing on various platforms. Yesterday I posted about Spine integration, and I’m also working on the tools for editing depth maps. There are a couple of other smaller features I’m hoping to have added at some point, such as loading of custom shaders, but when the depth editing is done, Sprite Lamp (the standalone application, for Windows) is getting startlingly close to finished. Given that, I’m going to try to make the next release a Steam release. Fingers crossed, I can make this happen in something like the next couple of weeks.

Questions of Steam early access

I’ve given a lot of thought to early access, because I have slightly mixed feelings on it in practice. I don’t want to be ‘one of the bad ones’ – I feel like there’s a certain amount of frustration going around with certain early access projects for various reasons, and I don’t want Sprite Lamp to be one of those.  On the other hand, betas are useful for various reasons, and a platform like Steam is a good way of carrying them out. There can also be hiccups in the implementation of being on Steam itself – it’d be nice to have a chance to make sure Steam-specific things work (for instance, upgrading from hobbyist to pro will be done using the DLC system, I need to make sure that works smoothly) before it goes to a bigger audience.

So I’m pretty open to suggestion on this strategy, but currently I’m thinking of trying to get the Windows build out as a closed beta (which will involve me trying to get Steam keys to everyone who has already got Sprite Lamp by Kickstarter or through PayPal). Once that’s sorted, we’ll go into early access – at that point, it’ll be at the current (slightly) discounted Kickstarter/early price of $35/$90. When it releases fully, it’ll be for $40/$100. I’m going to try to make this early access period as quick as possible, though. During the early access period, I’ll also try to get a maximally polished Linux build onto Steam. The current Mac build isn’t really Steam-ready, though – a fact probably known to those who have tried using it. That brings us to the next section.

Sprite Lamp for MacOS

For a while I’ve been in contact with a fellow I know by the name of Rob Caporetto who was potentially going to help me out with the native UI version of Sprite Lamp for MacOS. He’s got some experience with MacOS and C#, which isn’t the most common combination of skills, so it seemed pretty ideal. Unfortunately he wasn’t free to work on stuff until fairly recently, but I’ve been in contact with him and he’s had some time to look over the source code. We’ve talked about what needs to be done and how to do it, and come to some conclusions:

  • It’s probably not worth holding up the other releases to wait for this one. I didn’t make this decision lightly, because I had always wanted a simultaneous release, but at the same time, it seems pointless to keep a working build out of Windows and Linux users’ hands just for the sake of that (especially when those two groups are likely well over half the users).
  • There’s a small amount of work for me to do on the codebase to get it ready for porting, which I’m going to jump into as soon as the depth editing stuff is done.
  • It’s probably somewhere in the ballpark of a month of work. As such, I’m going prioritise doing as much as possible of the port stuff myself, especially the grunt work, and Rob can spend all his time on the hard bits. That way it’ll be in Mac users’ hands as soon as possible.
  • More than was the case with the rest of the development, we’ll be able to prioritise the adding of features so that the most commonly used ones are in first, and as soon as we have something pretty usable, we’ll put it out there (on Steam, if we’re at that point by then, or otherwise in a regular update).
  • More as it develops.

So, that’s that. I’m pretty damn excited to see the first build working on MacOS, but not half as much as Halley is (being the artist behind Sprite Lamp’s sample art, and a mac user).

More engine integration

The other part missing from this story is the future of engine integration. More than any other part of the development of Sprite Lamp, engine integration has taken me off guard scheduling-wise, because it’s hard not to get tangled up in small details when you’re working with unfamiliar tech. However, once this next release is sorted, I’ll be able to get into doing some of the integrations closer to full-time. First priority will be Unity since so many people use that, then I’ll look at rejiggering some of the Game Maker stuff, and then basically I’m going to go through the history of people requesting engine integrations and try to get as many sorted as I reasonably can. So far I’ve been including engine integration stuff with Sprite Lamp, but when there’s a bit more complete I’ll be making them all available for free download here.

Posted in Sprite Lamp | Leave a comment

Sprite Lamp and Spine

As I’ve mentioned recently, I’ve been playing with Spine and Sprite Lamp. It’s time to talk a bit about how that’s going and what it means.

Spine files in Sprite Lamp

The main thing I’ve been working on lately is loading up Spine files in Sprite Lamp, so you can view them, animated and dynamically lit, in Sprite Lamp’s preview window. And, it’s working! It looks something like this:

Sprite Lamp with an example Spineboy animation loaded

Spineboy artwork and animation is from Esoteric Software, with our own lighting profiles/normal maps applied.

As you can sort of see from the screenshot, the interface is not terribly complex – you load up a .json file and you have your character. You’ll also need to (draw and) load up lighting profiles in atlas form (if the files are named properly Sprite Lamp will automatically grab them), and then off you go. You can select any animation in the Spine file and also select different skins. You can also control the speed and direction of the animation playing.

The walk is a bit slower than I’d like, perhaps, but here’s an illuminated Spineboy, with a static light to make it easier to see what’s happening:

Spineboy walking with dynamic lightingThere’s a certain amount of dodginess regarding the bending of the knees, though for artwork that was made without dynamic lighting in mind, I think he came out pretty well. The fact that this is truly dynamically lit, rather than just faked, is most evident on the parts that are rotating the most, particularly the right hand.

The intricacies of rotating normals

It might be helpful, particularly for programmers, to have a bit of a grip on the maths behind this kind of thing. If that’s not your bag, you might want to skip this section.

It’s tempting to think that all you need to render a normal-mapped Spine character is the ability to render a normal mapped sprite combined with the ability to render a conventional Spine character. Unfortunately, the rendering side is slightly more complex than that (NB: I’m just talking about the shader maths here – these complications are not the artist’s problem).

Naturally, rendering a Spine character involves moving and rotating various images about. This is nothing special – rotating a textured quad is something computers have been able to do happily for decades, after all. You paint your character’s leg image or whatever, then you rotate it, and you’re all good. However, when normal maps become involved, things get slightly more complex. If a normal map has a pixel that encodes a vector that faces to the right, and you rotate the whole image 90 degrees clockwise, that pixel should now be facing down. But, its colour hasn’t changed – it still encodes ‘faces to the right’. If you rotate it another 90 degrees, so it should be facing to the left, it still appears to be ‘facing to the right’. This problem gets worse the more the character rotates. Some Spine enthusiasts reading might remember ages ago when Sprite Lamp was in its Kickstarter phase, we had a few shots at Spineboy walking around with dynamic lighting. If I recall correctly, this problem was present in those demos. It was very subtle, because no part of Spine Boy rotates a huge amount during his walk cycle, but it was there. Fortunately, the solution is not terribly complex – you simply have to tell the shader how much each body part has rotated from its default position, and rotate the normal by that amount in the pixel shader Done!

But, you might justifiably be wondering: what of soft skinning? After all, the fine folks at Esoteric Software have been hard at work following their recent Kickstarter adding soft skinning and free form deformation (FFD) to Spine. It’s not obvious what it means to refer to ‘rotation’ when the rotation of a point is going to vary throughout a mesh. And, indeed, this does get a bit more complicated. For Sprite Lamp, I’ve decided to go with a fragment-shader solution to this problem. It involves using the derivative functions in GLSL to compare the the world position and UV coordinate of a fragment with its neighbouring fragments, which enables you to calculate a thing called a TBN matrix (tangent, bitangent, normal). When this release comes along, I’ll talk a bit more about how this is done in the shader. The takeaway is that in the next release, Sprite Lamp should smoothly handle all the different types of animation Spine can throw at it – textured quads, but also soft skinning and FFD. As a demonstration/stress test, Halley has cooked up a slithering snake animation. She wanted me to make it clear that this is not her best work and she’s not very experienced with Spine animation. As far as a clear demonstration of variable rotation on a soft-skinned mesh, though, this does nicely:

Snake slithering to the leftYou can see here that with the light source on the left, the coils of the snake are picking up the lighting correctly as they wave. It’s not obvious for all animations when the normals aren’t being computed correctly, but in the case of this snake it’s something of a stress test.

Spine and Sprite Lamp in your game engine

So, so far the work has been on getting Spine animations displaying in Sprite Lamp. You might be wondering when you can actually put this in your game.

Unfortunately, the answer to that depends on a bunch of factors. I’m only one programmer, and the crossover between Spine and Sprite Lamp is only one of the many parts of Sprite Lamp. Once Sprite Lamp is out (like, out out, not in alpha like it is now) I’ll be able to give a much more thorough look into engine integration. My policy with Spine will be similar to my policy with the rest of Sprite Lamp’s engine integration: I’ll do as many as I reasonably can myself. Since there are a lot of engines in the world, and I can only cover a few of them, I’ll also do my best to document everything you need to know as a programmer to get things working yourself, be it in an existing game engine that I haven’t been able to cover, or in your own hand-coded system.

That all being said, somewhat predictably, my priorities towards the most widely-used engines will remain, meaning Unity will be first on the list. I’ll be posting more of that as I know it.

Posted in Sprite Lamp | Tagged , | Leave a comment

Unity Palette Shader first pass

Hi all,

You know how sometimes, after you’ve been working on some important thing, you get sick after you finish it? Like your body was holding off on getting sick until it could get away with it? Maybe it’s just me, but either way, I got sick right after putting the new version of Sprite Lamp out there. Anyway, sorry it took me a few days, but here’s my first crack at the palette shader from Sprite Lamp, in Unity form.

ZombiePaletteUnity

Come for the palette zombie, stay for the flawless framing of the screengrab.

 

A couple of important things to note:

  • It basically works as you’d expect, I think. Put the textures from Sprite Lamp in the appropriate texture slots on the material and you should be good.
  • Currently it makes use of the diffuse map, just to get the opacity value from it. The obvious thing to do is put the opacity in the index map’s alpha channel, but since Sprite Lamp doesn’t output them that way automatically yet, I made the shader so it works readily with what Sprite Lamp exports.
  • You can get some very crappy results if you don’t load your textures in as ‘uncompressed’. Compressing the palette map in particular will pretty much make everything awful (or at least, that’s what happened when I tested it).
  • The palette system is designed to work without coloured lighting. I might hack something in later that just multiplies the output by the light colour, but that kind of misses the point of having close artist control over what colours are rendered to the screen. Ultimately, if you’re making use of the palette system, the key is to set the lighting mood via the palettes.
  • Since this is a straightforward shader-based implementation, it makes use of simple additive lighting to handle multiple lights. Technically, this isn’t quite correct, but I think for most cases it should look fine. I hope to work on a more complete and correct approach to this in the future, but it might get a little hairy (might require something resembling a deferred rendering pass). I’ll go into some detail later as to how this might work.

Anyway, that’s it! As you can probably guess, this shader is a work in progress, and will change in the future – both in terms of how it works under the hood and how you use it as a developer. Let me know if it’s giving you trouble, failing to compile, or if it’s not clear how to make use of it, and I’ll try to straighten things out.

Posted in Graphics, Programming, Sprite Lamp | 2 Comments

Sprite Lamp’s palette system

Yesterday I released the latest update to Sprite Lamp, and with it, a properly implemented and documented palette system. Still pending are shaders for various engines to make it usable in your games, but in the mean time, I’m going to give a quick rundown of what it is, how it works, and how the (really pretty simple) shader works.

Why palettes?

This is something that came up due to repeated requests from artists. As a graphics programmer, my first thought was to calculate the light based on the angles of the light and the surface normal using standard Lambertian and basically call it a day. However, as several artists pointed out to me, this means that when a part of an image gets darker it approaches black, and artists very rarely use real black in their paintings. Shadows are more likely to have some blue to them, and highlights are likely to be slightly yellow rather than white. There are various ways to get around this – tweaking the ambient and direct light colour, for instance – and while those options remain, I thought it would be good to give artists more direct control. Hence the palette system.

This works by taking the diffuse map (that the artist creates), taking all the unique colours from it, and creating a sort of template palette image. This palette is then saved out and modified by the artist to get the effects they want. A palette image has a vertical column of pixels for every unique colour in the depth map. The vertical position in this column represents the colours that those pixels will be at different lighting levels. The midpoint of each column is the colour when that pixel is lit with full diffuse lighting but no specular lighting. Below that it fades as the diffuse lighting drops away to nothing, and above that it represents the colour when an increasingly strong specular highlight is added. Sprite Lamp can be used to generate either an ‘empty’ palette that will create flat lighting (the columns are the same colour all the way up), or a palette that will produce simple calculated lighting, fading to black at the bottom and white at the top.

As an example, here is the diffuse channel of the Sprite Lamp zombie:

Diffuse image of a zombie

And here are the autogenerated palettes for said zombie (with and without default lighting built in):

EmptyAndDefaultPalettes

From here, you save one of these images out (whichever would work best for you as a guide) and then change the colours as you see fit. The only really important thing is that you generate the index map (more on that later) and then make sure you keep the horizontal positions of the pixel columns in the same place/order in the palette.

Here are some examples of effects that are possible using this system, with the zombie’s palette image visible on the inset.

ZombiePalette2

This is a simple case of adding some blue to the shadows and some yellow to the highlights to add some depth to the result.

ZombiePalette3

In this image, we’ve done something like a traditional palette swap, to make a different colour scheme entirely.

ZombiePalette4

This one makes use of the Dawnbringer palette – it uses fewer colours and gives a more retro look.

The Shader

So, as promised, I’m going to give a quick outline of how the shader works. It’s actually not very complicated, but it hinges around something that Sprite Lamp will generate for you, called an index map. You’ll need a normal map, as usual, and then a diffuse map, and from the diffuse map Sprite Lamp will generate the palette map template (which you then modify) and the index map (which you don’t). The index map for the zombie looks like this:

zombie_Index_Bigger

The grey values in this image are actually a value from 0-1, representing the horizontal position in the palette map where that column of colours resides. Black represents the leftmost column of the palette map, then the second darkest grey (the hair) will be the second column across, and so forth. This is why it’s important to keep the columns of the palette map in the same place.

As the shader programmer, all you need to do is calculate some lighting value between zero and one (the way Sprite Lamp’s palette shader does this is by averaging the diffuse and specular components and then clamping to the correct range). Then, a look up into the index map will get you a luminosity value between zero and one. From there, you do a look up into the palette map, using the value read from the index map as your U coordinate, and the calculated level of illumination from your lighting algorithm of choice for the V coordinate, and you have your final colour. Because the whole point of the palette system is to give the artist precise control over the colours that end up on the screen, nothing more is done – the colour is outputted onto the screen. The pseudocode for the shader might look something like this:

float colourLevel = (diffuseLevel + specularLevel) * 0.5;
float indexPosition = tex2D(indexMap, textureCoords.uv).r;
//Note that we use 1.0 - colourLevel because usually positive V
//goes down the texture map.
vec3 finalColour = 
         tex2D(paletteMap, vec2(indexPosition, 1.0 - colourLevel);

The generation of the index map

For the most part this isn’t something you’ll be worried about, but there are certain circumstances where it’s important to know the details. Sprite Lamp generates a palette map from the diffuse map to use as a template, but then it generates the index map from the diffuse and the palette maps. It does this by going through every pixel of the diffuse map, and then searching for that pixel’s colour in the middle row of the palette map (that is, it looks through the row of pixels half way down the palette map). When it finds the colour it’s looking for, it will use the horizontal position of that to determine the greyness of that pixel in the index map.

This probably isn’t terribly relevant to most use cases, but it’s possible that you will want to use a palette map for more than one piece of art in your game (to render a whole scene coherently, for instance). In that case, you’ll want to make your own palette map from scratch, making sure the important colours are present all the way along the centre. Having done that, paint all your diffuse maps using only colours from that centre row of pixels. Then, load up a given diffuse map, and rather than generating a palette from it, open up the palette you made into the palette map, then click the ‘generate index’ button. If the diffuse colours are all present in the palette’s central row, Sprite Lamp should generate a fully functional index map without issue – it doesn’t matter that there are colours in the palette not present in the diffuse.

Conclusion

I would imagine that this problem has been tackled by other developers at various points through gaming history – this approach is just what came to mind to answer artists’ complains about black shadows. Given that, this explanation is straight from my brain to the page, as it were. Please, let me know if there’s anything I’ve been unclear on, so I can fix my explanation.

More importantly, if you do anything cool and unexpected with this system, I’d be keen to see your work. I’ve already been surprised/impressed with Halley’s implementation of the Drawbringer palette from above, and I’m confident that various cel shading and other techniques are possible using this system too.

Posted in Graphics, Sprite Lamp | Tagged , , | Leave a comment

Sprite Lamp: A minor update and apology for lack of communication

Hi all,

I’m coming at you a bit humbly today, because a comment someone made to me recently called me on being behind in my schedule and generally not telling people what’s up.

I’ll start by saying that this isn’t the dreaded “Sorry, this project isn’t going to happen” post. Sprite Lamp has been and continues to be in development, and all the promised features are on their way.

What this post is, is me apologising for being less productive than I would have liked over the last two months, and not being very communicative about that fact over that time. I have been in the US recently – for personal reasons I won’t go into, it would have been awkward for me to not go on the trip, so I convinced myself that I could just take my laptop and keep up work on Sprite Lamp while I was there. As it turns out, this was kind of foolish on my part, and in retrospect I should have just stayed home. I did keep working while I was there, but productivity has been lower than I hoped, and I haven’t been very good at keeping you all up to date on this. The current state of play is that I’m working on a few things for the next alpha release – UI overhaul, functional/usable palette system, updating some issues with engine shaders, and updated documntation are all coming.

The other thing I haven’t communicated about well is release dates. Initially, I stated that Sprite Lamp would be out approximately now. This was when the Kickstarter was initially written, and it was a small project without any stretch goals. It’s grown beyond that, and of course the stretch goals were things that I hadn’t done any development on, some of which have turned out to be slightly rabbit-hole-ish. At this point I’m hoping for one last alpha release in a week or so, and the first beta release in about a month.

So having said all that, I’m now back home and in a much better state to work in an undistracted fashion. I’ve always been a bit shy about social media and the like, but I’m going to put in an extra effort to be forthcoming on that front, too. For now, I figure the best way to make amends is to get right back into coding, so that’s what I’m going to do.

~ Finn

Posted in Uncategorized | 2 Comments

Per-texel lighting

So, I’ve been pretty negligent about documenting this one last feature in the Sprite Lamp shader. It’s rather obscure and difficult to explain, but I’m going to try to overcome that with pictures.

Pixels, texels, and fragments

These three things can get pretty confusing during the coming article, so I wanted to clear a few things up.

You’ve probably heard of pixel and fragment shaders, and observed that they’re basically the same thing. Well, they are. Technically, I believe, the correct term is ‘fragment shader’. A pixel (‘picture element’) is a single tiny rectangle of colour on a computer screen, whereas a fragment is also depth information and a few other things. A fragment might never become a pixel, because it might fail a depth test or whatever. The wikipedia page on fragments is a bit helpful. Either way, it’s good to know the difference, but this isn’t the most important distinction.

The distinction between a pixel and a texel is more important, especially if you’re a pixel artist. In a sense, I suppose, you could be described as a texel artist – texel means ‘texture element’ – basically, it’s one of the coloured rectangles that make up a texture. This is relevant because sometimes you draw a texture to the screen at a size other than its native size – in fact, in 3D games this is almost always what happens. That’s what filtering is for – bilinear filtering, for example, is a maxification filter – a way of zooming in on a texture – without it appearing blocky.

Per texel lighting

This is probably nothing new to artists who are used to working with computer graphics. The point is, when you’re viewing pixel art such that it is deliberately blocky (using nearest neighbour filtering (aka point filtering)), each texel is made up of many pixels. That is, each pixel in the source art is blown out to be many pixels on the monitor. This is the important thing to understand, because when a fragment shader operates on this artwork, it’s doing a lighting calculation once per pixel, NOT once per texel.

The result of this is that, even with the diffuse/normal/everything maps set to nearest neighbour filtering, you end up with colour variation within a texel. Almost always, this is imperceptible and doesn’t matter. However, when combined with cel shading, you can run into trouble. Here’s an example of what I’m talking about:

TexelVersusPixelBecause I have been staring at this kind of thing for a while now, it’s hard for me to tell how obvious the difference between these two images is. If it’s not immediately apparent to you, the point is that the image on the right has diagonal lines – discontinuities in the lighting level – running across texels. The image on the left could just be pixel art with static lighting – the image on the right definitely isn’t. This problem becomes less clear if the lighting is changing rapidly, but more clear if the light source is moving, but slowly. To me, and I daresay to various pixel purists out there, this is a problem worth fixing.

As you can see from the screenshot above, this has been solved in the Sprite Lamp shader. However, Sprite Lamp’s preview window makes this problem easier to solve than it is in the general case. I’m still working out the details of solving the general case, although I’ll document them carefully in the Unity shader so it can be reproduced elsewhere.

Until then, though, I have a question for anyone reading – would this feature be important to you? As mentioned, to me the visual problems are obvious, but I can understand that for many they wouldn’t be. Of course, it’s not relevant for high res art, and it’s mostly not relevant for low res art either unless there’s cel shading involved. Even then, arguably the problem being solved is fairly subtle. I’m curious to hear your thoughts.

 

Posted in Graphics, Programming, Sprite Lamp | 6 Comments