Byte Wrangler
A blog about developing an open world survival RPG.
May 10, 2012
Progress Report
In my last post I mentioned that February was going to be "Graphics Month". That turned out to be a bit of failure overall. ZBrush really wasn't the right tool for the job, but to cut a long story short, I once again looked at Blender and persevered with it long enough to get somewhere. I also found a few tutorials that really helped get me up to speed. I also found that making a cheat-sheet with all the common keyboard shortcuts was very handy, especially when coming back to it after a few days/weeks.
Most of the time I spent with Blender involved getting my head around UV-unwrapping, which isn't a trivial task, but absolutely necessary to have anything able to be textured. So far I've created only 2 small models, a rock (for terrain dressing purposes) and a campfire, but its a start.
In the past few months I've been tidying up the project quite a bit, disabling functionality that is only half finished, in an attempt to create a solid build so I can start passing it on to friends for feedback. My development schedule thus far has been fast and loose, whereby I'm not really developing towards a set of known goals, I just work on whatever interests me at the time. Unfortunately this has led to a the majority of features being only half finished, which is going to have to stop. So from here on I've started making feature lists for the next few monthly sprints, which has really helped focus my efforts in recent weeks. I've tentatively planned the next few months of development work, which I'd never really managed to do in advance.
One of the advantages of starting to show it around is obviously feedback, but also its forced me to care about the completeness of features. It's fine to leave something unfinished for development purposes, like say not handling some unusual edge case (with the idea of coming back to it and finishing it later), but once you start giving it out to people there's an expectation that everything works.
Pre-Alpha 1 was a reasonable success, though I had some teething issues getting the deployment correct due to not really understanding SlimDX's installation requirements properly. So far the feedback has largely been related to the camera system which is one of the first things I coded, and suffered from a situation where the controls made perfect sense to me, but didn't necessarily reflect what others might try to do. Fortunately one of my alpha testers works in user interface / graphic design, so he'll hopefully point out all my mistakes before they become too deeply ingrained. :)
Labels:
Big Picture,
Bulldog,
Development Schedule
January 21, 2012
The next step
I wrote about missing my target date in my last post, but what recent development have I done in Bulldog?
Last week I developed a sound playing engine for the game, to finally give the world of Bulldog some sound. Currently the only sound it plays is when you click on Button Controls in the user interface, but it's a start. In the future there will be ambience, such as wind or rain, or waves crashing on the shore, as well as creature sounds such as bird calls and eventually, music and perhaps even some voices.
In the past 3 months I've been spending alot of time trying to get the core mechanics of the game working. These are boring things like moving to a particular grid square, picking up an item, dropping an item etc. There's quite a bit of complexity in the interactions between the world and the user interface that caused a few nasty edge cases. I hadn't considered these when I originally coded the command/dispatch engine, which is responsible for executing creature's commands in the game.
For example, since there's a half second delay between issuing a drop command and the item leaving your inventory, in the initial, naive version, it was possible to queue up two drop commands on the same item, and cause the item to be duplicated, which is obviously a bad thing. Thinking in the manner of someone trying to exploit the system exposed a few other situations where this type of thing can occur, so I had to revise the way commands are executed in order to prevent problems like that, but I'm pretty sure I've got all my bases covered now.
Plans for the future?
February will officially be "graphics month", where I dedicate my development time to purely working on the graphics of the game. The key focus of this month will be drawing additional in-game art, such as icons for the items in game, but more importantly, 3D models for all the creatures and items. I've been putting off creating 3D models since I started the project, because it's not really my forte. I dabbled with 3d modelling way back when 3DS Max 1 was the latest thing, and haven't done anything since, so I pretty much have to learn 3D modelling from scratch using new software, so it's not something Ive been looking forward to.
I'm doing everything for this project legit, so I can't simply pirate the latest 3DS Max and just go for it. That said, 3DS max is far too expensive for me to afford for this project. While I've managed to use some of the tools and resources my company already owns, (such as Adobe Illustrator and Photoshop), 3D modelling is something my business has no need for, so justifying the $3,500 outlay to my business partners (and myself) is impossible. Similarly, from a personal perspective I can't afford it either.
I've looked at free alternatives, but haven't found one that doesn't have an enormous learning curve and weird esoteric commands. It annoys me that Autodesk don't sell a cut down (and cheaper) version of 3Ds Max that just has features like 3d modelling and UV unwrapping, and no fancy stuff like caustics, cloth simulations or fluid dynamics. Hell, the app doesn't even need a proper renderer. They did provide a version that was designed for games people specifically, called Gmax, but that was discontinued in 2005 and only saves the models into a proprietary format that is useless to me.
All that said, I recently looked at ZBrush, which is held in high esteem by a lot of people, and was shocked to discover it costs only $700, which is well within my price range. So I've got the 30-day trial sitting on my laptop and plan to evaluate it shortly.
Beyond February?
In the short term I want to get something demo-able to friends and family, and the graphics is the only thing holding me back at the moment. If all goes well, I hope to iterate a few times on the demo, adding more complete features and making changes based on feedback, and then start working on Phase 2 and the eventual proper release, which I'm VERY excited about. My plan is for everything up until the proper release to be available for free, and then charge something like $15 for the commercial release, which will entitle you to all additional content and features added from then on for free (and there will be a lot of them).
While it seems pretty popular with indy developers at the moment to fund development with preorders, I don't think I could justify this. In terms of what the customer would actually get, and the fact that I have a full time job so don't need the preorder money to survive, so at this stage that's not part of my plans.
Labels:
Big Picture,
Bulldog,
Development Schedule,
Release
January 8, 2012
Byte Wrangler is 1 year old!
I started this programming blog a year ago and its time to look back at what I've accomplished over the last year, and see if I'm on track.
The first thing to note is that there isn't anything available for download. In my second post on this blog I suggested I wanted to have something available for download at the end of 2011. That was my plan throughout the year and it seemed achievable until about August when I re-assessed where I was up to and realised I was well short of where I needed to be. Rather than lament the slippage of the deadline it's worthwhile looking at what went wrong and learning from the experience.
As far as I can tell I made 3 main mistakes, which I'll discuss in more detail below:
Mistake 1: Underestimating how long it would take to get certain parts of the system working.
This is the big one, and probably caused nearly 6 months of slippage. Since I decided I would use SlimDX and develop everything from scratch and not use an existing games engine, I started with nothing. I accepted this, but overlooked the fact that meant I had no user interface system to work with at all. That means no buttons, no textboxes, no labels, no scrollbars etc. Even designing a simple settings screen requires many different interface controls, and if you want to implement something more complex like an inventory screen with drag and drop etc, you're talking quite a bit of coding to develop the whole lot.
And just when I thought I'd implemented every control I'd need, I would think of another major one I'd forgotten. As if developing the user input side wassn't enough, I also needed a skinning/texturing system that allowed the controls to size dynamically as required and not have visual artifacts or ugly stretching when resizing.
On the plus side, over the past year I've implemented a windowing system and the following interface controls:
- Window
- Button
- Checkbox
- Context Menu
- Label
- Image
- Message Box
- Progress Bar
- Scroll Bar
- Text Box
- Tool Tip
There are a few additional controls on the wishlist, but they won't be needed until later and shouldn't take as long as getting this framework up and running.
Mistake 2: Overestimating how much free time I had over the entire year.
This one is hard to judge, as 2011 turned out to be fairly tumultous from a family standpoint, and since I'm developing this game in my spare time, work, family and sleep pretty much come first, and Bulldog lost out more times than I would have liked. Not much can be done about this moving forward as life is unpredictable, but I should adjust my estimates in the future to assume I have less free time.
Mistake 3: Spending too much time researching and developing unnecessary features.
This one was avoidable, and was caused by becoming sick of coding "boring" features and wanting to implement some cool stuff. Like for example, I spent a good 6 weeks developing the signed distance field font system, when I had an ok (albeit ugly) font system already in place. The end result is about 10x better in terms of flexibility and visual look, but that time might have been better spent working on essential features. At the same time though, the distance field stuff was a lot of fun to work on, and was very rewarding at the end of the day.
It's hard to stay focussed on the boring stuff, when there's so much unnecessary fun stuff. But since the fun stuff keeps you motivated, you have to deviate from the schedule sometimes.
Where to from here?
So I guess the question is, how much has actually been done, and what's the current plan / deadline? Since that will be a reasonably large post in itself, I'll leave that to my next post. Stay tuned.
Labels:
Big Picture,
Bulldog
October 26, 2011
Signed Distance Fields
I was first exposed to Signed Distance Fields through this white paper written by Chris Green from Valve Software. Valve often make technical documentation on their graphics technology available, which is awesome. In this case, the technique was used in Team Fortress 2, specifically for some of the signs and decals in the game.
Signed Distance Fields are a different way of storing (typically monochrome) bitmap data. Instead of each pixel in the bitmap representing the intensity at that point, it represents the distance to the nearest non black pixel in the source image. Pixels outside of the shape have positive distance values, while pixels inside the shape have negative distance values, hence the "signed" part of the name.
![]() |
| Figure 1. An example of how a signed distance field looks at the pixel level. |
Note that in reality the distance field is made up of floating point data, but for illustrative purposes I've shown them as integers.
To create a signed distance field you apply a distance transform to a source image. Then, to render the original image you do the following:
For each distance value in the field,
is the value <= 0?
if yes, draw the pixel
if no, ignore it.
The thing that makes signed distance fields really useful is what happens if you need to resize the image. The distance values are interpolated by the 3D hardware in the same way as intensity values in a traditional bitmap, but because the edge comes from a test, it remains crisp. This means you can magnify the bitmap many times and not suffer the blurry or chunky edges that traditional bitmaps exhibit due to filtering artifacts.
Creating the Distance Field
There are many different transforms you can use to calculate the distance field. It turns out that the best approach is to use a high resolution source image and then downsample the result to an acceptable size for your application, as the nature of the distance field preserves a lot of the information.
The brute force method (by which I mean calculating the euclidean distance between a given pixel and every other pixel in the bitmap) will generate a perfect distance field but is particularly slow for large bitmaps as it has O(n^2) complexity. There are faster (albeit less accurate) algorithms out there though the selection of algorithm isn't too important, as it doesn't need to be done at runtime. Valve actually used the brute force solution and ran the processing as a batch job overnight on their servers. I chose a faster approach simply because I was eager to get some results.
![]() |
| Figure 2. An example of what the final distance field looks like in Bulldog. |
An application of Distance Fields
Since the source data for Distance Fields is generally monochromatic, their usefulness is limited, however one application that is particularly well suited to distance fields is drawing text.
For example, a TrueType or OpenType font (or "typeface" to use the correct term) is stored in a vector format. This means each of the glyphs (characters in the typeface) are represented as shapes with x,y coordinates for their corners and control points. This is converted into a bitmap or "rasterised" for display on the screen. Depending on the size of the text you want, the x,y coordinates are scaled and the curves that represent the shape of the letter are scaled too. The rasterisation process can be a little slow even on modern hardware, so in games the preferred technique is to pre-rasterise the font at the size you want, store it as a bitmap and then construct the text required by picking individual letters from the bitmap.
This technique is very fast, but has some limitations. You need to create a seperate font bitmap for every size and style combination you want to use in your game since bitmaps don't scale well. Take for example a game that wants to have 2 different typefaces, say a normal looking sans serif typeface like Arial, and maybe a fancier caligraphy typeface for ye olde books and scrolls and the like. You may want to support 3 different sizes for stylistic reasons, such as titles/captions or tooltips. Or perhaps you want to support a wide range of screen resolutions and don't want people to require a microscope to read your UI elements. Already we have 2 * 3 = 6 different bitmaps you need to create and manage in the game. It gets even worse if you want to support italics or bold styles as well.
The signed distance field approach helps alleviate this burden by taking the sizing out of the equation since the distance field can be scaled up and down with less graphical artifacts.
As an added bonus distance field data can be used to anti-alias the edges. This can be achieved by adding an additional term to the distance test to smoothly ramp from lit to unlit for distance values within a certain range. The Valve paper covers a few other effects, such as drop shadows and outlines.
In Bulldog, I implemented signed distance field fonts using a pixel shader, which makes juggling the distance field data considerably easier.
The shader code is surprisingly simple, and for simple anti-aliased text is as follows:
delta is a constant which determines how far from the edge of the letter the anti-aliasing extends. The actual shader code I use in bulldog is slightly more complex as it handles borders and reversed characters (such as when selecting text in a textbox), as well as adjusting the anti-aliasing for different font sizes. I'll write up a more detailed post on the new font system I built using signed distance fields at some point. In the mean-time, here's an example of the same font rendered at several different sizes:float4 ps( VS_OUTPUT IN) : COLOR { // get the alpha value from the distance field texture float rawAlpha = tex2D( TextureSampler, IN.TilingCoords).a;
clip (rawAlpha - (0.5f-delta)); return float4(fillColour, smoothstep(0.5f-delta,0.5f+delta,rawAlpha) ); }
![]() |
| Figure 3. An example of the font output at 12, 24 and 64 pixels high. |
As a last note, I should mention I've also used signed distance fields in an unusual way in a different part of Bulldog, but that's a post for another time...
Labels:
Bitmap Font,
Shader,
Signed Distance Field
Subscribe to:
Posts (Atom)


