如何在Unity中设置整个颜色通道的饱和度
How to set the saturation level of an entire color channel in Unity
我想在我的主相机中设置整个颜色通道的饱和度。我找到的最接近的选项是 Hue vs. Sat(uration) 分级曲线。场景的背景是一棵蓝绿色的棕榈树。我希望树的绿色水平仍然显示。和前景草的顶部一样,比绿色更接近黄色,但我还是想看看它有一点绿色价值。
数周以来,我一直在 Unity 文档和资产商店中搜索可能的第 3 方着色器,但一无所获。我目前的结果是我能想到的最好结果,任何帮助将不胜感激。谢谢
已解决
- 通过勾选答案。只是想与将来偶然发现此问题的任何人分享结果。比较上面的屏幕截图,其中背景中的棕榈树和前景中的草顶只是黑色和白色,与下面的屏幕截图相比。在RGB饱和度的场景中全面掌控!
我最好的猜测是使用自定义着色器或相机 FX,让您可以控制每个通道。
希望对您有所帮助 ;)
下面是一个后处理着色器,旨在让您设置每个颜色通道的饱和度。
它首先取原始像素颜色,得到色相、饱和度和亮度。该颜色采用其最饱和的中性亮度版本。然后将其 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
*/
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(通用渲染管线),您可以创建一个新的前向渲染器管线资产,将着色器分配给该资产,并适当地配置它。可以在 custom render passes with URP.
的官方统一教程中找到包括图表在内的更多信息
如果您不使用 URP,您还有其他选择。您可以将它附加到特定的 materials,或者使用来自 Wikibooks 的以下脚本到相机的游戏对象,以使用上述着色器将 material 作为后处理效果应用于相机:
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);
}
}
如果你使用后处理效果,你会想用不同的相机渲染你想从效果中排除的东西,然后把所有东西放在一起。但是,这有点超出了这个答案的范围。
我想在我的主相机中设置整个颜色通道的饱和度。我找到的最接近的选项是 Hue vs. Sat(uration) 分级曲线。场景的背景是一棵蓝绿色的棕榈树。我希望树的绿色水平仍然显示。和前景草的顶部一样,比绿色更接近黄色,但我还是想看看它有一点绿色价值。
数周以来,我一直在 Unity 文档和资产商店中搜索可能的第 3 方着色器,但一无所获。我目前的结果是我能想到的最好结果,任何帮助将不胜感激。谢谢
已解决
- 通过勾选答案。只是想与将来偶然发现此问题的任何人分享结果。比较上面的屏幕截图,其中背景中的棕榈树和前景中的草顶只是黑色和白色,与下面的屏幕截图相比。在RGB饱和度的场景中全面掌控!
我最好的猜测是使用自定义着色器或相机 FX,让您可以控制每个通道。
希望对您有所帮助 ;)
下面是一个后处理着色器,旨在让您设置每个颜色通道的饱和度。
它首先取原始像素颜色,得到色相、饱和度和亮度。该颜色采用其最饱和的中性亮度版本。然后将其 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
*/
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(通用渲染管线),您可以创建一个新的前向渲染器管线资产,将着色器分配给该资产,并适当地配置它。可以在 custom render passes with URP.
的官方统一教程中找到包括图表在内的更多信息如果您不使用 URP,您还有其他选择。您可以将它附加到特定的 materials,或者使用来自 Wikibooks 的以下脚本到相机的游戏对象,以使用上述着色器将 material 作为后处理效果应用于相机:
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);
}
}
如果你使用后处理效果,你会想用不同的相机渲染你想从效果中排除的东西,然后把所有东西放在一起。但是,这有点超出了这个答案的范围。