变色Shader-将游戏中的红色变为符合和谐要求的其他颜色

最近在做国内版本的合规工作,其中一项要求是游戏里不能出现代表血腥的红色(嗯?),鉴于红色是一个很常见的颜色,我就在思考是否可以通过后期效果的方式将红色转为其他颜色,以节约巨大的工作量。

做了一些尝试之后,我做了一个版本,还算符合要求,以下是我的解决方案:
(最后面附上了效果对比)

C# 脚本

using UnityEngine;  
using UnityEngine.Rendering;

[ExecuteInEditMode, ImageEffectAllowedInSceneView]
public class ColorSwapEffect : MonoBehaviour  
{
    [SerializeField]
    private Material effectMaterial;

    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (effectMaterial != null)
        {
            Graphics.Blit(src, dest, effectMaterial);
        }
        else
        {
            Graphics.Blit(src, dest);
        }
    }
}

Shader

fixed4 _Color = fixed4(60.0f / 255.0f, 69.0f / 255.0f, 85.0f / 255.0f, 1);

fixed4 frag(v2f i) : SV_Target  
                {
                    fixed4 col = tex2D(_MainTex, i.uv);
                    fixed4 newCol = col;

                    // swap colors

                    fixed offset_g = col.r - col.g;
                    fixed offset_b = col.r - col.b;

                    if (offset_g < 0)
                    {
                        offset_g = 0;
                    }

                    if (offset_b < 0)
                    {
                        offset_b = 0;
                    }

                    fixed offset_gv = col.g /col.r;
                    fixed offset_bv = col.b / col.r;

                    fixed offset =  ( offset_g + offset_b / (col.r * 2));

                    fixed luminance = dot(col.rgb, fixed3(0.299, 0.587, 0.114));

                    if (offset > 0.2)
                    {
                        if (offset_gv < 0.75 && offset_bv < 0.75 && offset > 0.1)
                        {
                            newCol = lerp(col, _Color, 0.2f);
                        }

                        if (offset_gv < 0.65 && offset_bv < 0.65 && offset > 0.1)
                        {
                            newCol = lerp(col, _Color, 0.4f);
                        }

                        if (offset_gv < 0.55f && offset_bv < 0.55f && offset > 0.2f)
                        {
                            newCol = lerp(col, _Color, 0.6f);
                        }

                        if (offset_gv < 0.45f && offset_bv < 0.45f && offset > 0.2f)
                        {
                            newCol = lerp(col, _Color, 0.9f);
                        }

                        if (offset_gv < 0.35f && offset_bv < 0.35f && offset > 0.2f)
                        {
                            newCol = lerp(col, _Color, 1);
                        }
                    }

                    fixed newluminance = dot(newCol.rgb, fixed3(0.299, 0.587, 0.114));
                    newCol.rgb *= luminance / newluminance;
                    col = lerp(col, newCol, _ColorSwap);

                    return col;
                }

其实这个问题的本质就是如何识别红色,以及如何将其转换为另外一个颜色的同时,不显著的影响整个画面的美观性,我的思路就是从rgb的相对值出发,如果r的值显著大于了gb两个颜色,则将其视为红色,并根据差别的大小,阶段式地用不同的插值参数。

最终再基于原来的亮度,对新的色彩亮度进行还原。

失去红色之后,整个画面会变得大伤元气,有一种阴森的感觉,但相比起将游戏中的素材大大改一遍相比

变色前
变色前1 变色前2

变色后 变色后1 变色后2

kisence

潮落江平未有风。