HLSL Pixel Shader - change the color of the image for a specific hue

I would like to write a pixel shader that takes an input image and converts all the colors in one hue range (i.e. HSV) to another hue range.

My motivation is simple: I want to paint a bunch of different textures in different ways, but I do not want to color the entire texture, just a part with a hue in a certain range. Thus, I can draw one image of a racing car, and then change the color of only the stripes and logo on a car with a pixel shader.

I looked at the HLSL documentation online and couldn't find anything to handle the shades. Is there an HLSL code library available on the Internet?

Here is some pseudo code for what I'm trying to execute:

external float SrcMinHue,SrcMaxHue,TargetMin void changeHues(image source) { foreach x,y in image: { float sourceHue = getHue(source,x,y) if (SrcMinHue < sourceHue < SrcNaxHue): setHue(source,x,y,(TargetMin + (sourceHue - MinHue)) } } 

I work with XNA Game Studio if this information is important to everyone.

+4
source share
4 answers

Take a look at the β€œpost RGB to HSV” sample on the NVidia Shader Library page . This may give you some inspiration.

Otherwise, I think you could "just" convert the RGB color to HSV in your pixel shader using the formula from Wikipedia , and then take it from there.

+6
source

Make a matrix that rotates the RGB color around the [1,1,1] axis (brightness axis) * by an angle that will rotate the source color to your target color. Set this matrix as the pixel shader constant.

In the pixel shader, convert the pixel color to this matrix. Then take a liper between the untransformed and converted colors in accordance with the angle between the untranslated hue of the pixel and the hue of the source. When the angle is small, use the converted color. When the angle is large, use an untransformed color.

To determine the hue of a pixel, subtract the average of its RGB * from the pixel. The angle between this vector and [1,0,0] is the hue.

* I know that brightness is not so simple, but this is a good enough approximation for this case.

+3
source

Hue / Saturation / Brightness / Contrast HLSL pixel shader (shazzam.fx)

 /// <class>7Aliens HSBC Hue/Saturation/Brightness/Contrast</class> /// <description>Blend modes Brightness/Contrast (Photoshop CS) with Hue and Saturation.</description> sampler2D input : register(s0); /// <summary>The brightness offset.</summary> /// <minValue>-2</minValue> /// <maxValue>2</maxValue> /// <defaultValue>0</defaultValue> float SliderBrightnes : register(C0); /// <summary>The brightness offset.</summary> /// <minValue>-1</minValue> /// <maxValue>1</maxValue> /// <defaultValue>0</defaultValue> float SliderContrast : register(C1); /// <summary>The brightness offset.</summary> /// <minValue>-1</minValue> /// <maxValue>1</maxValue> /// <defaultValue>0</defaultValue> float sliderSaturation : register(C2); /// <summary>The brightness offset.</summary> /// <minValue>-180</minValue> /// <maxValue>180</maxValue> /// <defaultValue>0</defaultValue> float sliderHue : register(C3); float3x3 QuaternionToMatrix(float4 quat) { float3 cross = quat.yzx * quat.zxy; float3 square= quat.xyz * quat.xyz; float3 wimag = quat.w * quat.xyz; square = square.xyz + square.yzx; float3 diag = 0.5 - square; float3 a = (cross + wimag); float3 b = (cross - wimag); return float3x3( 2.0 * float3(diag.x, bz, ay), 2.0 * float3(az, diag.y, bx), 2.0 * float3(by, ax, diag.z)); } const float3 lumCoeff = float3(0.2125, 0.7154, 0.0721); float4 Desaturate(float3 color, float Desaturation) { float3 grayXfer = float3(0.3, 0.59, 0.11); float grayf = dot(grayXfer, color); float3 gray = float3(grayf, grayf, grayf); return float4(lerp(color, gray, Desaturation), 1.0); } float4 main(float2 uv : TEXCOORD) : COLOR { float4 cInput; cInput = tex2D( input , uv.xy); float4 inputColor; inputColor = cInput; float4 blendColor; blendColor = cInput; float4 resultColor; resultColor = cInput; float3 hsv; float3 intensity; float3 root3 = float3(0.57735, 0.57735, 0.57735); float half_angle = 0.5 * radians(sliderHue); // Hue is radians of 0 tp 360 degree float4 rot_quat = float4( (root3 * sin(half_angle)), cos(half_angle)); float3x3 rot_Matrix = QuaternionToMatrix(rot_quat); resultColor.rgb = mul(rot_Matrix, inputColor.rgb); resultColor = Desaturate(resultColor, -sliderSaturation); inputColor = resultColor;`enter code here` blendColor = resultColor; resultColor = resultColor; blendColor.rgb = clamp(blendColor.rgb / blendColor.a, 0, 1); if (resultColor.r > 0.5) resultColor.r = 1 - (1 - 2 * (resultColor.r - 0.5)) * (1 - blendColor.r); else resultColor.r = (2 * resultColor.r) * blendColor.r; if (resultColor.g > 0.5) resultColor.g = 1 - (1 - 2 * (resultColor.g - 0.5)) * (1 - blendColor.g); else resultColor.g = (2 * resultColor.g) * blendColor.g; if (resultColor.b > 0.5) resultColor.b = 1 - (1 - 2 * (resultColor.b - 0.5)) * (1 - blendColor.b); else resultColor.b = (2 * resultColor.b) * blendColor.b; float4 colorOverlay = resultColor; colorOverlay = colorOverlay * SliderContrast; resultColor.rgb = (1 - (colorOverlay.a)) * inputColor.rgb + colorOverlay.rgb; inputColor = resultColor; blendColor = resultColor; float4 colorScreen = resultColor; colorScreen.rgb = (1.0f - (1.0f - inputColor.rgb) * (1.0f - blendColor.rgb)); colorScreen = -(colorScreen * SliderBrightnes * -(1 - inputColor.r)); resultColor.rgb = (1 - (colorScreen.a)) * inputColor.rgb + colorScreen.rgb; return resultColor; } 
+1
source

All Articles