1. Help us improve the editor usability and artist workflows. Join our discussion to provide your feedback.
    Dismiss Notice
  2. We're looking for feedback on Unity Starter Kits! Let us know what you’d like.
    Dismiss Notice
  3. We’re giving 2017.1 beta testers a chance to win t-shirts and a Nintendo Switch. Read more on the blog.
    Dismiss Notice
  4. We want to know how you learned Unity! Help us by taking this quick survey and have a chance at a $25 gift card
    Dismiss Notice
  5. Unity 5.6 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice

Achieving a multi pass effect with a Surface Shader

Discussion in 'Shaders' started by Sycle, Jul 12, 2011.

  1. Sycle

    Sycle

    Joined:
    Nov 24, 2009
    Posts:
    446
    Heya! I've been scratching my head over this and was hoping someone might be able to point me in the right direction.

    I'm trying to add a silhouette effect to some characters so they're visible through objects, this is a mockup of what I'm going for :

    [​IMG]

    Normally I'd do this with a flat shaded second pass which uses "ztest Greater" but I'm using a Surface Shader which don't seem compatible with additional passes.

    Is there a way to do this or get an equivalent result while still using a Surface Shader?

    Code (csharp):
    1. Shader "Character Indicator" {
    2. Properties {
    3.     _Color ("Main Color", Color) = (1,1,1,1)
    4.     _MainTex ("Base (RGB)", 2D) = "white" {}
    5.     _WrapTex ("Wrap ramp (RGBA)", 2D) = "black" {}
    6.     _IndicatorTex ("Indicator Lights (RGB)", 2D) = "white" {}
    7.     _Indicator ("Indicator Color", Color) = (1,1,1,1)
    8.     _Cutoff ("Alpha cutoff", Range (0,1)) = 0.0
    9. }
    10.  
    11. SubShader {
    12.     Tags { "RenderType" = "Opaque" }
    13.  
    14. CGPROGRAM
    15. #pragma surface surf Ramp alphatest:_Cutoff
    16.  
    17. uniform float4 _Color;
    18. uniform float4 _Indicator;
    19. uniform sampler2D _MainTex;
    20. uniform sampler2D _WrapTex;
    21. uniform sampler2D _IndicatorTex;
    22.  
    23. half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {
    24.     half NdotL = dot (s.Normal, lightDir);
    25.     half diff = NdotL * 0.5 + 0.5;
    26.     half3 ramp = tex2D (_WrapTex, float2(diff)).rgb;
    27.     half4 c;
    28.     c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
    29.     c.a = s.Alpha;
    30.     return c;
    31. }
    32.  
    33. struct Input {
    34.     float2 uv_MainTex;
    35.     float2 uv_BumpMap;
    36.     float3 viewDir;
    37. };
    38.  
    39. void surf (Input IN, inout SurfaceOutput o) {
    40.     o.Albedo = tex2D ( _MainTex, IN.uv_MainTex).rgb * _Color;
    41.     o.Emission = tex2D ( _IndicatorTex, IN.uv_MainTex).rgb * _Indicator * 2;
    42.    
    43.     half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
    44.     o.Emission += tex2D ( _MainTex, IN.uv_MainTex).rgb * 2 * pow (rim, 3.0);
    45.     o.Alpha = tex2D ( _MainTex, IN.uv_MainTex).a;
    46. }
    47.  
    48. ENDCG
    49.  
    50. }
    51.  
    52. Fallback " Glossy", 0
    53.  
    54. }
    Any help would be much appreciated!
     
  2. Daniel-Brauer

    Daniel-Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,314
    You can't add arbitrary passes with surface shaders, but what you can do is use #pragma debug in your surface shader to get the generated passes in comments when you open the compiled shader. You can use this as a starting point and then add your extra passes by hand.
     
  3. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    You can add arbitrary passes while using a surface shader.

    You just stick everything else in Pass {} tags and ensure that your surface shader isn't inside any of them (as Unity will generate them as it parses the surface shader).

    For my river shader, I've successfully done a depth-based pass then a grab pass then a distortion pass which then has a surface shader rendering on top.

    Example code;
    Code (csharp):
    1.  
    2. Shader "Exploration/River" {
    3.     Properties {
    4.         _Color ("Main Color", Color) = (1,1,1,1)
    5.         _DepthColor ("Depth Color", Color) = (1,1,1,1)
    6.         _WaterDepth ("Water Depth", Range (0, 10)) = 1
    7.         _BumpMap ("Normal Shading (Normal)", 2D) = "bump" {}
    8.         _WaterSpeed ("Water Speed", Range (0, 10)) = 1
    9.         _WaterSpeed2 ("Water Speed", Range (0, 10)) = 0.37
    10.         _Fresnel ("Fresnel Value", Float) = 0.028
    11.     }
    12.     SubShader{
    13.         Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
    14.         Blend One One
    15.  
    16.         Pass
    17.         {
    18.             Name "RiverDepth"
    19.             Blend SrcAlpha OneMinusSrcAlpha
    20.             CGPROGRAM
    21.                 #pragma vertex vert
    22.                 #pragma fragment frag
    23.                 #pragma fragmentoption ARB_precision_hint_fastest
    24.                 #include "UnityCG.cginc"
    25.  
    26.                 struct v2f {
    27.                     float4 pos          : POSITION;
    28.                     float4 screenPos    : TEXCOORD0;
    29.                 };
    30.  
    31.                 v2f vert (appdata_full v)
    32.                 {
    33.                     v2f o;
    34.                     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);   
    35.                     o.screenPos = ComputeScreenPos(o.pos);
    36.                     return o;
    37.                 }
    38.  
    39.                 sampler2D _CameraDepthTexture;
    40.                 float4 _DepthColor;
    41.                 float _WaterDepth;
    42.  
    43.                 half4 frag( v2f i ) : COLOR
    44.                 {
    45.                     float depth = 1 - saturate(_WaterDepth - (LinearEyeDepth(tex2D(_CameraDepthTexture, i.screenPos.xy / i.screenPos.w).r) - i.screenPos.z));
    46.                     return half4(_DepthColor.rgb, depth * _DepthColor.a);
    47.                 }
    48.             ENDCG          
    49.         }
    50.  
    51.         GrabPass {
    52.             Name "RiverGrab"
    53.         }
    54.  
    55.         Pass
    56.         {
    57.             Name "RiverDistortion"
    58.             Blend Off
    59.             CGPROGRAM
    60.                 #pragma vertex vert
    61.                 #pragma fragment frag
    62.                 #pragma fragmentoption ARB_precision_hint_fastest
    63.                 #include "UnityCG.cginc"
    64.  
    65.                 struct v2f {
    66.                     float4 pos          : POSITION;
    67.                     float4 uvgrab       : TEXCOORD0;
    68.                     float2 uv           : TEXCOORD1;
    69.                     float4 screenPos    : TEXCOORD2;
    70.                 };
    71.  
    72.                 v2f vert (appdata_full v)
    73.                 {
    74.                     v2f o;
    75.                     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);   
    76.                     #if UNITY_UV_STARTS_AT_TOP
    77.                     float scale = -1.0;
    78.                     #else
    79.                     float scale = 1.0;
    80.                     #endif
    81.                     o.uvgrab.xy = (float2(o.pos.x, o.pos.y * scale) + o.pos.w) * 0.5;
    82.                     o.uvgrab.zw = o.pos.zw;
    83.                     o.uv = v.texcoord.xy;
    84.                     return o;
    85.                 }
    86.  
    87.                 sampler2D _BumpMap;
    88.                 float _WaterSpeed, _WaterSpeed2;
    89.                 sampler2D _GrabTexture;
    90.                 float4 _GrabTexture_TexelSize;
    91.  
    92.                 half4 frag( v2f i ) : COLOR
    93.                 {
    94.                     float2 riverUVs = i.uv;
    95.                     riverUVs.y += _Time * _WaterSpeed;
    96.                     float3 normal1 = UnpackNormal(tex2D(_BumpMap, riverUVs));
    97.                     riverUVs = i.uv;
    98.                     riverUVs.x *= -1;
    99.                     riverUVs.y += 0.3 + _Time * _WaterSpeed2;
    100.                     float3 normal2 = UnpackNormal(tex2D(_BumpMap, riverUVs));
    101.                     normal2 *= float3(1, 1, 0.5);
    102.                    
    103.                     float3 combinedNormal = normalize(normal1 * normal2);
    104.                
    105.                     float2 offset = combinedNormal.xy * 5 * _GrabTexture_TexelSize.xy;
    106.                     i.uvgrab.xy = (offset * i.uvgrab.z) + i.uvgrab.xy;
    107.                     return half4(tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab)).rgb, 1);
    108.                 }
    109.             ENDCG
    110.         }
    111.  
    112.         CGPROGRAM
    113.             #include "ExplorationLighting.cginc"
    114.             #pragma surface surf ExplorationRiver noambient novertexlights nolightmap
    115.             #pragma target 3.0
    116.            
    117.             struct Input
    118.             {
    119.                 float2 uv_BumpMap;
    120.             };
    121.  
    122.             sampler2D _BumpMap, _CameraDepthTexture;
    123.             float _Specular, _Gloss, _WaterSpeed, _WaterSpeed2;
    124.  
    125.             void surf (Input IN, inout SurfaceOutput o)
    126.             {
    127.                 float2 riverUVs = IN.uv_BumpMap;
    128.                 riverUVs.y += _Time * _WaterSpeed;
    129.                 float3 normal1 = UnpackNormal(tex2D(_BumpMap, riverUVs));
    130.                 riverUVs = IN.uv_BumpMap;
    131.                 riverUVs.x *= -1;
    132.                 riverUVs.y += 0.3 + _Time * _WaterSpeed2;
    133.                 float3 normal2 = UnpackNormal(tex2D(_BumpMap, riverUVs));
    134.                 normal2 *= float3(1, 1, 0.5);
    135.                
    136.                 float3 combinedNormal = normalize(normal1 * normal2);
    137.                
    138.                 o.Albedo = fixed3(1);
    139.                 o.Normal = combinedNormal;
    140.                 o.Alpha = 0;
    141.             }
    142.         ENDCG
    143.     }
    144.    
    145.     Fallback "Transparent/VertexLit"
    146. }
    147.  
    You can even use multiple surface shaders on top of one another and change the blending/zwrite/blah values of them;

    Code (csharp):
    1.  
    2. /*
    3. Alpha tested pass.
    4.  
    5. Alpha blended pass w/ ZWrite off and alphatest greater than _Cutoff.
    6.  
    7. Anisotropic highlight.
    8. */
    9.  
    10. Shader "Exploration/Hair Soft Edge Surface" {
    11.     Properties {
    12.         _Color ("Main Color", Color) = (1,1,1,1)
    13.         _MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "white" {}
    14.         _SpecularTex ("Specular (R) Gloss (G) Null (B)", 2D) = "gray" {}
    15.         _BumpMap ("Normal (Normal)", 2D) = "bump" {}
    16.         _AnisoTex ("Anisotropic Direction (RGB)", 2D) = "bump" {}
    17.         _AnisoOffset ("Anisotropic Highlight Offset", Range(-0.5,0.5)) = -0.2
    18.         _Cutoff ("Alpha Cut-Off Threshold", Range(0,1)) = 0.5
    19.         _Fresnel ("Fresnel Value", Float) = 0.028
    20.     }
    21.  
    22.     SubShader {
    23.         Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" }
    24.  
    25.         CGPROGRAM
    26.             #include "ExplorationLighting.cginc"
    27.             #pragma surface surf ExplorationSoftHairFirst fullforwardshadows exclude_path:prepass
    28.             #pragma target 3.0
    29.            
    30.             struct Input
    31.             {
    32.                 float2 uv_MainTex;
    33.             };
    34.            
    35.             sampler2D _MainTex, _SpecularTex, _BumpMap, _AnisoDirection;
    36.                
    37.             void surf (Input IN, inout SurfaceOutputCharacter o)
    38.             {
    39.                 fixed4 albedo = tex2D(_MainTex, IN.uv_MainTex);
    40.                 o.Albedo = albedo.rgb;
    41.                 o.Alpha = albedo.a;
    42.                 o.AnisoDir = tex2D(_AnisoDirection, IN.uv_MainTex);
    43.                 o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    44.                 o.Specular = tex2D(_SpecularTex, IN.uv_MainTex).rgb;
    45.             }
    46.         ENDCG
    47.  
    48.         Blend SrcAlpha OneMinusSrcAlpha
    49.         ZWrite Off
    50.  
    51.         CGPROGRAM
    52.             #include "ExplorationLighting.cginc"
    53.             #pragma surface surf ExplorationSoftHairSecond fullforwardshadows exclude_path:prepass noforwardadd
    54.             #pragma target 3.0
    55.            
    56.             struct Input
    57.             {
    58.                 float2 uv_MainTex;
    59.             };
    60.            
    61.             sampler2D _MainTex, _SpecularTex, _BumpMap, _AnisoDirection;
    62.                
    63.             void surf (Input IN, inout SurfaceOutputCharacter o)
    64.             {
    65.                 fixed4 albedo = tex2D(_MainTex, IN.uv_MainTex);
    66.                 o.Albedo = albedo.rgb;
    67.                 o.Alpha = albedo.a;
    68.                 o.AnisoDir = tex2D(_AnisoDirection, IN.uv_MainTex);
    69.                 o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    70.                 o.Specular = tex2D(_SpecularTex, IN.uv_MainTex).rgb;
    71.             }
    72.         ENDCG
    73.     }
    74.     FallBack "Transparent/Cutout/VertexLit"
    75. }
    76.  
     
    Last edited: Jul 12, 2011
    ted537, antislash and Arkade like this.
  4. increpare

    increpare

    Joined:
    Nov 17, 2010
    Posts:
    151
    Ooh, count me interested in the outcome to this one : )
     
  5. rea

    rea

    Joined:
    Oct 10, 2009
    Posts:
    1,818
    Count me in too, im interested in this one.

    Edit :
    Wait, how do you transfer the generated texture from the previous pass?
     
    Last edited: Jul 12, 2011
  6. Daniel-Brauer

    Daniel-Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,314
    Very cool. I had no idea.
     
  7. Chickenlord

    Chickenlord

    Joined:
    May 13, 2011
    Posts:
    381
    You could also write just two surface shaders and Unity will generate the right thing from it. What i mean is:
    Code (csharp):
    1.  
    2. //1st pass
    3. CGPROGRAM
    4. #pragma surface surf
    5. ...
    6. ENDCG
    7.  
    8. //2nd pass
    9. CGPROGRAM
    10. #pragma surface surf
    11. ...
    12. ENDCG
    13.  
    Hope it helps ;)
     
  8. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    Ehr, you don't... it just draws on top.
     
  9. Fishman92

    Fishman92

    Joined:
    Feb 9, 2010
    Posts:
    2,764
    Wow, this could be so useful! I am watching intently.
     
  10. Sycle

    Sycle

    Joined:
    Nov 24, 2009
    Posts:
    446
    Thankyou Farfarer! That was just what I needed to know!

    I got my shader working the way I wanted it to, for anyone curious it ended up looking like this :

    Code (csharp):
    1. Shader "Character Indicator" {
    2. Properties {
    3.     _Color ("Main Color", Color) = (1,1,1,1)
    4.     _MainTex ("Base (RGB)", 2D) = "white" {}
    5.     _WrapTex ("Wrap ramp (RGBA)", 2D) = "black" {}
    6.     _IndicatorTex ("Indicator Lights (RGB)", 2D) = "white" {}
    7.     _Indicator ("Indicator Color", Color) = (1,1,1,1)
    8.     _Cutoff ("Alpha cutoff", Range (0,1)) = 0.0
    9. }
    10.  
    11. SubShader {
    12.     Tags { [COLOR="red"]"Queue" = "Geometry+1"[/COLOR] "RenderType" = "Opaque" }
    13.    
    14. [COLOR="red"]       Pass {         
    15.             Tags { "LightMode" = "Always" }
    16.             AlphaTest Greater [_Cutoff]
    17.             ZWrite Off
    18.             ZTest Greater
    19.            
    20.             SetTexture [_MainTex] {
    21.                 constantColor [_Indicator]
    22.                 combine constant, texture
    23.             }
    24.         }[/COLOR]
    25.  
    26. CGPROGRAM
    27. #pragma surface surf Ramp alphatest:_Cutoff
    28.  
    29. uniform float4 _Color;
    30. uniform float4 _Indicator;
    31. uniform sampler2D _MainTex;
    32. uniform sampler2D _WrapTex;
    33. uniform sampler2D _IndicatorTex;
    34.  
    35. half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {
    36.     half NdotL = dot (s.Normal, lightDir);
    37.     half diff = NdotL * 0.5 + 0.5;
    38.     half3 ramp = tex2D (_WrapTex, float2(diff)).rgb;
    39.     half4 c;
    40.     c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
    41.     c.a = s.Alpha;
    42.     return c;
    43. }
    44.  
    45. struct Input {
    46.     float2 uv_MainTex;
    47.     float2 uv_BumpMap;
    48.     float3 viewDir;
    49. };
    50.  
    51. void surf (Input IN, inout SurfaceOutput o) {
    52.     o.Albedo = tex2D ( _MainTex, IN.uv_MainTex).rgb * _Color;
    53.     o.Emission = tex2D ( _IndicatorTex, IN.uv_MainTex).rgb * _Indicator * 2;
    54.    
    55.     half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
    56.     o.Emission += tex2D ( _MainTex, IN.uv_MainTex).rgb * 2 * pow (rim, 3.0);
    57.     o.Alpha = tex2D ( _MainTex, IN.uv_MainTex).a;
    58. }
    59.  
    60. ENDCG
    61.  
    62. }
    63.  
    64. Fallback " Glossy", 0
    65.  
    66. }
     
    Arkade likes this.
  11. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,357
  12. rea

    rea

    Joined:
    Oct 10, 2009
    Posts:
    1,818
    Wow, so we can combine Fixed Shader with Surface shader? This is interesting...
     
  13. increpare

    increpare

    Joined:
    Nov 17, 2010
    Posts:
    151
    Thanks for posting this, sycle : )
     
  14. Fishman92

    Fishman92

    Joined:
    Feb 9, 2010
    Posts:
    2,764
    Hey, is there anyone who can add this to the toon lighted shader? It would be really useful- You can have a dollar or two for doing it ;).
    OR here, to save me a few bucks, would this part of code:
    Code (csharp):
    1. Pass {         
    2.             Tags { "LightMode" = "Always" }
    3.             AlphaTest Greater [_Cutoff]
    4.             ZWrite Off
    5.             ZTest Greater
    6.            
    7.             SetTexture [_MainTex] {
    8.                 constantColor [_Indicator]
    9.                 combine constant, texture
    10.             }
    11.         }
    added into any shader using the same format work? I don't need the texture, just the colour, so if I edited the SetTexture lines out, would it work?


    EDIT: Forget it, I got it to work! YES!
     
    Last edited: Jul 15, 2011
  15. bem13

    bem13

    Joined:
    Jul 1, 2010
    Posts:
    63
    Exactly what I was looking for, ChickenLord and FarFarer!

    If this trick works it should definitely added to the documentation right next to where it mentions that surf shaders cannot be used in Pass {} blocks. And if it is already there, added with underlining :)
     
  16. brn

    brn

    Joined:
    Feb 8, 2011
    Posts:
    297
    I think the reason the documents have been a little vague about using surface shaders in multiple passes is because although it does work there are some cases where it becomes a little unpredictable.

    For instance if your first pass is using the geometry render queue and the second in a latter one such as transparent, the order of the transparent pass wont play well with other transparent objects( in my experience it no longer draws from back to front ).

    Switching between deferred and forward passes also is unpredictable ( which i totally accept)

    Another weird one Ive found is that Zwrites are ignored on multi pass transparent surface shaders as well.

    Just thought id mention these to save others pulling their hair out.

    Cheers
    Brn
     
  17. thorbrian

    thorbrian

    Joined:
    Aug 26, 2010
    Posts:
    23
    I've been playing around with multiple passes, and I think what's actually going on is that each Subshader can only have one set of Tags associated with it, and it just takes the first definition for each tag mentioned and uses those values for all passes - meaning you can't have multiple passes in different queues in a single shader (I'm not able to anyways). So the reason the back to front thing was messed up was probably both your geometry pass and the transparent pass of your shader rendered in the geometry layer, making it so your transparent pass was below all other transparent items.

    ... the way this is screwing things up for me, is IgnoreProjector - I want to have a multi pass shader where the self-illuminated parts of the scene render above blob shadow projectors, and it's not working because I can't make the self illuminated part render without the projector :(
     
  18. Dev.D1

    Dev.D1

    Joined:
    Dec 29, 2010
    Posts:
    99
    @thorbrian: Were you able to resolve this issue? Or did you have to resort to using multiple materials?
     
  19. brn

    brn

    Joined:
    Feb 8, 2011
    Posts:
    297
    Personally I haven't found a way around mixing Deferred and Forward passes or the render queue issue. Its a pity because it would open up many of possibility's.
     
  20. Steven-1

    Steven-1

    Joined:
    Sep 11, 2010
    Posts:
    248
    Is it possible to combine multiple surface shaders?
    As opposed to combining a surface shader with non- surface shaders.
     
    Last edited: Jan 30, 2012
  21. CharlesBarros

    CharlesBarros

    Joined:
    Nov 17, 2011
    Posts:
    42
    I understand what Sycle did but I can't use the custom tag on Unity 4. And I can't just put the pass after the surface shader because it will consider the object mesh itself in the ztest greater. Anyone knows how to get it work?
     
  22. CharlesBarros

    CharlesBarros

    Joined:
    Nov 17, 2011
    Posts:
    42
    Nevermind, I got it.

    Here follows a sample (based on what Sycle and Farfarer wrote) that illustrate how to use multi pass with 3 different ways to write shaders in unity. Just uncomment the pass blocks to see the effect.

    $results.png

    Code (csharp):
    1. Shader "Character Indicator"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Main Color", Color) = (1,1,1,1)
    6.         _MainTex ("Base (RGB)", 2D) = "white" {}
    7.         _Indicator ("Indicator Color", Color) = (1,1,1,1)
    8.         _Cutoff ("Alpha cutoff", Range (0,1)) = 0.0
    9.     }
    10.    
    11.     SubShader
    12.     {
    13.         Tags { "Queue" = "Geometry+1" "RenderType" = "Opaque" }
    14.  
    15.         CGPROGRAM
    16.         #pragma surface surf BlinnPhong alphatest:_Cutoff
    17.        
    18.         uniform float4 _Color;
    19.         uniform float4 _Indicator;
    20.         uniform sampler2D _MainTex;
    21.          
    22.         struct Input
    23.         {
    24.             float2 uv_MainTex;
    25.             float3 viewDir;
    26.         };
    27.        
    28.         void surf (Input IN, inout SurfaceOutput o)
    29.         {
    30.             o.Albedo = tex2D ( _MainTex, IN.uv_MainTex).rgb * _Color;
    31.         }
    32.         ENDCG
    33.  
    34. // Pass: Surface SHADER
    35. //      ZWrite Off
    36. //      ZTest Greater
    37. //      Blend DstColor Zero
    38. //     
    39. //      CGPROGRAM
    40. //      #pragma surface surf BlinnPhong
    41. //      uniform float4 _Color;
    42. //      uniform float4 _Indicator;
    43. //      uniform sampler2D _MainTex;
    44. //
    45. //      struct Input
    46. //      {
    47. //          float2 uv_MainTex;
    48. //          float3 viewDir;
    49. //      };
    50. //     
    51. //      void surf (Input IN, inout SurfaceOutput o)
    52. //      {
    53. //          //o.Albedo =_Indicator;
    54. //          o.Albedo = tex2D ( _MainTex, IN.uv_MainTex).rgb * _Indicator;
    55. //      }
    56. //      ENDCG  
    57.  
    58. // Pass: CG SHADER
    59. //      Pass
    60. //        {
    61. //          Tags { "LightMode" = "Always" }
    62. //          AlphaTest Greater [_Cutoff]
    63. //          ZWrite Off
    64. //          ZTest Greater
    65. //         
    66. //            CGPROGRAM
    67. //            #pragma vertex vert
    68. //            #pragma fragment frag
    69. //            #pragma fragmentoption ARB_precision_hint_fastest
    70. //            #include "UnityCG.cginc"
    71. //
    72. //          sampler2D _MainTex;
    73. //          float4 _MainTex_ST;
    74. //          uniform float4 _Indicator;
    75. //         
    76. //            struct v2f
    77. //            {
    78. //                float4 pos          : POSITION;
    79. //                float2 uv           : TEXCOORD1;
    80. //            };
    81. //
    82. //            v2f vert (appdata_full v)
    83. //            {
    84. //                v2f o;
    85. //                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);    
    86. //                o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
    87. //                return o;
    88. //            }
    89. //            
    90. //            half4 frag( v2f i ) : COLOR
    91. //            {
    92. //              half4 texcol = tex2D (_MainTex, i.uv);
    93. //                  return texcol * _Indicator;
    94. //            }
    95. //              ENDCG          
    96. //        }
    97.        
    98. // Pass: Fixed pipeline
    99. //        Pass
    100. //      {          
    101. //          Tags { "LightMode" = "Always" }
    102. //          AlphaTest Greater [_Cutoff]
    103. //          ZWrite Off
    104. //          ZTest Greater
    105. // 
    106. //          SetTexture [_MainTex]
    107. //          {
    108. //              constantColor [_Indicator]
    109. //              //combine constant, texture
    110. //              combine constant* texture
    111. //          }
    112. //      }
    113.        
    114.     }
    115.  
    116.  
    117.    
    118.     Fallback " Glossy", 0
    119.  
    120. }
     

    Attached Files:

    Last edited: Apr 21, 2013
    glitchers and Arkade like this.
  23. calbar

    calbar

    Joined:
    May 18, 2013
    Posts:
    10
    Charles, your single post has helped my understanding more than the last few hours of research. Thanks a million for taking the time to post this code and the accompanying images. :D
     
  24. lodendsg

    lodendsg

    Joined:
    Sep 1, 2012
    Posts:
    149
    This is an older post but is exactly what I am looking for however I cant seem to get it working.

    The double surface trick works but not the CG or fixed function pass and what I need to do is run a surface shader for non occluded parts then follow up with a CG rendering only the occluded parts ...

    I tryed using the code you have posted above and commented each 1 by 1 again the surface surface works as expect but not surface + CG or surface + fixed

    PS: I have worked around this by just using surface shaders as opposed to a vert/frag CG; also I note you need to switch the order

    below is an example

    Code (csharp):
    1.  
    2. SubShader
    3.  {
    4.   Tags { "Queue" = "AlphaTest" "RenderType" = "Opaque" }
    5.  
    6.     ZWrite Off
    7.     ZTest Greater
    8.     Blend One One
    9.      
    10.     CGPROGRAM
    11.     #pragma surface surf Lambert
    12.     struct Input {
    13.       float2 uv_MainTex;
    14.       float2 uv_BumpMap;
    15.       float3 viewDir;
    16.     };
    17.     //sampler2D _MainTex;
    18.     sampler2D _BumpMap;
    19.     float4 _RimColor;
    20.     float _RimWidth;
    21.     void surf (Input IN, inout SurfaceOutput o) {
    22.       o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
    23.       half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
    24.       o.Emission = _RimColor.rgb * pow (rim, _RimWidth);
    25.     }
    26.     ENDCG  
    27.    
    28.     ZWrite On
    29.     ZTest LEqual
    30.     Blend Off
    31.    
    32.     CGPROGRAM
    33.     #pragma surface surf Lambert
    34.  
    35.     sampler2D _MainTex;
    36.     sampler2D _BumpMap;
    37.     fixed4 _Color;
    38.  
    39.     struct Input {
    40.         float2 uv_MainTex;
    41.         float2 uv_BumpMap;
    42.     };
    43.  
    44.     void surf (Input IN, inout SurfaceOutput o) {
    45.         fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    46.         o.Albedo = c.rgb;
    47.         o.Alpha = c.a;
    48.         o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    49.     }
    50.     ENDCG
    51.  }
    52.  
    This does the following
    $RimBumped.PNG
     
    Last edited: Feb 24, 2014
    Arkade likes this.
  25. entity476

    entity476

    Joined:
    Nov 2, 2012
    Posts:
    40
    Thank you lodendsg! Given my beginner's understanding, I was pulling my hair to realize, why I cannot combine a CG pass with a depth offset parameter, no mater what combinations of code I tried. While the same time, due to the 3.4 version of Unity that I currently use, it doesn't seem to work with the structure the older posts had recommended. It is your example that showed me the correct way, although I'm not sure that I fully understand, how the order of code blocks is significant for a proper function...:confused:
     
  26. Earlybird

    Earlybird

    Joined:
    Mar 30, 2013
    Posts:
    14
    Can i ask is this possible using an Indie version of Unity?
    im pretty new to shaders but can understnad Surface Shaders but I cant any of these shaders to work?

    Also are these Multi pass more expensive because they use surface shaders?

    Here's what I have so far:
    Code (csharp):
    1. Shader "Custom/MultiPass Surface Shader" {
    2. Properties {
    3.     _Color ("Main Color", Color) = (1,1,1,1)
    4.     _MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
    5.     _BumpMap ("Bump (RGB) Gloss (A)", 2D) = "bump" {}
    6.     _RimColor ("Rim Color", Range (0, 1)) = 0.5
    7.     _RimWidth ("Rim Width", Range (0, 1)) = 0.5
    8. }
    9.  
    10. SubShader
    11.  {
    12.   Tags { "Queue" = "AlphaTest" "RenderType" = "Opaque" }
    13.  
    14.     ZWrite Off
    15.     ZTest Greater
    16.     Blend One One
    17.  
    18.     CGPROGRAM
    19.     #pragma surface surf Lambert
    20.  
    21.     struct Input {
    22.       float2 uv_MainTex;
    23.       float2 uv_BumpMap;
    24.       float3 viewDir;
    25.     };
    26.  
    27.     //sampler2D _MainTex;
    28.     sampler2D _BumpMap;
    29.     float4 _RimColor;
    30.     float _RimWidth;
    31.  
    32.     void surf (Input IN, inout SurfaceOutput o) {
    33.       o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
    34.       half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
    35.       o.Emission = _RimColor.rgb * pow (rim, _RimWidth);
    36.     }
    37.  
    38.     ENDCG  
    39.  
    40.    
    41.  
    42.     ZWrite On
    43.     ZTest LEqual
    44.     Blend Off
    45.  
    46.     CGPROGRAM
    47.     #pragma surface surf Lambert
    48.  
    49.     sampler2D _MainTex;
    50.     sampler2D _BumpMap;
    51.     fixed4 _Color;
    52.  
    53.     struct Input {
    54.         float2 uv_MainTex;
    55.         float2 uv_BumpMap;
    56.     };
    57.  
    58.     void surf (Input IN, inout SurfaceOutput o) {
    59.         fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    60.         o.Albedo = c.rgb;
    61.         o.Alpha = c.a;
    62.         o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    63.     }
    64.  
    65.     ENDCG
    66.  
    67. Fallback "Diffuse"
    68.  
    69.  }
    and here is the error I keep getting?
    "Shader error in 'Custom/MultiPass Surface Shader': Parse error: syntax error at line 107"

    Any help?
    Thanks.
     
  27. OneWayRoad

    OneWayRoad

    Joined:
    Jul 27, 2013
    Posts:
    26
    hey farfarer, i just tested your hair shader. i just noticed that the aniso color(white) is just too strong when not lighted. the darker the area the stronger the aniso is. is there a way to control the intensity of aniso?
     
  28. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    627
    hey, i'm folowing this thread with great interest and it helped me to successfully achieve some effects.

    i have a question : is there a way to keep a variable over the passes ?
     
    Last edited: Jun 1, 2015
  29. varfare

    varfare

    Joined:
    Feb 12, 2013
    Posts:
    199
    As far as I know - it is not possible. You can pass data from vertex program to fragment program or from script to shader but not from pass to pass.
     
    antislash likes this.
  30. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    627
    mmm too bad, may be a setPixel/getPixel to store a value ? or is ot too slow ?

    thanks a lot
     
    Last edited: Jun 2, 2015
  31. varfare

    varfare

    Joined:
    Feb 12, 2013
    Posts:
    199
    SetPixel/GetPixel is really slow but if it's not a problem for you then why not. In general- reading data from GPU is tricky. I believe that you can do that with Compute Shaders but they are probably not what you are looking for. Also, if you need a specific variable to be passed for both passes you may want to create C# script, compute whatever you need to and pass it to the shader/material.
     
  32. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    627
    i'll follow your advice and avoid set/get pixel then
    thanks a lot
     
  33. Zardify

    Zardify

    Joined:
    Jul 15, 2015
    Posts:
    5
    Old post, but look into Stencil shaders where you can easily assign a 0-255 integer value to the pixels of each pass and then use those values for basic calculations in other passes. :)
     
    antislash likes this.
  34. varfare

    varfare

    Joined:
    Feb 12, 2013
    Posts:
    199
    You can write your image effect or compute buffer - store your values in custom render target and assign them for your passes (blur effect is done this way). Compute buffers are also an option since they can return calculation values or textures back to the CPU.
     
  35. Zardify

    Zardify

    Joined:
    Jul 15, 2015
    Posts:
    5
    This whole shader thingy can get so complicated in minutes! :D I just started learning but after every line of code i feel like i "need more"...
     
  36. AlexTemina

    AlexTemina

    Joined:
    Feb 19, 2014
    Posts:
    41
    Hi!

    Sorry to bump this up, but I have a question that may help a lot people that comes and see this, which is a rather famous post in the forum.

    I'm trying to do a multipass shader, but I need the _MainTex of the first pass, since I'm making one operation and then, once the maintex is done, do another one, but this doesn't work because I get the old maintex again.

    How can I achieve that?

    Thanks!
     
  37. Marco-Sperling

    Marco-Sperling

    Joined:
    Mar 5, 2012
    Posts:
    516
    You mean, you manipulate the fragments of the _MainTex in the first pass and want to access the manipulated _MainTex in the second pass?
    Won't work. Since you are not manipulating any of the input texture data. You are manipulating the output to the framebuffer in a shader. The input textures are mere variables that help shaping the output.
    Passes only blend what's already in the framebuffer with the output they themself generate in a specified manner.
    And that's the answer to your challenge. You can either do it with clever pass blending. Or if you absolutely need to manipulate texture data for usage in subsequent passes because there is no blend operation that suits your requirements you probably need to do this with rendertextures and Graphics.Blit()
     
    AlexTemina likes this.