Skip to main content
GameDev.net gamedev.net
🔒 Locked

Rendering Grayscale, RenderState/TextureState

Started by konnichiwa Sep 12, 2005 at 5:08 PM 6 replies 9.8k views
Original Post
konnichiwa
konnichiwa
I'm trying to render a sprite (or anything really) to be a Grayscale when i want it to be, I REALLY dont want to edit the texture to make it gray, so I wondered If there was any RenderState / Texture State i can apply to make this work? Thank you very much :)
Evil Steve
Evil Steve
If you're using pixel shaders, it's easy - you just average the red, green, and blue channels, and then set all 3 channels to the same (averaged) value. You could make things more complicated by using the proper luminance values (I don't rmember them, but green is multiplied by 0.3 I think. Red and blue are multipled by different values).

Without pixel shaders, I can't think of any way to do this without modifying the texture, but I'm fairly sure there must be a way. I'd be interested to know too...
Armadon
Armadon
Hi there konnichiwa,
How are you doing buddy?

The Problem
Setting renderstate to make a texture grayscale

The Solution
I would say the logical and easiest step is just to modify the texture. Unforunately I don't know of any render states that you might be able to set to get this effect but it surely is possible in shaders and if you want more information on that you can check the Post Process sample in the SDK directory,
Source: (SDK root)\Samples\C++\Direct3D\PostProcess

You could probably also fake a kind of grayscale by rendering to texture and modifying the values of each of the vertices in the texture after rendering and then you have your "greyscale" texture.

I hope this helps buddy.
Take care.
neneboricua19
neneboricua19
If you're using pixel shaders, you can convert an RGB color to grayscale by the following:

float fLuminance = 0.299f*color.r + 0.587f*color.g + 0.114f*color.b;
return float4( fLuminance, fLuminance, fLuminance, 1.0f );

Use this luminance value as the RGB colors output from the pixel shader and you get proper grayscale images.

As far as I know, there is no way to do this without using shaders.

neneboricua
SirKnight
SirKnight
Quote:
Original post by neneboricua19
If you're using pixel shaders, you can convert an RGB color to grayscale by the following:

float fLuminance = 0.299f*color.r + 0.587f*color.g + 0.114f*color.b;
return float4( fLuminance, fLuminance, fLuminance, 1.0f );

Use this luminance value as the RGB colors output from the pixel shader and you get proper grayscale images.

As far as I know, there is no way to do this without using shaders.

neneboricua


Couldn't you just use SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3) and set ARG1 to the texture and ARG2 to TFACTOR. Then before you render call SetRenderState( D3DRS_TEXTUREFACTOR, dwTFactor) where dwTFactor is the vector (0.299, 0.587, 0.114) packed into a DWORD. I havn't tried it but it may work.


-SirKnight
remigius
remigius
I tried out the effect described by SirKnight and it works perfectly, but you have to use inverted weights for the TFactor (don't ask me why :). I initially used the following C# code, following the instructions:

[source lang=C#]device.TextureState[0].ColorOperation = TextureOperation.DotProduct3;device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;device.TextureState[0].ColorArgument2 = TextureArgument.TFactor;device.RenderState.TextureFactor = ( 0xFF << 24 ) | (76 << 16) | (150 << 8) | 29;


This however produced an inverted, but grayscale image in my effect demo. It may be a problem with the renderstates already set by my effects, so I thought I'd post my original result as well. Anyway, here it is:



To fix this inverted color, I simply inverted the TFactor. This gave the correct effect and it also miraculously solved the problem with the articfacts in the shadow volume & billboards in the first picture. So, the code:

[source lang=c#]device.TextureState[0].ColorOperation = TextureOperation.DotProduct3;device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;device.TextureState[0].ColorArgument2 = TextureArgument.TFactor;device.RenderState.TextureFactor = ( 0xFF << 24 ) | ( (255-76) << 16) | ( (255-150) << 8) |(255- 29);


and the final effect:

Evil Steve
Evil Steve
Quote:
Original post by SirKnight
Couldn't you just use SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3) and set ARG1 to the texture and ARG2 to TFACTOR. Then before you render call SetRenderState( D3DRS_TEXTUREFACTOR, dwTFactor) where dwTFactor is the vector (0.299, 0.587, 0.114) packed into a DWORD. I havn't tried it but it may work.


-SirKnight
Ooh, that's a sexy way to do it. I'd never think of that. [smile] Ratings++
neneboricua19
neneboricua19
Quote:
Original post by SirKnight
Couldn't you just use SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3) and set ARG1 to the texture and ARG2 to TFACTOR. Then before you render call SetRenderState( D3DRS_TEXTUREFACTOR, dwTFactor) where dwTFactor is the vector (0.299, 0.587, 0.114) packed into a DWORD. I havn't tried it but it may work.

Well done, SirKnight. I had forgotten about the TFACTOR thing. Been doing nothing but shaders for the past couple of years so I tend to forget parts of the fixed function pipeline.

neneboricua

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.