Шейдер для 1-битной цветовой палитры + VFX ramp

Я делаю игру Unity с “1-битной” цветовой палитрой, а-ля Даунвелл – подавляющее большинство экрана будет черно-белым, но, в отличие от настоящей 1-битной графики, некоторые блики и визуальные эффекты будут использовать дополнительные цвета. В моем случае эти эффекты будут выводить значения в диапазоне цветов, составляющих одну цветовую шкалу – по умолчанию все цвета от зеленого до розового включительно. Это также игра с низким разрешением и большими пикселями, в которой используется пиксельная идеальная камера пакет, чтобы обеспечить это.

Я хочу иметь возможность переключать точные значения черного, белого и цветовой шкалы, которые используются во время выполнения, так же, как это делает Даунвелл, благодаря возможности разблокировать дополнительные палитры. Похоже, это хорошая работа для шейдеров, поэтому я наконец взялся за дело и написал для этого шейдерный код. Теперь я хочу проверить, есть ли возможности для улучшения с точки зрения потенциальных узких мест в производительности или общего стиля шейдеров.

Этот компонент прикреплен к основной камере:

using UnityEngine;

public class ColorPaletteApplier : MonoBehaviour
{
    public Material Material;

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

И это шейдер, который я написал:

Shader "Color Palette"
{
    Properties
    {
        [PerRendererData] _MainTex ("Texture", 2D) = "white" {}
        _BlackColor ("Black Color", Color) = (0, 0, 0, 1)
        _WhiteColor ("White Color", Color) = (1, 1, 1, 1)
        _RampTex ("Ramp LUT", 2D) = "defaulttexture" {}
    }

    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex, _RampTex;
            float4 _BlackColor, _WhiteColor;

            inline fixed4 convertBlackAndWhite (fixed4 input)
            {
                bool closerToWhite = round(input.r);
                return closerToWhite ? _WhiteColor : _BlackColor;
            }

            // input is assumed to be somewhere on a lerp between (0, 1, 0) and (1, 1, 0)
            // these colors are chosen so that one channel goes from 0 to 1, the other two channels are always the same value, and all three channels are never equal
            inline fixed4 convertEffectRamp (fixed4 input)
            {
                float i = input.r;
                
                // for effect pixels that break the g or b assumptions, we can assume they occupy subpixel positions and that the pixel perfect camera averaged their true value with the background pixel. we'll fix that by making the effects override the background color
                if (input.g == 0.5)
                {
                    // undo average with black
                    i *= 2;
                }
                else if (input.b == 0.5)
                {
                    // undo average with white
                    i = i * 2 - 1;
                }

                return tex2D(_RampTex, i);
            }

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

                return (col.r == col.g && col.g == col.b) ? convertBlackAndWhite(col) : convertEffectRamp(col);
            }
            ENDCG
        }
    }
}

Я использую PNG 128×1 для текстуры поиска рампы.

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *