Shaders allow you to make beautiful games, allowing special effects such as depth of field and bloom. I like making pretty games, but I have always used other people's shaders rather than writing my own. The internet it a great code base to get familiarized with the concepts of the code and find some simple code that people have already written. However, at some point you either have a bigger problem than someone has written code for on Stack Exchange, or you just want to learn how to write the code yourself.
Today I fit into category B, and so I waded out into the new world of shaders. For the game I pitched last week it is essential that the game can filter out colors (make certain colors white) until a certain point in the game. Last week I modified a stock shader to make sure I could get the RGB value of a pixel and selectively show it. However, the shader was in no way robust and only worked for very specific values of red, green, and blue. I determined, that the minimum requirement for my shader would be the ability to filter out 10 distinct colors (red, green, blue, yellow, orange, pink, purple, brown, black, and gray) whenever I so desired. It is a much simpler problem than say depth of field shader, but it was a starting point nonetheless.
As is common when one starts coding I brainstormed to come up with a couple of different implementation methods. However, not knowing what a shader would allow me to do in terms of data structures, I decided that to start I would use a simple color range to calculate which color I had. Because my elementary school had art projects I am able to visually distinguish between the desired colors*. However, I can't tell you off the top of my head what RGB value equates to a dark shade of cyan. So doing what most would do in this situation, rather than blindly guessing I opened up photoshop to get some reference values to start with.
I quickly realized that using the RGB value was a horrible idea, but it seemed to me that the HSB (Hue, Saturation, Brilliance) value was much more consistently grouped. I don't really use HSB values often so I went logged onto the Internet to see how a HSB value relates to a RGB value. To my rejoice I found that a color's hue defines it location color wheel that contains red, yellow, green, cyan, blue, and purple. The color wheel already defined values for 5 of my desired colors, so I decided that this would be an easy first implementation. XNA color structs don't provide hue values, so all it took was one more quick search and I was off.
Once I got the equations coded up, I was excited because I thought all I had to tweak the ranges to yield orange and pink (black and grey are easy because they are the lack of brilliance and saturation). Unfortunately I was wrong, I ran into the first road block of the day, the color brown. By that, I don't mean that it was a roadblock that caused some tricky coding, rather it was a roadblock in that it took a long time to define what brown is. It ranges between so many values that you can't do a simple if statement as a catch all. However, I come to you as a proud man, in a spite of genius I was able to defined the mysterious brown and define its muddy qualities exposing it to the world**. At this point I stumbled upon a much, much bigger problem.
When you write a shader in XNA you are allotted a maximum number of arithmetic instructions that you are allowed to apply to every pixel. The keyword being instructions (not operators), meaning however many instructions you have after the compiler runs threw your program reorganizing your code as it pleases. In other words, it becomes extremely difficult to make a few simple changes in your code base to cut down on the instruction count (removing some operations does nothing, adding one operation adds 10 instructions, etc.) While I could just specify that it should compile under a system that allowed me to use more instructions, what is the fun in that (Read: it didn't work on my GPU without me writing a vertex shader).
After much toiling, I was able to get all of my code to work with one expection, I haven't been able to sneak in the cutoff for brown. This means I am able to draw just brown, but I can't draw yellow without the brownish yellow values. While I don't like leaving incomplete code I had to throw in the towel for today and work on some other items. I will leave the preliminary results (minus some threshold tweaking and fixing the aforementioned issue) below, but don't worry, I will be back with better results in the future (sooner if my game idea gets picked).
Results:
Full Picture:
Picture showing only certain colors (clockwise from top left: red, purple, blue, brown):
*Elementary school isn't my highest education level, I was making a joke.
**It wasn't that hard, I am being melodramatic.


No comments:
Post a Comment