如何在Unity中设置整个色彩通道的饱和度水平。

5
我想在我的主摄像机中设置整个颜色通道的饱和度。我找到的最接近的选项是色相与饱和度分级曲线。场景的背景中有一棵被涂成蓝绿色的棕榈树。我希望树的绿色值仍然能显示出来。前景草地的顶部也是如此,它更接近黄色而非绿色,但我仍然希望看到它具有的少量绿色值。
我已经搜索了Unity文档和资产商店数周,但没有找到可能的第三方着色器。我的当前结果是我能想到的最好的,任何帮助都将不胜感激。谢谢。 Current Result

Grading Curve

已解决-通过勾选答案。只是想分享一下结果,以便将来遇到这个问题的人参考。请将上面的截图与下面的截图进行比较,背景中的棕榈树和前景中的草顶只是黑白色的,而下面的截图则完全控制了RGB饱和度!绿黑白 红黑白

2个回答

3

使用此方法的示例: 使用URP的示例


以下是一个后处理着色器,旨在让您设置每个颜色通道的饱和度。 它首先获取原始像素颜色,获取其色调、饱和度和亮度。然后将该颜色转换为最饱和、中性亮度版本。然后将其rgb乘以去饱和因子,以计算新色调的rgb。那个rgb的大小乘以原始饱和度,得到新的饱和度。这个新的色调和饱和度与原始亮度一起计算出新的颜色。
Shader "Custom/ChannelSaturation" {
    Properties{
        _MainTex("Base", 2D) = "white" {}
        _rSat("Red Saturation", Range(0, 1)) = 1
        _gSat("Green Saturation", Range(0, 1)) = 1
        _bSat("Blue Saturation", Range(0, 1)) = 1
    }
        SubShader{
            Pass {
                CGPROGRAM
                #pragma vertex vert_img
                #pragma fragment frag
                #include "UnityCG.cginc"

                uniform sampler2D _MainTex;
                float _rSat;
                float _gSat;
                float _bSat;

                /*
                  source: modified version of https://www.shadertoy.com/view/MsKGRW
                  written @ https://gist.github.com/hiroakioishi/
                            c4eda57c29ae7b2912c4809087d5ffd0
                */
                float3 rgb2hsl(float3 c) {
                    float epsilon = 0.00000001;
                    float cmin = min( c.r, min( c.g, c.b ) );
                    float cmax = max( c.r, max( c.g, c.b ) );
                    float cd   = cmax - cmin;
                    float3 hsl = float3(0.0, 0.0, 0.0);
                    hsl.z = (cmax + cmin) / 2.0;
                    hsl.y = lerp(cd / (cmax + cmin + epsilon), 
                            cd / (epsilon + 2.0 - (cmax + cmin)), 
                            step(0.5, hsl.z));

                    float3 a = float3(1.0 - step(epsilon, abs(cmax - c)));
                    a = lerp(float3(a.x, 0.0, a.z), a, step(0.5, 2.0 - a.x - a.y));
                    a = lerp(float3(a.x, a.y, 0.0), a, step(0.5, 2.0 - a.x - a.z));
                    a = lerp(float3(a.x, a.y, 0.0), a, step(0.5, 2.0 - a.y - a.z));
    
                    hsl.x = dot( float3(0.0, 2.0, 4.0) + ((c.gbr - c.brg) 
                            / (epsilon + cd)), a );
                    hsl.x = (hsl.x + (1.0 - step(0.0, hsl.x) ) * 6.0 ) / 6.0;
                    return hsl;
                }

                /*
                  source: modified version of
                          https://dev59.com/CXE95IYBdhLWcg3wV8e_#42261473
                */
                float3 hsl2rgb(float3 c) {
                    float3 rgb = clamp(abs(fmod(c.x * 6.0 + float3(0.0, 4.0, 2.0),
                            6.0) - 3.0) - 1.0, 0.0, 1.0);
                    return c.z + c.y * (rgb - 0.5) * (1.0 - abs(2.0 * c.z - 1.0));
                }

                float4 frag(v2f_img i) : COLOR {
                    float3 sat = float3(_rSat, _gSat, _bSat);

                    float4 c = tex2D(_MainTex, i.uv);
                    float3 hslOrig = rgb2hsl(c.rgb);

                    float3 rgbFullSat = hsl2rgb(float3(hslOrig.x, 1, .5));
                    float3 diminishedrgb = rgbFullSat * sat;

                    float diminishedHue = rgb2hsl(diminishedrgb).x;

                    float diminishedSat = hslOrig.y * length(diminishedrgb);
                    float3 mix = float3(diminishedHue, diminishedSat, hslOrig.z);
                    float3 newc = hsl2rgb(mix);

                    float4 result = c;
                    result.rgb = newc;

                    return result;
                }
                ENDCG
            }
        }
}

如果您正在使用建议使用的URP(通用渲染管线),您可以创建一个新的前向渲染管线资产,将着色器分配给该资产,并适当配置它。更多信息,包括图表,可以在Unity官方教程中找到使用URP自定义渲染通道
如果您没有使用URP,您还有其他选择。您可以将其附加到特定的材质上,或者使用来自Wikibooks的以下脚本将该材质作为后处理效果应用于相机,使用上述着色器:
using System;
using UnityEngine;

[RequireComponent(typeof(Camera))]
[ExecuteInEditMode]

public class PostProcessingEffectScript : MonoBehaviour {

   public Material material;
   
   void OnEnable() 
   {
      if (null == material || null == material.shader || 
         !material.shader.isSupported)
      {
         enabled = false;
      } 
   }

   void OnRenderImage(RenderTexture source, RenderTexture destination)
   {
      Graphics.Blit(source, destination, material);
   }
}

如果您使用后处理效果,则需要使用不同的相机渲染要从效果中排除的内容,然后将所有内容合在一起。但是,这超出了本答案的范围。

1
太好了!你上次的修改起作用了!在你之前把代码拿下来之前,我已经复制了它并进行了一些更改,但没有你对frag方法的重写。感谢你的工作,冷却期明天到时会发送赏金。 - Rickest Rick
1
哇,渲染管道的步骤讲解得真好...可惜你没有在30分钟前发布! :) - Rickest Rick

-1

我的最佳猜测是使用自定义着色器或相机特效,这将使您对每个通道具有控制权。

希望这有所帮助;)


嗨,Thomas,你有特定的着色器想法吗?我已经尝试在资产商店中查找,但还没有找到我要找的东西。我已经为这个问题开始了50pt的赏金,如果你能找到我要找的内容并将其添加到你的答案中! - Rickest Rick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接