views:

815

answers:

6

In a Direct3D application filled with Sprite objects from D3DX, I would like to be able to globally adjust the brightness and contrast. The contrast is important, if at all possible.

I've seen this question here about OpenGL: http://stackoverflow.com/questions/139012/tweak-the-brightness-gamma-of-the-whole-scene-in-opengl

But that doesn't give me what I would need in a DirectX context. I know this is something I could probably do with a pixel shader, too, but that seems like shooting a fly with a bazooka and I worry about backwards compatibility with older GPUs that would have to do any shaders in software. It seems like this should be possible, I remember even much older games like the original Half Life having settings like this well before the days of shaders.

EDIT: Also, please note that this is not a fullscreen application, so this would need to be something that would just affect the one Direct3D device and that is not a global setting for the monitor overall.

A: 

The answers in this forum may be of help, as I have never tried this.

http://social.msdn.microsoft.com/Forums/en-US/windowsdirectshowdevelopment/thread/95df6912-1e44-471d-877f-5546be0eabf2

James Black
Thanks for the link -- I'm not working with video, though, so it's a completely different API unfortunately.
x4000
And it's DirectX9, I meant to mention.
x4000
+1  A: 

You didn't specify which version of DirectX you're using, so I'll assume 9. Probably the best you can do is to use the gamma-ramp functionality. Pushing the ramp up and down increases or decreases brightness. Increasing or decreasing the gradient alters contrast.

Kylotan
Only works in fullscreen, exclusive mode, unfortunately. Maybe this isn't possible for non-fullscreen applications without a pixel shader, I don't know.
x4000
The docs imply that it could work in windowed mode. In practice I expect it will depend on your graphics card and drivers.
Kylotan
Unfortunately not: "When setting new ramp levels, keep in mind that that the levels you set in the arrays are only used when your application is in full-screen, exclusive mode." (from the link)
x4000
Strange. It also says, "Because the gamma ramp is a property of the swap chain, the gamma ramp can be applied when the swap chain is windowed." I guess it means it can be applied, but it won't do anything. Which is not so useful. :)
Kylotan
+1  A: 

A lot of games do increasing brightness by, literally, applying a full screen poly over the screen with additive blending. ie

SRCBLEND = ONE
DESTBLEND = ONE

and then applying a texture with a colour of (1, 1, 1, 1) will increase the brightness(ish) of every pixel by 1.

To adjust contrast then you need to do similar but MULTIPLY by a constant factor. This will require blend settings as follows

SRCBLEND = DESTCOLOR
DESTBLEND = ZERO

This way if you blend a pixel with a value of (2, 2, 2, 2) then you will change the contrast.

Gamma is a far more complicated beast and i'm not aware of a way you can fake it like above.

Neither of these solutions is entirely accurate but they will give you a result that looks "slightly" correct. Its much more complicated doing either way properly but by using those methods you'll see effects that will look INCREDIBLY similar to various games you've played, and that's because that's EXACTLY what they are doing ;)

Goz
This sounds very promising -- I will experiment with this in the morning and see how it works in practice. Thanks!
x4000
Okay, actually, I already checked it out and it's perfect! Obviously it is not 100% accurate as you say, but it's older-GPU friendly, quite efficient overall, and gives a result that is plenty good enough. Thanks, once again!
x4000
You're welcome :)
Goz
A: 

Another approach is to edit all your textures. It would basically be the same approach as the gamma map, except you apply the ramp manually to the pixel data in each of your image files to generate the textures.

Kylotan
+1  A: 

Just use a shader. Anything that doesn't at least support SM 2.0 is ancient at this point.

BigSandwich
+1  A: 

For a game I made in XNA, I used a pixel shader. Here is the code. [disclaimer] I'm not entirely sure the logic is right and some settings can have weird effects (!) [/disclaimer]

float offsetBrightness = 0.0f;    //can be set from my C# code, [-1, 1]
float offsetContrast   = 0.0f;    //can be set from my C# code  [-1, 1]

sampler2D screen : register(s0);  //can be set from my C# code

float4 PSBrightnessContrast(float2 inCoord : TEXCOORD0) : COLOR0
{
    return (tex2D(screen, inCoord.xy) + offsetBrightness) * (1.0 + offsetContrast);
}

technique BrightnessContrast
{
    pass Pass1 { PixelShader = compile ps_2_0 PSBrightnessContrast(); }
}
Jodi