As you probably know from previous updates, we’ve been working hard on our ‘GDC’ build. The real reason we were working so hard is because we’re in the Indie MEGABOOTH at PAX East! Check out this sweet trailer: (we’re at 0:36s)
I’m happy to say that we’re currently putting the final touches on the game demo. We’ve been working insane hours for the past few months, but we think it’s all coming together now. We’ll be showing our game on a 60″ TV, so it better run well!
The plan for next week is to fly to San Francisco first, and be at GDC for 2 days for the Independent Games Summit (my favourite part of GDC by far). Then on Wednesday we’re flying to Boston, which by then will be completely free of snow, and be just as sunny as San Francisco… yea… Anyway, we’ll be setting up our booth on the Thursday, and then Friday, Saturday and Sunday will be demoing our game to the fine people of PAX East! We are super excited!
Here’s another little boss teaser, this time from within the game, and with some nice lighting:
So come check out our booth (nr 5176) and try to beat this mean boss!
Oh, one more thing, our usual Wednesday-dev-stream will be moved to tomorrow. Jesse is off today, and Caley and I think we’re nowhere near handsome enough to be on camera.
It’s been a while since the last Tech post, so it’s about time I wrote some stuff down again. Lately I’ve been working mostly on porting the engine to PS4, as well as keeping the DirectX and OpenGL versions up to date. Not really something that is super interesting to write about!
Now with those excuses out of the way, let’s talk about lighting. I’ve been wanting to add proper lighting to our game for a while, but since it’s a 2d(-ish) game where we ‘cheat’ with the perspective quite a bit, most of the ideas I had about lighting wouldn’t really work. To illustrate what I am talking about, have a look at the scene below. The left image is the game camera perspective, the right one is the perspective from an independent 3d camera:
In the game camera (left image), the entire scene is skewed by an angle of about 30 degrees, much like an isometric view. However, it is actually a perspective view with a very low camera field of view angle, and a skew matrix applied to the world. So you still see a bit of 3d, yet it looks like a hand-drawn flat 2d game.
In the 3d camera (right image), you can see that we’re cheating quite a bit to get the look we want. The boat for example is built up out of a few flat facades, much like the buildings in a Hollywood movie set. Characters in the world are flat camera facing sprites. Also, the background is actually a big flat texture that is pretty close to the back of the boat.
When you apply conventional lighting methods to this, a few things start to go wrong. First off, most lighting methods use the surface-normal to generate proper lighting. We toyed with the idea of generating normal maps for all our textures, but when we looked at the amount of work required to create normal maps we quickly axed that idea. Yes, we looked at tools like Spritelamp, but we are just 3 guys trying to make a pretty content heavy game here! We have to pick our battles.
So I tried implementing simple omnidirectional lights that just ignore the normal of the surface entirely, but still applied a nice falloff based on the distance to the light. That actually looked quite decent! I added omni lights to our puppets and made them animatable, so we can easily add lighting effects to characters. For example, check out the Clang lighting effect (somewhat crappy gif compression, but you get the idea):
With omni’s out of the way, I started looking at directional shadows. Luckily for us, all our textures are polygonized, so the edges are actually triangle edges. If you’re wondering what I am rambling on about, check this blog post. This means generating a proper depth texture for shadow casting lights is quite trivial, and doesn’t involve any texture lookups for alpha testing at all. Now, when applying shadows to a flat world like this, you DO want to look at the surface normal. You only want to apply light to surfaces that are not-in-shadow, and facing the light. To clarify: I just determine if the light is coming from behind the pixel or in front of the pixel, and either apply all lighting or no lighting at all.
Because of our flat camera facing sprites, the only shadows that look good are shadows coming from the front or from the back of the world, so we are a little limited with how much we can do with the shadows, but it does add a cool effect to our world. Check out these examples below. You have to click them and move your mouse left/right to see the before/after:
Alright that’s it for this week, I hope it was informative. If any questions pop up, feel free to ask away in the comments, or even in the chat during our stream later today on Twitch!
Also, since it’s a Wednesday, don’t forget to tune into our devblog later today! Jesse will be streaming from 4pm-6pm PST today, and it’s always a blast to see him drawing and chatting with the viewers. It’s a good time, I promise. Come check it out. Click the image below to go straight to our twitch stream:
This week there isn’t too much to say about the actual development of the game, as we were super busy getting everything ready for the Playstation Experience in Las Vegas. We left for Vegas on December 4th, setup our stand on the Friday, and showed the game to the public on Saturday and Sunday. The show was super fun, and really well organized. We received lots of valuable feedback from players, and we met a lot of fellow indie developers. Here are some impressions from this weekend:
Jesse showing the game to Parkitect creator Garret Randell
People kicking some Snowclaw behinds off the ice raft.
A huge Jake the dog inflatable statue.
We’re in good company!
Screenshot of the game!
Group shot after a super fun show! Huge thanks to Kevin (far right) and Gordon (horizontal) from PowerUp Audio for helping us out at the booth!
Alright, that’s it for this week. We have lots of feedback to integrate into our game, so we are getting back to the grind. Till next week!
Oh, and of course, tune in to our weekly Twitch cast from 4-6pm today!
On Monday we showed our game off at the Seattle Indie Expo, and it was super fun to meet a bunch of Seattle indie developers, as well as meeting all the people checking out our game! We’ve gotten a lot of feedback, and we’re going to be incorporating all of that into our game to make it even better. Here’s a quick pic I snapped of Caley and Jesse and our setup.
Alright, now to the tech stuff. This week I put in something I’ve been wanting to put in the game for a long time: Color grading. Color grading isn’t new, and I am definitely not claiming this is something unique. However, it is very cool, and I wish more people knew about it. Every artist I show this too reacts as if their mind is blown, and every programming is like ‘yea, I knew that’. There have been many games that are using this already, like The Witness, and a lot of AAA games. There’s a great description on how to use it on Code Laboratorium, and this week I’ll try to give you my version here as well.
The basic idea of color grading is to map every possible color to another (color graded) color. In other words, you basically want to be able to call a function in the form of:
Color GetColorGradedColor(Color rawColor)
One way to map each possible color to each other color is to use a huge array. If we’re using 8 bits per color channel, that means 256 steps per color channel, so we’d need an array of 256 * 256 * 256 different mapped colors. That’s a lot of memory, and a lot of cache misses to deal with! Luckily there is an easier and faster way.
Imagine that there was a way to store all these mapped colors in a cube. the X axis could be the Red value, the Y axis the Green value, and the Z axis the Blue value. Now, if we had a color value, we could just use the RGB value as the XYZ coordinate in the cube, and get the color graded color. Now also imagine that the color grading is pretty smooth, and neighboring colors in the cube are very close together. That means we could just take a lower resolution cube, and interpolate for any colors in between.
I’ve just described the exact behaviors of a 3d-texture. For my implementation I’m using a 3d texture of 16x16x16 pixels as my color grading look-up texture (also called a LUT). I’ll get into how to create these textures later, but for now, imagine we’ve got a color grading 3d texture completely set up. What actually needs to happen to get the screen to show up completely color graded? It’s simple: Render the entire screen to a render target, then render this render target to the screen using the color grading pixelshader.
The color grading pixel shader is very simple (this is GLSL, but it should be pretty easy to convert this to HLSL):
Note that the alpha of the color isn’t used in this shader, as the screen is drawn without Alpha blending. The scale and offset parameters are there because of the way textures are interpolated. There’s a great explanation in GPU Gems about this.
Alright, so now that we’re able to combine an input texture (from your render target) and a 3d color grading look up texture into a final color graded output image, we need to start worrying about how to create these color grading textures. (This is the part that usually blows the artists mind). The basic process is this:
1) Create a screenshot of your game, and insert the color cube information to the image.
2) Load the screenshot into photoshop, aperture, paint .net, gimp, or whatever color correction application you prefer, and change the colors of the image using whatever plugin you want.
3) Save the screenshot once you’re done
4) Load the screenshot back into your tool, and extract the color cube information.
That’s it! Pretty simple, right? Here it is in pictures:
This is the interface we have in the editor for generating the color grading textures. The button ‘Generate Screenshot’ will create a screenshot of the game, attach the color cube information at the top, and save it out to disk as a png (you’ll want to use a loss-less image format, don’t use jpg!). This is the image it generated:
Notice the color grading information in the top left. To generate this screenshot, all existing color correction and bloom in the engine was turned off, so the image is as close to the raw data as you can get.
Now, I’ve loaded this image into paint.net, and changed the color, then saved it out to this image:
I didn’t change these colors to look particularly good, just enough to show a difference between the incoming and outgoing image. Next, this image is loaded back into the editor, which extracts the colors from the image, and puts them in a 3d texture to use as the color grading LUT:
That’s all there is to it! I’ve added a few extra things like being able to blend between color gradings within a level, which creates really cool mood changes when you walk into a cave or when you get into a village. Here’s a few more extreme color gradings:
Alright, that’s it, hope it was helpful. Keep color grading them games!
You may remember a blog-post I did a long time ago about the texture polygons we created for Shellrazer. If not, here it is. The system we used at the time required hand-editing of each texture, and this quickly becomes WAY too much work. Especially at the rate Jesse is able to crank out art for Viking Squad!
Now, Viking Squad is not meant for mobile devices, but we’re still generating texture polygons. The difference is that we’re only using full opaque texture polygons for viking squad, and we have removed all alpha blended triangles from most triangles that get rendered. This is mostly as a preparation for proper shadows and lighting (which I haven’t implemented yet). Also, by enabling full screen anti-aliasing, the edges of our models are really nice and crisp, especially on a 1080p TV.
The whole process of generating the texture polygons is also fully automated now. The basic algorithm is fairly simple, I first trace the outline of the mesh by checking the alpha of each 2×2 pixel block. I add edges for each edge, and connect them all together. After this step, the mesh would basically look like this:
That’s a LOT of points! As a clarification, on the right is the image with blue circles representing the vertices, and a green triangles representing fully opaque triangles. On the left is the resulting mesh rendered. As you can see the edges get a bit blocky with this many points, something we’re trying to avoid.
The next step is to simplify the edge, while trying to retain the shape of the outline we just created. This is done by a basic edge-collapse algorithm that calculates the ‘cost’ of collapsing each edge by looking at how much it would alter the original outline. Each turn, every potential edge collapse is given a score based on how much it alters the original outline, and then the one with the lowest score is collapsed. Then another turn is started. This continues until the cost of a collapse is above a given threshold value. The end result looks something like this:
As you can see here, the steppy-blocky edges are pretty much all gone, and they have been smoothed out into nice sharp looking edges.
The triangulation of the outline is the last step in the process. I use OpenTK in our editor (a C# OpenGL, OpenAL and OpenCL implementation), and luckily that has access to the GLUTess functions, which create a tessellation of a given outline. This works pretty well!
There’s another example, this time a tree:
As you see, we’re generating quite a few triangles for each object, and in a whole scene this turns into quite a lot of triangles, but they are all nice and crisp and all ready for some awesome lighting (which again, I still need to implement). Check out this wireframe/solid slide able image to see how many triangles we’re putting on screen: (The second image might take a while to load, just give it some time. It’s mostly because I can’t even HTML)
(Btw, the very cool slider thing we used in the ‘Click me’ image above is from here)
Alright, that’s it for this week. Until next time, and keep those triangles wireframing.
Welcome back followers of the fearsome! This week we are out taking in the sights of this years Game Developer’s Conference and then hitting up Pax East at the Indie Megabooth! Wish us luck as we brave the blizzard that is Boston and if you are over at Pax East be sure to stop by! […]