Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Different Blending Modes like Add/ Screen/ Overlay + changing Hue/ Tint

Discussion in 'Shaders' started by Senshi, Oct 3, 2010.

  1. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    528
    Hello everyone,

    I'm currently making my first Unity game for my Game Design class and thus learning the ropes with JavaScript, the engine and now ShaderLab.
    I'm trying to get multiple textures on one material to be layered on top of each other, some with different blending modes. I found some GLSL and HLSL documentation (included as an attachment) on this, but I'm not sure how I can implement it in my Shader. I've set up the Base Color and Texture slots, as well as a Hue slider. My two main questions are as follows:

    1) How can I set a Texture's blending mode to Overlay/ Add? I understand the SetTexture and Combine principle, but I don't know how to apply it for these specific Blending Modes.

    2) How can I control a Texture's Hue/ Tint?

    Also, am I correct in assuming these values can be changed real-time by means of a GUI or an in-game event using the getComponent() function?

    Thanks in advance,
    Patrick
     

    Attached Files:

  2. the_gnoblin

    the_gnoblin

    Joined:
    Jan 10, 2009
    Posts:
    722
    I hope this helps

    Code (csharp):
    1. Shader "ChannelBlend/DiffuseAdd" {
    2. Properties {
    3.       _MainTex ("Texture", 2D) = "white" {}
    4.       _BlendTex ("Texture", 2D) = "white" {}
    5.     }
    6.  
    7.     SubShader {
    8.       Tags { "RenderType" = "Opaque" }
    9.       CGPROGRAM
    10.       #pragma surface surf Lambert
    11.       struct Input {
    12.           float2 uv_MainTex;
    13.  
    14.       };
    15.       sampler2D _MainTex;
    16.           sampler2D _BlendTex;
    17.  
    18.       void surf (Input IN, inout SurfaceOutput o) {
    19.         o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    20.         half3 blend = tex2D (_BlendTex, IN.uv_MainTex).rgb;
    21.                
    22.                 //I think this can be optimized a bit
    23.                 o.Albedo.r = min(1.0, o.Albedo.r + blend.r);
    24.                 o.Albedo.g = min(1.0, o.Albedo.g + blend.g);
    25.                 o.Albedo.b = min(1.0, o.Albedo.b + blend.b);
    26.       }
    27.       ENDCG
    28.     }
    29.     Fallback "Diffuse"
    30.   }
     
  3. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
    Most photoshop blending styles cannot be expressed on the GPU itself. The three most common hardware supported blending styles are 'blend' ('normal' in photoshop), 'additive' (linear dodge/add) and 'multiply' (multiply). You will find several shaders in the particle section of the built-in shaders that implement these. Other popular blending styles, like photoshop's screen, simply cannot be expressed on the GPU. You will have to try and avoid using such effects when designing for GPU rendered games.

    Affecting a texture's hue or tint can be done in hardware (by writing custom shaders), although hue will require quite an extensive shader (GPU's only support RGB, so the shader will need to implement the RGB to HSL conversion). For the Battlebot game we made, the customizer does the hue conversion of the textures in script, rather than the shader. I believe there are scripts on the Unify wiki for HSL/RGB conversion to help you with that, but it will be some programming work.

    Edit: After checking your attachment, which contains photoshop implementations for blend effects, I feel I need to clarify: you can use any photoshop blending type for colors within a single shader on a single object. However, as far as I know, you just cannot use them between different objects, as you cannot use shader programs to control the blending with the framebuffer. Sadly, using these effects between different objects is by far the most useful application.
     
    Last edited: Oct 22, 2010
  4. the_gnoblin

    the_gnoblin

    Joined:
    Jan 10, 2009
    Posts:
    722
    I hope this also helps.

    Code (csharp):
    1. Shader "HSB_HSV_Colorpicker_cutdown" {
    2.     Properties {
    3.       _MainTex ("Texture", 2D) = "white" {}
    4.       _HueShift("HueShift", Float) = 0
    5.     }
    6.     SubShader {
    7.       Tags { "RenderType" = "Opaque" }
    8.       CGPROGRAM
    9.       #pragma surface surf Lambert
    10.       #pragma target 3.0        
    11.  
    12.         float3 hsv_to_rgb(float3 HSV)
    13.         {
    14.                 float3 RGB = HSV.z;
    15.            
    16.                    float var_h = HSV.x * 6;
    17.                    float var_i = floor(var_h);   // Or ... var_i = floor( var_h )
    18.                    float var_1 = HSV.z * (1.0 - HSV.y);
    19.                    float var_2 = HSV.z * (1.0 - HSV.y * (var_h-var_i));
    20.                    float var_3 = HSV.z * (1.0 - HSV.y * (1-(var_h-var_i)));
    21.                    if      (var_i == 0) { RGB = float3(HSV.z, var_3, var_1); }
    22.                    else if (var_i == 1) { RGB = float3(var_2, HSV.z, var_1); }
    23.                    else if (var_i == 2) { RGB = float3(var_1, HSV.z, var_3); }
    24.                    else if (var_i == 3) { RGB = float3(var_1, var_2, HSV.z); }
    25.                    else if (var_i == 4) { RGB = float3(var_3, var_1, HSV.z); }
    26.                    else                 { RGB = float3(HSV.z, var_1, var_2); }
    27.            
    28.            return (RGB);
    29.         }
    30.  
    31.       struct Input {
    32.           float2 uv_MainTex;
    33.       };
    34.      
    35.       float _HueShift;
    36.      
    37.       void surf (Input IN, inout SurfaceOutput o)
    38.       {
    39.           float3 hsv = float3(_HueShift, IN.uv_MainTex.x, IN.uv_MainTex.y);
    40.           if ( hsv.x > 1.0 ) { hsv.x -= 1.0; }
    41.           o.Albedo = half3(hsv_to_rgb(hsv));
    42.       }
    43.      
    44.       ENDCG
    45.     }
    46.     Fallback "Diffuse"
    47.   }
     
  5. the_gnoblin

    the_gnoblin

    Joined:
    Jan 10, 2009
    Posts:
    722
    And here's a version that does two way conversion and modifies _MainTex (the previous one just generates something that looks like photoshop hsb colorpicker).

    Code (csharp):
    1. Shader "HSB_HSV_Colorpicker" {
    2.     Properties {
    3.       _MainTex ("Texture", 2D) = "white" {}
    4.       _HueShift("HueShift", Float) = 0
    5.     }
    6.     SubShader {
    7.       Tags { "RenderType" = "Opaque" }
    8.       CGPROGRAM
    9.       #pragma surface surf Lambert
    10.       #pragma target 3.0
    11.          
    12.         float3 rgb_to_hsv_no_clip(float3 RGB)
    13.         {
    14.                 float3 HSV;
    15.            
    16.          float minChannel, maxChannel;
    17.          if (RGB.x > RGB.y) {
    18.           maxChannel = RGB.x;
    19.           minChannel = RGB.y;
    20.          }
    21.          else {
    22.           maxChannel = RGB.y;
    23.           minChannel = RGB.x;
    24.          }
    25.          
    26.          if (RGB.z > maxChannel) maxChannel = RGB.z;
    27.          if (RGB.z < minChannel) minChannel = RGB.z;
    28.            
    29.                 HSV.xy = 0;
    30.                 HSV.z = maxChannel;
    31.                 float delta = maxChannel - minChannel;             //Delta RGB value
    32.                 if (delta != 0) {                    // If gray, leave H  S at zero
    33.                    HSV.y = delta / HSV.z;
    34.                    float3 delRGB;
    35.                    delRGB = (HSV.zzz - RGB + 3*delta) / (6.0*delta);
    36.                    if      ( RGB.x == HSV.z ) HSV.x = delRGB.z - delRGB.y;
    37.                    else if ( RGB.y == HSV.z ) HSV.x = ( 1.0/3.0) + delRGB.x - delRGB.z;
    38.                    else if ( RGB.z == HSV.z ) HSV.x = ( 2.0/3.0) + delRGB.y - delRGB.x;
    39.                 }
    40.                 return (HSV);
    41.         }
    42.  
    43.         float3 hsv_to_rgb(float3 HSV)
    44.         {
    45.                 float3 RGB = HSV.z;
    46.            
    47.                    float var_h = HSV.x * 6;
    48.                    float var_i = floor(var_h);   // Or ... var_i = floor( var_h )
    49.                    float var_1 = HSV.z * (1.0 - HSV.y);
    50.                    float var_2 = HSV.z * (1.0 - HSV.y * (var_h-var_i));
    51.                    float var_3 = HSV.z * (1.0 - HSV.y * (1-(var_h-var_i)));
    52.                    if      (var_i == 0) { RGB = float3(HSV.z, var_3, var_1); }
    53.                    else if (var_i == 1) { RGB = float3(var_2, HSV.z, var_1); }
    54.                    else if (var_i == 2) { RGB = float3(var_1, HSV.z, var_3); }
    55.                    else if (var_i == 3) { RGB = float3(var_1, var_2, HSV.z); }
    56.                    else if (var_i == 4) { RGB = float3(var_3, var_1, HSV.z); }
    57.                    else                 { RGB = float3(HSV.z, var_1, var_2); }
    58.            
    59.            return (RGB);
    60.         }
    61.  
    62.       struct Input {
    63.           float2 uv_MainTex;
    64.       };
    65.      
    66.       sampler2D _MainTex;
    67.       float _HueShift;
    68.      
    69.       void surf (Input IN, inout SurfaceOutput o) {
    70.           o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    71.          
    72.           float3 hsv = rgb_to_hsv_no_clip(o.Albedo.xyz);
    73.           hsv.x+=_HueShift;
    74.                  
    75.           if ( hsv.x > 1.0 ) { hsv.x -= 1.0; }
    76.           o.Albedo = half3(hsv_to_rgb(hsv));
    77.  
    78.       }
    79.      
    80.       ENDCG
    81.     }
    82.     Fallback "Diffuse"
    83.   }
     
  6. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    528
    o_O I'm so sorry, I can't believe I never noticed these answers! I'll be sure to give it all a try, thank you both so much!! =D
    @Tom: Blending multiple textures on a single object is all I need luckily! =)
     
  7. AIResearcher

    AIResearcher

    Joined:
    Aug 23, 2010
    Posts:
    39
    I can't seem to get these to work in the new Unity3d 3.5. I'm not sure what changed in Shaders or how to go about fixing it.
     
  8. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    528
    Woah, nostalgia topic!

    Anywho, I just did a quick test on two of the shaders and they both worked just fine. Where are yuu experiencing trouble? To use these shaders you have to:
    - Create a new shader (.shader file) and copy the shader code into this.
    - Create a new material and set it to use that newly created shader.

    -Patrick
     
  9. allesisda

    allesisda

    Joined:
    Jan 14, 2013
    Posts:
    3
    does anyone have a shader for photoshop "screen"?
    also known as negative multiply...

    the code should be output= 1-((1-a)*(1-b))

    so it should be something like OneMinus (OneMinusSourceColor)* (OneMinusDstColor)
     
  10. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,356
    I think you might be misunderstanding what shaders do. "Screen" is one type of blending operation. There are an infinite number of possible shaders that use a screen operation somewhere.

    If you're looking for parameters to the Blend command that will produce a screen blend, that's unfortunately not possible due to the limitations of fixed function blending. To get a screen operation into the final blend, you would need to get the destination colour from a more versatile source, such as a GrabPass. The documentation for GrabPass is here.
     
  11. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,699
    Actually you can do `Screen` using the blending hardware. I did it in my Shader Wizard asset. But other ones like Overlay, Hard Light etc you can only do between two textures within the shader, and not against the backbuffer.
     
  12. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,356
    I must be missing something, then. Screen reduces like this:

    1 - (1 - a) (1 - b)
    1 - 1 + a + b - ab
    a + b - ab

    The closest I can get is:

    Code (csharp):
    1. BlendOp Sub
    2. DstColor One
    Which gives you:

    1 * b - b * a
    b - ab

    ...which is of course missing the a term.
     
  13. allesisda

    allesisda

    Joined:
    Jan 14, 2013
    Posts:
    3
    GrabPass is not working for me...

    thanks for the answers!

    sry imaginaryhuman but i dont have the money for your plugins, but they look very nice!

    Daniel, can you give me a shadercode example for implementing this?
     
  14. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,356
    Perhaps you don't have Unity Pro? GrabPass is a Pro-only feature.

    If Imaginary Human tells us how to accomplish screen blending using blending hardware, then you shouldn't need Pro.
     
  15. Elringus

    Elringus

    Joined:
    Oct 3, 2012
    Posts:
    523
    A was able to reproduce some of the blend modes without GrabPass with the help of Blend and BlendOp commands.

    Darken:
    BlendOp Min
    Blend One One​

    Lighten:
    BlendOp Max
    Blend One One​

    Linear Burn:
    BlendOp RevSub
    Blend One One​

    Linear Dodge:
    Blend One One​

    Multiply:
    Blend DstColor OneMinusSrcAlpha​

    All the others are achievable with GrabPass.

    btw, I have a package on the store, that allow to easily apply all the blend modes (22, like in Photoshop) to GUI elements: https://www.assetstore.unity3d.com/en/#!/content/28238
     
    GreedyVox, flashframe and rakkarage like this.
  16. Dolkar

    Dolkar

    Joined:
    Jun 8, 2013
    Posts:
    576
    Hmm, let's see... You were quite close:
    a + b - ab
    can be also expressed as:
    a + (1 - a) * b
    which can be translated as a simple addition:
    Blend One OneMinusSrcColor
    or symmetrically:
    Blend OneMinusDstColor One

    which is already included in the manual as "Soft Additive" blending... Maybe it needs some clarification that it's equivalent to Screen blending?
     
    Last edited: Feb 4, 2015
  17. pvzkiller

    pvzkiller

    Joined:
    Oct 3, 2012
    Posts:
    7
    And for simulating the "Color" Photoshop layer effect? I can reward anybody with a working Unity shader, because I am really unable to find this anywhere on Google.
     
  18. Dolkar

    Dolkar

    Joined:
    Jun 8, 2013
    Posts:
    576
    If you specify color blending as just multiplying the destination color with a luminosity normalized source color, then it can be done with just hardware blending as well... Otherwise you will need to have it either as a post processing effect or use grab pass or command buffer magic. PM me the details if you want me to write you one.
     
unityunity