Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Palette swap based on light position

Discussion in '2D' started by nantoaqui, Apr 19, 2020.

  1. nantoaqui

    nantoaqui

    Joined:
    Oct 1, 2014
    Posts:
    40
    Hello!

    I'm trying to create this type of art style where dark areas gets its color swapped to a different one preserving only the edge/silhouette color.

    In this example you can see the brick being lit has a greenish color and the unlit area has a dark tone:




    I've tried to apply the concepts from these articles but couldn't get it to work :(

    Shaders Case Study - Pixel Art Palette Swapping -https://www.youtube.com/watch?v=u4Iz5AJa31Q
    Prime31 - SpriteLightKit - https://github.com/prime31/SpriteLightKit
    Stencil Buffer http://prime31.github.io/stencil-buffer-occlusion/
     
  2. vhman

    vhman

    Joined:
    Aug 13, 2018
    Posts:
    267
  3. nantoaqui

    nantoaqui

    Joined:
    Oct 1, 2014
    Posts:
    40
    Hi @vhman ! Thanks for sharing the links!

    I'm trying to apply a different palette outside the mask like the images bellow:

    https://i.imgur.com/yShbDAZ.png

    https://i.imgur.com/lktqvIN.png

    This is the code used in the video:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [ExecuteInEditMode]
    4. public class PaletteSwapMatrix : MonoBehaviour
    5. {
    6.     public Color Color0;
    7.     public Color Color1;
    8.     public Color Color2;
    9.     public Color Color3;
    10.  
    11.     Material _mat;
    12.  
    13.     void OnEnable()
    14.     {
    15.         Shader shader = Shader.Find("Hidden/PaletteSwapMatrix");
    16.         if (_mat == null)
    17.             _mat = new Material(shader);
    18.     }
    19.  
    20.     void OnDisable()
    21.     {
    22.         if (_mat != null)
    23.             DestroyImmediate(_mat);
    24.     }
    25.  
    26.     void OnRenderImage(RenderTexture src, RenderTexture dst)
    27.     {
    28.         _mat.SetMatrix("_ColorMatrix", ColorMatrix);
    29.         Graphics.Blit(src, dst, _mat);
    30.     }
    31.  
    32.     Matrix4x4 ColorMatrix
    33.     {
    34.         get
    35.         {
    36.             Matrix4x4 mat = new Matrix4x4();
    37.             mat.SetRow(0, ColorToVec(Color0));
    38.             mat.SetRow(1, ColorToVec(Color1));
    39.             mat.SetRow(2, ColorToVec(Color2));
    40.             mat.SetRow(3, ColorToVec(Color3));
    41.  
    42.             return mat;
    43.         }
    44.     }
    45.  
    46.     Vector4 ColorToVec(Color color)
    47.     {
    48.         return new Vector4(color.r, color.g, color.b, color.a);
    49.     }
    50. }
    Code (CSharp):
    1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    2.  
    3. Shader "Hidden/PaletteSwapMatrix"
    4. {
    5.     Properties
    6.     {
    7.         _MainTex ("Texture", 2D) = "white" {}
    8.     }
    9.     SubShader
    10.     {
    11.         Cull Off ZWrite Off ZTest Always
    12.  
    13.         Pass
    14.         {
    15.             CGPROGRAM
    16.             #pragma vertex vert
    17.             #pragma fragment frag
    18.            
    19.             #include "UnityCG.cginc"
    20.  
    21.             struct appdata
    22.             {
    23.                 float4 vertex : POSITION;
    24.                 float2 uv : TEXCOORD0;
    25.             };
    26.  
    27.             struct v2f
    28.             {
    29.                 float4 vertex : SV_POSITION;
    30.                 float2 uv : TEXCOORD0;
    31.             };
    32.  
    33.             v2f vert (appdata v)
    34.             {
    35.                 v2f o;
    36.                 o.vertex = UnityObjectToClipPos(v.vertex);
    37.                 o.uv = v.uv;
    38.                 return o;
    39.             }
    40.            
    41.             sampler2D _MainTex;
    42.             half4x4 _ColorMatrix;
    43.  
    44.             fixed4 frag (v2f i) : SV_Target
    45.             {
    46.                 fixed x = tex2D(_MainTex, i.uv).r;
    47.                 return _ColorMatrix[x * 3];
    48.             }
    49.  
    50.             ENDCG
    51.         }
    52.     }
    53. }
    54.  
     
  4. vhman

    vhman

    Joined:
    Aug 13, 2018
    Posts:
    267
    Hi,

    I don't have experience in Shaders. I assume it would be better to have two tilemaps with different palettes and use sprite mask
     
  5. nantoaqui

    nantoaqui

    Joined:
    Oct 1, 2014
    Posts:
    40
    Good news!!! I've spent some time studying shaders and managed to get the effect

    Using SpriteLightKit and make the RenderTexture full black and white we can compare the pixel color:


    Code (CSharp):
    1.  
    2.  
    3. half4 frag( fragmentInput i ) : COLOR
    4. {
    5.     half4 main = tex2D( _MainTex, i.uv );
    6.     half4 lights = tex2D( _LightsTex, i.uv );
    7.         fixed x = tex2D(_MainTex, i.uv).r;
    8.        
    9.     return lights.r > 0.9 ? _MultiplicativeFactor * main * lights : _ColorMatrix[x * 3];
    10. }
    11.  
    I'm checking if the current pixel from LightsText (Black/White) is white. In that case i'm going to render the original image. Otherwise I'll apply the color swapping on black areas.
     
    DeanTheodorakis and vhman like this.
unityunity