Author Archives: Michael Farrell

Still going…

Too far to turn back now. Progress has been steady. I’ll post some shots this weekend.  Level 8 is done. I’ve added a really awesome new game mechanic (randomly distributed hostile gangsters) for level 7 and up that makes the gameplay a lot more intense.  My initial playthroughs of this new mechanic have been awesome and I find myself almost unable to think I have to react so fast which is exactly the kind of gameplay action that I’m going for.

I’ve decided to try to do one new level of the game per day until it’s done.  If I can do this, I’ll be on track to have the game done by some time in April like I’ve been planning for.  Let’s see how it goes. I still cannot believe that I originally thought this game could be done in a matter of weeks. Granted that I’ve increased the game beyond its original scope, 2 weeks even for a most basic version of this game is way way off.

Playtesting demos!

Here they are, the public play testing demos! These are downloadable and playable on just about any recent computer (recent meaning 2012 ish). Older laptops may struggle and older older laptops will struggle hard. I wouldn’t expect this game to run on any pre-600 series nvidia card or equivalent amd card. Intel HD 4000 was tested but that’s it from the intel family, so I expect that’s the required card for intel.

Feel free to grab these, play the crap out of the demo, and don’t hold back in giving me feedback. This’ll be the first time I get any real feedback for this game so let me have it!

Edit:  these have likely expired by now as the actual game has been finished

Mac – http://vertostudio.com/playtest/gd-playtest-mac.zip
Win – http://vertostudio.com/playtest/gd-playtest-win.zip

Downloads are a little dodgy from my server so you may have to retry once or twice to get it.

Also, IF IT CRASHES, please email or contact me immediately so I can find out what went wrong. There’s one sound-related windows crash that I haven’t fully nailed down yet but I expect it to be quite rare. Either way, if that happens, please let me know via email or on here.

Pushing for playtest demo

Not a lot of updates here lately because I’ve been working hard to get to the point where I can post a playtest demo and get some early feedback for the game. The demo will feature the first six levels of the game which I’m tying off today.

An early screen shot of the sixth level is below..
It was a pain to convert and simplify all of the “night time” shaders that I had for the night fog scene back into “day mode”. But I got it done. I also noticed that with the fog lifted, the original scene was way to simple so I had to add some desert in the distance and some extra buildings to make it look more presentable.

OpenGL point light shadows & Atomspheric FX hacks

So asset creation in the form of modeling the final environment that’ll be used in the game took the past few days.  It’s amazed how much faster it went this time compared the first scene (the city street).  I chalk this up to experience that I’ve picked up now that I’ve been doing this awhile, and my understanding of things that are very time consuming to model vs things I can quickly grab, import, texture, and place from turbosquid.  The perfect balance of both techniques has led to me being done with the dark night alley street scene after just a few days.

Where I spent the most time this time was in the shaders.  I really wanted to have quality rendering and go out with a bang since this’ll likely be the last environment that I do for the game.  I want the dark alleyway to appear foggy and dark, like its just about to rain.  That includes moist shiny cobblestone rocks, and a damp fog effect that feels very palpable to the player.

This idea of mine posed two major problems that I haven’t had to tackle until now.

Point Light Shadows

The first major problem, is that I could no longer “cheat” using a single directional light source representing the “sun” in the scene.  Instead, I had to place a street lamp every building or so and have these be the only sources of light in the scene.  This means, in order to keep my shadows working, I now had to implement shadows from a point light source.  In some ways this was easier than point lighting (no longer necessary to compute an optimal shadow bounding box to be used for the light’s ortho matrix projection).  However, now I needed render to and utilize cube maps to store the shadow depth information.  Surprisingly, there was very little comprehensive information on the web about how to properly do PCF shadows using cubemaps.

