Game Development Community

Black and white rendering

by Gregory Stewart · in Torque Game Builder · 09/03/2005 (8:00 am) · 16 replies

So, I think it would be cool to have the game that I am working on switch to black and white occasionally. Does anybody have any ideas on how to implement this?

My initial guess, without actually looking into it, would be that there may be some way to overlay the screen with a quad and then use some sort of GL filtering to modulate the colors out of the scene. Does anybody know if this is possible?

I'll let everyone know if I find a way to do this.

EDIT: I suppose I should clarify that I mean black and white as in greyscale, not only black and white.

#1
09/03/2005 (8:13 am)
Well, I hate to point out the obvious, but why not just create a method that changes the sprite from a colored version, to a grayscale one? I mean, often times you'll want to manually select the grayscale tone, instead of just filtering the whole screen to show the luminance.

--
Hans
#2
09/03/2005 (9:46 am)
That or make the sprite grayscaled to begin with (or just white) then use the blending mode to switch them.
#3
09/03/2005 (11:19 am)
Right. Thanks for the replies, guys. I guess the reason why I am hesitant to have two versions is just exactly that... that would require double the amount of video/system ram to have ALL of the graphics in both color and grayscale versions.

Some searching on gamedev.net reveals that you could use a shader to do this.. however, I think this would essentially eliminate about half of the people that could play the game (myself included). At least, I don't think my card can handle shaders.. I know I can't run the TSE demo..

EDIT: Wait, I can run the TSE demo.. I just remember that it was an issue with an outdated driver. I have a Geforce 4 ti4200 and I know it can't run some shaders at least.. I really need to do more research into shaders and which cards do/don't support them.
#4
09/06/2005 (5:49 am)
A Geforce4 can definitely do shaders.
#5
09/06/2005 (11:49 am)
A GeForce 4 has limitted shader capabilities. But anything GeForce 256 or better can easily do what you need.

Basically, it works like this. You render to a texture (whether this is via a copy or with FBO depends on what the implementation implements). Then, all you really need to do is do a dot product between each color and the "grayscale vector". If our eyes saw each color equally, this vector would be (0.3, 0.3, 0.3). However, this is not the case, so the grayscale vector is actually something like this (0.3, 0.5, 0.1). These aren' t the exact numbers (look them up on the internet), but I do know it isn't an even distribution.
#6
09/06/2005 (12:37 pm)
All you have to do is make the image grayscale, and then set the blend color in the datablock. When you want to display the image in black and white, simply remove the blend color. That's what we are doing with our game. We have various layer images that get combined into a final brick (this is breakout style game), each layer image is grayscale, and the blend color for each layer is set in the editor. This allows you to make a virtually unlimited number of types based of a single set of images, and you can get your black and white by simply turning off the blending...
#7
09/06/2005 (1:56 pm)
The proper weights for the luminance function, are .3, .59, .11 so the luminance formula, for quick reference, is:
y = 0.3R + 0.59G + 0.11B

However, the shader-route probably isn't the right way to go, if you want to use T2D.

--
Hans
#8
09/06/2005 (6:07 pm)
Thanks for all of the replies, guys. Awesome, as usual.. Now, I just need to decide which approach to use..
#9
09/06/2005 (6:51 pm)
Quote:All you have to do is make the image grayscale, and then set the blend color in the datablock. When you want to display the image in black and white, simply remove the blend color. That's what we are doing with our game. We have various layer images that get combined into a final brick (this is breakout style game), each layer image is grayscale, and the blend color for each layer is set in the editor. This allows you to make a virtually unlimited number of types based of a single set of images, and you can get your black and white by simply turning off the blending...

So, rather than having one post-process pass (that can function on pretty much any and all hardware), you're effectively rendering 3 sprites for every one you need. Plus, since you're relyong on the blending to make it work, you can't use the blending correctly for other stuff.

I don't see this as being terribly efficient, compared to the shader route.

Quote:However, the shader-route probably isn't the right way to go, if you want to use T2D.

Why not? This is a pretty dirt-simple shader to write.
#10
09/06/2005 (7:57 pm)
Alright Smaug, I've got to take you to task on this one. How?

I've looked on several occassions at OpenGL and shaders. But, short of using GLSL and OpenGL 2.0 (which I'm not sure how you'd make T2D use), how do you do it? T2D uses OpenGL 1.4, right? How do you write a shader program that isn't chipset specific?

Everything I've seen makes it look like porting T2D to TSE is the right choice. I'd love for you to prove otherwise... and show me that writing shaders is simple. Go! :-)
#11
09/06/2005 (11:32 pm)
Quote:
However, the shader-route probably isn't the right way to go, if you want to use T2D.
Quote:
Why not? This is a pretty dirt-simple shader to write.

Because T2D isn't ready for it. You'll have to go in and fix it. Me, I'd just change the sprites. Keep an alternative gray-scale one, and change that. At least I know that'd take me less time than adding this into the engine.

--
Hans
#12
09/07/2005 (1:39 pm)
Quote:I've looked on several occassions at OpenGL and shaders. But, short of using GLSL and OpenGL 2.0 (which I'm not sure how you'd make T2D use), how do you do it? T2D uses OpenGL 1.4, right? How do you write a shader program that isn't chipset specific?

By doing what the pros do: write all the paths.

We're not talking about a game full of shaders here. We're talking about a simple post-processing pass that gets run after the main render loop but before the framebuffer swap. It's just 1 shader; you can easily afford to have the 3 separate pieces of code that work for the 3 kinds of hardware. At most.

First, check for ARB_fragment_program (not glslang) support. If you don't find that, check for NV_register_combiner (available since the first GeForce). And if you don't find that, maybe you can do a check for ATi_fragment_shader (only useful for R200-based hardware. Radeon 8500-9400s). You could easily drop the last one, as even finding that hardware to test it on is rather difficult.

Writing the actual shader is pretty trivial in any of the interfaces.

Quote:Everything I've seen makes it look like porting T2D to TSE is the right choice.

Except that, because of what TSE is, you'll still have to write the OpenGL code (unless you're going to affix yourself to D3D and Windows) to create the shader anyway; TSE probably doesn't come with a B&W shader. Which means you'll still need to check the extension strings to see what the hardware supports and write different paths for the different hardware. Nothing changes.

Quote:Because T2D isn't ready for it. You'll have to go in and fix it.

It's not like the source code isn't already there. All you need to do is insert a bit of code at the end of the render loop. And possibly at the start of it if you intend to use FBO for direct rendering to a texture.
#13
09/07/2005 (4:47 pm)
Thanks for the replies guys. It has given me some ideas on how to go about this.
#14
09/08/2005 (11:37 am)
Oh, one more thing I realized. You don't technically have to resort to shaders. You can easily use ARB_texture_env_dot3 extension. It is supported by all this hardware. It's much easier to work it this way, and you don't have to do any real work for multiple platforms.
#15
03/25/2007 (12:12 pm)
Did anyone ever get this figured out for TGB?
#16
03/27/2007 (4:50 am)
My game can run in grayscale. What I did to achieve this was multiply all the colors by a global color channel before applying the color. I.E. instead of calling glColor4f( color ) call glColor4f(color * globalColor). I actually have a list of global colors and added a variable to the color class to tell it which color to multiply by. There's other advantages to this as well: I can alpha fade the entire screen or fade to black for instance.