HLSL Pixel Shader - 更改特定色调的图像颜色

发布于 2024-08-03 18:22:06 字数 591 浏览 7 评论 0原文

我想编写一个像素着色器,它获取输入图像,并将一个色调范围(即 HSV)的所有颜色转换为另一个色调范围。

我的动机很简单:我想对一堆不同的纹理进行不同的着色,但我不想对整个纹理进行着色,而只是对色调在特定范围内的部分进行着色。这样,我可以绘制一辆赛车的图像,然后使用像素着色器仅更改汽车上的条纹和徽标的颜色。

我在线查看了 HLSL 文档,找不到任何处理色调的内容。是否有在线可用的 HLSL 代码库?

这是我想要完成的一些伪代码:

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))
   }
}

我正在与 XNA Game Studio 合作,如果该信息对任何人都很重要。

I'd like to write a pixel shader that takes an input image, and converts all of the colors of one Hue range (i.e. HSV) into another Hue Range.

My motivation is simple: I want to color a bunch of different textures differently, but i don't want to color the entire texture, just the portion with a hue in a specific range. That way, I can draw one image of a racing car, and then change the color of just the stripes and the logo on the car with a pixel shader.

I looked at the HLSL documentation online and couldn't find anything to deal with hues. Is there a library of HLSL code available online?

Here's some pseudocode for what i'm trying to accomplish:

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'm working with XNA Game Studio, if that information matters to anyone.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

话少心凉 2024-08-10 18:22:06

Take a look at the "post RGB to HSV" sample over at the NVidia Shader Library page. That might give you some inspiration.

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

半世蒼涼 2024-08-10 18:22:06

创建一个矩阵,将 RGB 颜色围绕 [1,1,1] 轴(亮度轴)* 旋转一定角度,从而将源颜色旋转到目标颜色。将此矩阵设置为像素着色器常量。

在像素着色器中,通过该矩阵变换像素颜色。然后,根据未变换像素的色调和源颜色的色调之间的角度,在未变换和变换的颜色之间进行 lerp。当角度较小时,使用变换后的颜色。当角度较大时,使用未变换的颜色。

要确定像素的色调,请从该像素中减去其 RGB* 的平均值。该向量与 [1,0,0] 之间的角度就是色调。

*我知道亮度并不是这么简单,但对于这种情况来说,这是一个足够好的近似值。

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

In the pixel shader, transform the pixel color by this matrix. Then, lerp between the untransformed and transformed colors, according to the angle between the untransformed pixel's hue and the source color's hue. When the angle is small, use the transformed color. When the angle is large, use the 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'm aware that luminance is not this simple, but this is a good enough approximation for this case.

诺曦 2024-08-10 18:22:06

色相/饱和度/亮度/对比度 HLSL 像素着色器 (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, b.z, a.y),
    2.0 * float3(a.z, diag.y, b.x),
    2.0 * float3(b.y, a.x, 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; 
}

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, b.z, a.y),
    2.0 * float3(a.z, diag.y, b.x),
    2.0 * float3(b.y, a.x, 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; 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文