What I found that works is the following.

  • Create a cubemap renderer that is positioned at the exact same position as one of the point lights - this special vgl engine object renders the scene into 6 faces of a cubemap with 90-degree fov angles to properly capture the entire scene from “all angles”.
  • Format the cubemap shader to have each face hold floating point depth-component values and keep the size small (256×256) since there will be alot of these.
  • Define an “override” shader to be used by the above cubemap renderer to ensure a simple specialized “light render” shader was used when rendering the scene into the cubemap faces.  
  • Set the cubemap compare mode (GL_TEXTURE_COMPARE_MODEfor the rendered cubemap texture to GL_COMPARE_REF_TO_TEXTURE which helps with percentage-closest-filtering (PCF) mode to allow smoother linear-interpolated shadow edges.  
  • Lastly, pass a rendered shadow cubemap for each light to the scene shaders in the form of samplerCubeShadow

The “light render” shader mentioned above which is used when rendering the depth information to the cubemaps looks like so:

Basically this encodes the distance from the surface point to the light in the form normalized depth information.  This is done by manually overriding the depth value stored in gl_FragDepth.  Each light has its own cubemap renderer with a custom-tailored shader like this (using the correct light index to compute distance from).

The per-fragment lighting shader code that utilizes the cube shadow maps looks like:

Essentially the highlighted code above compares the distance between the surface point to the light to the stored depth value in the cube texture using the fragment-light vector as a lookup value into the cubemap.  Because we’re sampling using a special “shadow” version of the cubemap sampler, the result will be properly interpolated between shadow texels to avoid ugly edges between shadowed and non-shadowed areas.

Luckily, I was able to build this into the Verto Studio editor and associated graphics system and test this out with relatively little trouble.  Even though I have 4 or 5 statically rendered cubemap shadow textures in the entire scene.  I was able to keep performance high by building versions of the shaders for each side of the street so that each individual shader only has to shade with at most 3 lights at a time.  This worked out better than I had expected.

Light-Fog Interaction (Volume FX)

This part was tricky..  I had an idea in my head of how I wanted this to look.  So I did something that usually leads to trouble;  I tried to come up with a volume rendering technique on my own from scratch and implement it and just kinda see how it goes.

The basic idea stems from what I’ve observed in real life from foggy, dark, damp nights and lighting.  Essentially, fog at night is black… IF there is no light around to interact with the fog.  Naturally, if the water droplets don’t have any light to interact with them, you won’t see them and the fog will appear black.  However, if any light interacts with the water vapor in the air, it’ll create the illusion of a whiter colored and denser fog.  So this is what I set out to emulate with my shader.

Now atmospheric shader effects can often lead to the necessity of raymarching and heavy iteration in the fragment shader to simulate the accumulation of light-atomosphere interaction.  To this I said “hell no” since ray marching of any kind in a shader terribly robs performance.  I quickly realized that I could avoid raymarching entirely if I used a simple model to represent the light-fog interaction that I was going for.

In my case, it turned out I could do the whole effect using something as simple as a sphere intersection test.  Basically, when I’m shading a pixel (a point on the surface), I’m interested in what happens to the light on its way back from the surface to the viewer, the surface-to-viewer vector.  If the atmosphere affects the light at any point along this vector, I’ll need to compute that.  In other words, if the ray from the surface to the viewer intersects a sphere centered at the light, then the fog affects the light on the way back to the viewer.  How much?  Well if I calculate the length of the segment between the entry and exit points of the ray intersection (how much of the sphere the ray pierces), I find that length is proportional to both the perceived increase in density of the fog and the brightening of the fog color.

This algorithm is given below in fragment shader code:

 

I’m sure I’m not the first one to come up with this idea before, but it still did feel pretty cool to reason my way through a shading problem like this.  The visual result looks amazing.

The progress of this all is below in a gallery.  

How to 3D sound in windows (hint: it’s not OpenAL)

So yesterday and today, I bit the bullet and started working on compiling the game for windows.  I wanted to do this before the project got too much further along so I didn’t write any code that would have serious implications on windows.  I must say, I’m amazed at how much trouble I didn’t have with the rendering system.  The levels/screens load up and look great!  I did have some issues with visual studio that I chalk up to lack of experience in windows dev on my part.  Namely getting the builds to be 64-bit instead of the default 32, SSE3 operator overload stuff, and getting debug builds to forego some of the extremely slow settings that make the engine run at a crawl.  Once I took care of all that, my little game was running on windows like a champ, complete with same stellar OpenGL 3.3 performance I get on mac.  All was well… that is except for one little tiny issue.  The sound.

One thing that became apparent almost right away was that OpenAL support on windows is in a terrible state.  Counting on it to just be there like OpenGL is a no no.. and installing your own via something like OpenAL soft gives pretty poor support.  I realized that I had to do something I’ve never done before, and that’s directly use a DirectX subsystem.  After some quick googling I discovered what I need can be done using a combination of xAudio2 and X3DAudio.  Both of these systems come with DirectX and the DX SDK so I was already set up to use em.

So basically, the plan on windows was pretty simple:  since I already have all my 3D sound calls abstracted out in my SoundManager class, I all I had to do is re-implement the stuff that OpenAL handled using this new xAudio2 stuff.. and pray that it played nice along side SDL_Mixer which I use for mp3 music.  More or less, things went relatively painless and I was able to find an xAudio2/X3DAudio analog for just about everything I was doing in OpenAL EXCEPT for a little issue I had with source playback.

On mac, I’m able to play a source overtop of itself as many times as I want to.  On windows, this seems to be a no-go.  So for win, I had to manually pre-allocate pools of sources for the sounds that I would be playing rapidly such as bullet ricochet sounds and typewriter keystrokes and ensure that I return an available source whenever I ask to play that sound.  That process more or less worked out just fine.

After all that, we have my reworked soundmanager class for windows.  The code is below for anyone who wants to learn from it.

All of the multiple source stuff is essentially handled by my inner MultiSource class which handles the souce pools for sounds that need em.  I found that I never needed more than 8 sources per sound.  I also had to add a new update3D method to update the 3D sound calculations and call it once every other frame or so (which wasn’t needed in OpenAL since it was done automatically).

Not shown here is a Wave class which essentially is a slightly modified version of the one from this tutorial.  That class basically handles wav file loading for me and manages the sound buffer data internally.  

That’s just about it.  Everything else was pretty straightforward.

So much progress

So much has been done.  I’ve gotten the menu screen (title) finished and it’s beutifal.  I got the early music soundtrack for the title and first two levels in place, and a way to transition between all of these things.

My latest work has been the pre and post status screen in the game showing you how many enemies and bystanders to expect before each level, and how many you correctly or incorrectly killed at the end.

 

Some of the funnest work has been coding up the cutscenes for introducing the environments in the game.  I’m still planning on only doing 3 environments (otherwise I’ll never finish this game), and making the 36 total levels out of different takes on these same environments.

Here’s a tease of the intro into the second environment of the game.

C++11′s take on retain cycles

I’d like to take a brief moment to discuss something rather programmy today.  Namely, the topic of retain cycles.  If you’ve ever programmed in Objective-C before (since the addition of ARC) or Swift, this concept will be very familiar to you.  But if you’re coming from other programming languages such as the older (pre-11) C++, This concept will be new and you might want to read on.

Now before I get started, let me say that this example may not be the most correct way to handle delegation via lambda (block) functions in C++11.  Many will tell you that shared ownership of objects in C++ can get you into trouble, and this is certainly a case of how that can happen.  However it’s the most conceptually compatible with other languages, which I value over “c++ correctness” due to the fact that I’m porting code from another language to start with, and shared ownership allows me to get work done without reasoning around the lifespan of my objects.

Now as many newcomers to C++11 know, concepts such as smart pointers and lambda callback delegation can really save you alot of time when developing new systems.  However, there’s ahidden evil in using these two concepts together, that must be uncovered.

Example 1 :: All is well

Consider this example:

and its output:

What we’ve essentially done here is created an object (via shared pointer), set a callback lambda, and issued a method call which at some point calls our callback.  We see that everything is working as desired.  Most importantly, we see that our object is properly deleted when we are finished our program (when the shared pointer goes out of scope).

Example 2 :: Not so much

Now lets look what happens when I add a slightly more complicated, second case.

Obj2 essentially is the same as obj1 right?  All we do is add a little printout of obj2′s someProperty value from within the lambda… and of course, C++11 dictates that we must explicitly declare all external objects that we access within our lambda (a capture list).

So what is the output then?

Note the alarming lack of “object freed” being displayed for obj2.  That’s right, the above code memory-leaks obj2.  You see, obj2 owns someCallback, and someCallback owns obj2 via a capture. This is a retain cycle and it permanently causes obj2 to be “forever retained” and therefore leaks.  Once a retain cycle is made, you can consider things to be more-or-less, too late.

This type of bug is a dangerous silent killer of the night.  Why?  Because it can be so easy to miss when developing.  Objective-C and swift have evolved over time to add compiler and IDE warnings about this kind of “retain cycle” problem.  C++11 assumes that you just wouldn’t write this type of code.  But when porting code over from Objective-C, this kind of code can pop up ALL the time.

So what do we do?

Solution 1 :: The ObjC way

Well Objective-C handles this problem by introducing the concept of “weak pointers”.  These are special pointers that ensure that they do not own their reference, they only keep track of whether or not it is allocated (if any shared pointers to it exist).  Luckily, C++11 brings the weak pointer to us as well.  A solution that uses them looks like so:

You’ll note now that running this code will solve the leak.  It’s also important to note that, while this is an ugly solution, this is/was the only way to solve a retain cycle of this nature in Objective-C.

However, for this explicitly unique case, in C++, there’s another way.

Solution 2 :: The tempting C++ way

What if I told you there was a way to solve the original problem by adding one character to the original code?  Here it is:

See that little ‘&’ added before obj2 in the capture?  This allows us to capture a reference to the smart pointer and not a value.  Why does this matter?  Well when a smart_pointer value is copied, it essentially increments its retain count of the object in question, and when it finally is destroyed by going out of scope, it’ll decrement the retain count, restoring the natural balance to the universe.  However, as I mentioned before, a retain cycle prevents the retain count from ever reaching zero in this case.  A reference to obj2′s smart pointer value allows us to forego the copy-increment mechanism and essentially stop obj2 from being over-retained.  Its essentially like taking a pointer to a pointer….

However, this solution can be dangerous, as it assumes the coder understands the rammifcations of doing things like capturing a reference to a stack variable, an argument, or anything that may be “dead” by the time the callback is ran.  Almost always, this “solution” may give unintended consequences.

The “correct” way

Here’s where things get somewhat opinionated. The “correct” way to handle this really depends on the situation at hand. I suggest that if you a working with a team, you might want to use the safer and more verbose weak pointer method since it is more explicit in its intentions and helps explain why strong ownership could be a problem.  Furthermore, if you are working in a smaller system where shared pointership is not necessary, you might want to avoid using shared pointers altogether (assuming you fully understand the ownership semantics of the objects being used in the captures).

Either way, the golden rule is to understand the side effects of the code you are writing and when using shared pointers, keep that little retain cycle demon in the back of your mind… always