SyntaxHighlighter

Saturday 17 December 2011

2D Lighting System tutorial series: Part 1


2D Lighting system tutorial series

Welcome to the first in a series of blog posts that are going to walk you through the creation of a fully featured 2d lighting system to use in you games. The system focuses on creating soft lighting and shadows that can be cast by any arbitrary sprite in your scene.
For a preview of the kind of system we'll be creating, have a look at the following video:


The video quality isn't great as I only have the free version of fraps to record with, but hopefully it's given you an idea of what we are working towards.

For those of you who are already comfortable with shaders and digging around in other people's source code, I've uploaded the full source to both the lighting system and a basic sample that creates 2 different colored spotlights and lets you move them around the scene:


For the rest of you, in this post I'm going to set out what we'll be covering in the rest of the series.

The series will be split into 9 (fingers crossed!) parts:

1) Introduction, and series contents.

2) Introduction to shaders and the LightBlend shader.

3) Structure of the lighting system, overview of the algorithm, and the LightRenderer class.

4) Point lights: 'Unwrapping' the shadow casters, and creating the occlusion map.

5) Point lights: Lighting the scene.

6) Blurring Creating soft shadows.

7) Spotlights: 'Unwrapping' the shadow casters part 2.

8) Spotlights: Lighting the scene and soft shadows.

9) Conclusion: Optimisations for the future.

I'll try and keep each part to a manageable length, but there is a lot of material to cover, so they may be a couple of long posts along the way!

Tumbleweed

Well, what a surprise! Yet another massive hiatus in updating my blog.

For the last few months I've been in something of a rut. I started designing maps for the-game-formally-known-as-Sphero, and found myself lacking motivation. I was clear in the experience I wanted to player to have, but I was struggling to convert that into what I thought would be compelling puzzles and an interesting environment to traverse. I'd also stopped programming, which is the bit of game development that I enjoy more than anything else. 

As a break I decided to work on a side project. I started off by starting work on a 2D lighting engine, based very loosely on the same principle as the one described by @CatalinZima here: http://www.catalinzima.com/2010/07/my-technique-for-the-shader-based-dynamic-2d-shadows/ 

I had some innovative ideas to improve the approach, and I thought it would be a good short break from designing. Also, I've always wanted to play around with shaders and write some from scratch based on my own ideas, so this seemed a great place to start. I also thought it would give me the coding fix I needed, and let me recharge my batteries for a fresh run at designing Sphero levels. 

Unfortunately, I encountered a few tricky hurdles, and ended up with some very stubborn bugs in my shader code that left me stranded once more, mid-project, with no momentum. Rather than persevere, as I should have, I let myself get distracted by Ludum Dare.

For those of you who don't know, Ludum Dare is a quarterly, 48 hour game development competition. There are no prizes, just prestige. Participants vote on the theme in the run up to the competition, and the theme is announced at the start of the competition. I'd been toying with a new, very simple, mobile game idea for a while, and this seemed like the perfect opportunity to prototype it, if the theme fit. The theme that particularly fit with my idea was 'Escape'. So I up-voted escape and decided that I would only compete if that ended up being the theme. I'm not sure whether I expected it or not, but when I awoke on the morning of the competition, low and behold, the chosen theme was 'Escape'.

So I stuck to my guns and dived head first into creating the game idea that had been brewing in my head for a week or so. The premise was simple. You have balls falling through space, and by tapping on the screen you create small black holes, the gravity of which alters the ball's path, the goal being to alter their path so that they hit an 'exit' portal. When all of the balls have been deposited in the exit portal, the player has passed the level. Any balls that get sucked into one of the black holes reappear at the top of the screen again. 

In my head, this seemed like a pretty simple game. I decided to use XNA and Farseer for Ludum Dare, with the intention of porting to IOS later if I liked the game. 

Even using APIs I was familiar with, I failed miserably to create anything playable in the time limit. There were other distractions, but the main reason was that I completely underestimated how difficult it would be to code everything from scratch. 

Despite this, I still thought that the game had potential, so I carried on with it after the competition. Some readers may have noticed a pattern emerging at this point, but I won't spoil it for those that haven't figured it out yet!

I ended up spending over 2 weeks creating something approaching a basic playable prototype. It took a lot of tweaking of physics values to create a system that let the player actually influence the path of the balls with any degree of control. But eventually I got there. There was a lot more that I had planned for it, but the core of the game was there.

And it was BORING! I realised very quickly that there was no way I was going to come up with an interesting game based on this mechanic. It was almost impossible to come up with level designs where the solution wasn't immediately obvious, and then it became a game of trial and error playing with the placement of blackholes to get them just right to solve the puzzle. In order to come up with interesting levels they would have had to be massively more complex, at which point they no longer leant themselves to the limited screen space of a mobile device. 

Deflated, but determined not to stall yet again, I ploughed on half-heartedly trying to implement another feature, portals, which I thought might make the game a bit more interesting. 

Then came the Microsoft Build conference, which was the last time I posted to this blog. Microsoft released the developer build of Windows 8, and the XNA community immediately noticed that something was missing: XNA! 

There was a lot of noise about XNA being dead, which led me to write my last post on here. Incidentally, my confidence in the future of XNA has actually slipped further in the months since, but that's for another time. In light of the fact that, at least initially, it was clear that XNA games weren't going to be a viable option in Metro style apps, and therefore the Windows marketplace, I decided that there was a gap in the market for a new API. 

For a while I'd been toying with the idea of throwing in my current day-job/ career when I finish my part-time CS MSc course and trying to get a programming job in an established game studio. For that I need real-world C++ coding experience, and I'd been looking for a chance to use C++ in a project. 

These two events collided, and I decided I could kill two birds with one stone by writing a C++ version of the XNA API, written in DirectX 11 so as to allow XNA devs to port to C++ easily and use the new Metro UI. Even at the time I knew it was massively ambitious, but my fall back position was to write enough of the API so that I could port Alta, and so Sphero, to give me a new motivation to work on Sphero - get it done as a launch game for Windows 8. 

I set about the task, and actually got pretty far, completing a number of the smaller XNA classes in their entirety. Then I hit the real meat of the Graphics classes and started struggling. I wouldn't be in a position to properly test any of them until I'd written more, and without knowing DirectX 11 properly I could be heading in completely the wrong direction, but might not realise it for weeks. Still, I persevered (again).

Then a few things happened at once. Work got very busy. I was leaving for work and hour and a half earlier than usual and leaving at the same time. I was averaging maybe 5-6 hours sleep a night. I'd started lectures again for my MSc, which was taking up a lot of my time with assignments. And then Steve Jobs died.

It's strange. I'm not a huge apple fan. I have a macbook, but spend most of my time on MS products. I have an iPod touch, but my phone runs Windows Phone 7. I'd always seen Steve Jobs as an impressive leader and a good salesman, but I would never have considered him an idol. 

Yet when he died, I felt sad. Even now, months later, I have no idea why. But I did. This was before all of the media hype surrounding his death, before watching his famous Stanford address, or reading his sister's eulogy. When I heard the news I felt sad. And, as it played out in the media for the next few days, I, like tech enthusiasts and wannabe entrepreneurs everywhere, started re-evaluating my life.

I started making changes. I took up running. For reference, at school I could never finish the 1500m without stopping to walk at some point. I started following a program recommended by the NHS called Couch to 5k, which aims to get you from doing no exercise at all to running 5k over the course of 9 weeks. I've just finished week 8, and my last run was 4.9k, 28 minutes. I'm literally running further and for longer than I ever have in my entirely life. Why? To prove to myself that I can.

I knew I needed to work some exercise into my routine, but I never feel that I have the time. I knew running took the least time and would burn a lot of calories quickly, that I could do it in the park next to my house so there'd be no travel time built in, but I ruled it out because 'I can't run long distances'. In the aftermath of Steve Jobs' death I started questioning any and all assumptions that started with 'I can't'. 

As you might expect, I also applied this approach to my game development. By this point I had 4 projects on the go. That was at least 2, maybe 3 too many, so I started by questioning why I had so many. I wasn't ready to throw in the towel on Sphero, I still believed it was a genuinely fun game, I just had to get the level design right. My lighting engine was maybe 70% done, but the bugs I'd hit had made me lose momentum, and I'd let them beat me. My mobile game was just not any fun, and my native XNA port was horrifically over-ambitious. 

So I started cutting down my projects. My lighting engine was the closest to completion, I was genuinely learning a lot about shaders, and so it was fulfilling it's goals. The best way to get that project off of the books was to finish it, so that would be my first priority. 

My mobile game was DoA. The only reason I hadn't written it off was that I didn't want to give up on a project. But in this case, it was dead weight. The whole point of prototyping was to weed out the ideas that are no good, and this was one of those. Holding on to it would do me no good. So I declared it scrapped, with no intention of ever returning to it. 

My Native XNA port was tricky. The reasons for starting it were based on conflicting objectives. On the one hand, porting Sphero assumed both that I'd finished it, and that I'd be staying an indie developer. On the other, I wanted to do it to get C++ experience to get into the industry. It was an embodiment of my own indecision over my future path in games development. So, reluctantly, I put in into a perma-hiatus. I may one day resurrect it, but only if I actually need a C++ XNA port.

That leaves me with 2 projects, my lighting engine, which I'd work on first, and then back to Sphero. It was important to me to get the lighting engine finished first. I wanted to prove to myself that I could actually finish a project that I'd designed myself from the ground up, not just a clone of an existing game. 

2-3 months on, and I've finished the lighting engine. The source is on codeplex, and I'm in the process of writing an accompanying tutorial series to guide others through how to develop their own. I'll be posting the series up here as I complete it.

And then, come the new year, it'll be back to Sphero. I had toyed with the idea of taking up a new project that would help me bring Sphero to more platforms than just the Xbox and Windows, and might also help speed up the process of developing Sphero, but I've resisted the temptation for now. Again, if the reasons are right, I might consider it, but I'm done with changing projects to try and get myself out of a rut. 

So, without further ado, I shall shortly be posting the first (and possibly second) tutorial in my new series on developing a 2D lighting/ shadow engine. I hope other people can get as much from it as I did developing it.