Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Opaque Alpha in a transparent surface shader (for Water)

Discussion in 'Shaders' started by Kelly G, Apr 8, 2011.

  1. Kelly G

    Kelly G

    Joined:
    Oct 29, 2010
    Posts:
    35
    Hello. I use the free version of Unity. I thought the built-in water shaders in Unity free look a bit strange until it occurred to me that they must represent deep bodies of water viewed from far away, where as I'm trying to make a little pond or puddle.

    I'm trying to make a modified version of the water shader to incorporate some features that I would like. I don't really know the Unity shader language, but I was able to figure out how to add some surface properties by looking at the examples in the documentation and also this forum, and then just cobbling things together. So far I've added:

    transparency
    Specular highlights based on the bump map
    cube map reflection that is perturbed by the bump map.

    the problem that I am having is that I would like the specular highlights to be opaque when they are really bright. Right now they are as transparent as the rest of the water. Here is a web player example, so you can see what I mean.
    http://www.kellygallagherprojects.com/gamedev/UnityDemos/water.html
    This uses the standard WASD, mouse look controls
    Step into the puddle and turn around to see the specular highlights.

    my code
    Code (csharp):
    1.  
    2. Shader "FX/Water (kdg) 4" {
    3. Properties {
    4.     _MainAlpha ("Tansparency", Range(0.0,1.0)) = 0.5
    5.     _WaveScale ("Wave scale", Range (0.02,0.15)) = .07
    6.     _ColorControl ("Reflective color (RGB) fresnel (A) ", 2D) = "" { }
    7.     _ColorControlCube ("Reflective color cube (RGB) fresnel (A) ", Cube) = "" { TexGen CubeReflect }
    8.     _BumpMap ("Waves Normalmap ", 2D) = "" { }
    9.     WaveSpeed ("Wave speed (map1 x,y; map2 x,y)", Vector) = (19,9,-16,-7)
    10.     _MainTex ("Fallback texture", 2D) = "" { }
    11.    
    12.     _Specular ("Specular", Range (0,1)) = .07
    13.     _Gloss ("Gloss", Range (0,128)) = 1
    14. }
    15.  
    16.    
    17. // -----------------------------------------------------------
    18. // Fragment program
    19.  
    20. Subshader {
    21.     Tags {"Queue"="Transparent" "RenderType"="Transparent"}
    22.    
    23. CGPROGRAM
    24.         #pragma surface surf SimpleSpecular alpha vertex:vert
    25.         //uniform float4 _horizonColor;
    26.  
    27.         uniform float _MainAlpha;
    28.         uniform float4 WaveSpeed;
    29.         uniform float _WaveScale;
    30.         uniform float4 _WaveOffset;
    31.        
    32.         uniform float _Specular;
    33.         uniform float _Gloss;
    34.        
    35.         sampler2D _BumpMap;
    36.         sampler2D _ColorControl;
    37.         samplerCUBE _ColorControlCube;
    38.        
    39.         #include "UnityCG.cginc"
    40.  
    41.         struct Input {
    42.              
    43.              half2 bumpuv0 : TEXCOORD0;
    44.             half2 bumpuv1 : TEXCOORD1;
    45.             half3 vDir : TEXCOORD2;
    46.             half3 worldRefl;
    47.             INTERNAL_DATA
    48.         };
    49.        
    50.         void vert (inout appdata_full v, out Input o) {
    51.             float4 s;
    52.  
    53.             // scroll bump waves
    54.             float4 temp;
    55.             temp.xyzw = v.vertex.xzxz * _WaveScale / unity_Scale.w + _WaveOffset;
    56.             o.bumpuv0 = temp.xy * float2(.4, .45);
    57.             o.bumpuv1 = temp.wz;
    58.  
    59.             // object space view direction
    60.             o.vDir = normalize( ObjSpaceViewDir(v.vertex) ).xzy;
    61.         }
    62.  
    63.         void surf (Input IN, inout SurfaceOutput o) {
    64.          
    65.             half3 bump1 = UnpackNormal(tex2D( _BumpMap, IN.bumpuv0 )).rgb;
    66.             half3 bump2 = UnpackNormal(tex2D( _BumpMap, IN.bumpuv1 )).rgb;
    67.             half3 bump = (bump1 + bump2) * 0.5;
    68.             o.Normal = bump;
    69.              
    70.             half3 worldRefl = WorldReflectionVector (IN, o.Normal);
    71.             half fresnel = dot( IN.vDir, bump);
    72.             half4 water = tex2D( _ColorControl, float2(fresnel,fresnel) );
    73.             half3 R = IN.vDir - ( 2 * dot(IN.vDir, o.Normal )) * o.Normal;
    74.             half4 reflcol = texCUBE (_ColorControlCube, R);
    75.          
    76.             half4 col;
    77.        
    78.             col.rgb = water.rgb;
    79.                         //make 0.5 into a slider eventually
    80.             col.rgb = lerp( reflcol.rgb, col.rgb, 0.5 );
    81.            
    82.             col.a = _MainAlpha;
    83.            
    84.             o.Albedo = 0.0;
    85.            
    86.             o.Alpha = col.a;
    87.             o.Emission = col;
    88.         }
    89.        
    90.         half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
    91.         {
    92.                     half3 h = normalize (lightDir + viewDir);
    93.  
    94.                     half diff = max (0, dot (s.Normal, lightDir));
    95.  
    96.                     float nh = max (0, dot (s.Normal, h));
    97.                     float spec = pow (nh, _Gloss);
    98.          
    99.                      half4 c;
    100.                     c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2) * _Specular;
    101.                     //I have alpha set to 1 for debugging. Really it doesn't seem to matter what I put here
    102.                     c.a = 1;
    103.                     return c;
    104.                     }
    105.         ENDCG
    106. }
    107.  
    108. // -----------------------------------------------------------
    109. //  Old cards (you can ignore anything below here)
    110.  
    111. // three texture, cubemaps
    112. Subshader {
    113.     //Tags { "RenderType"="Opaque" }
    114.     Tags {"Queue"="Transparent" "RenderType"="Transparent"}
    115.     Pass {
    116.         Color (0.5,0.5,0.5,0.5)
    117.         SetTexture [_MainTex] {
    118.             Matrix [_WaveMatrix]
    119.             combine texture * primary
    120.         }
    121.         SetTexture [_MainTex] {
    122.             Matrix [_WaveMatrix2]
    123.             combine texture * primary + previous
    124.         }
    125.         SetTexture [_ColorControlCube] {
    126.             combine texture +- previous, primary
    127.             Matrix [_Reflection]
    128.         }
    129.     }
    130. }
    131.  
    132. // dual texture, cubemaps
    133. Subshader {
    134.     //Tags { "RenderType"="Opaque" }
    135.     Tags {"Queue"="Transparent" "RenderType"="Transparent"}
    136.     Pass {
    137.         Color (0.5,0.5,0.5,0.5)
    138.         SetTexture [_MainTex] {
    139.             Matrix [_WaveMatrix]
    140.             combine texture
    141.         }
    142.         SetTexture [_ColorControlCube] {
    143.             combine texture +- previous, primary
    144.             Matrix [_Reflection]
    145.         }
    146.     }
    147. }
    148.  
    149. // single texture
    150. Subshader {
    151.     //Tags { "RenderType"="Opaque" }
    152.     Tags {"Queue"="Transparent" "RenderType"="Transparent"}
    153.     Pass {
    154.         Color (0.5,0.5,0.5,0)
    155.         SetTexture [_MainTex] {
    156.             Matrix [_WaveMatrix]
    157.             combine texture, primary
    158.         }
    159.     }
    160. }
    161.  
    162. }
    163.  
    164.  
    So my lighting model is called LightingSimpleSpecular, which comes right out of the example surface shader with the same name. I want to set my alpha to something like (c.r+c.g+c.b)/3 (the luminosity), but it doesn't seem to make any difference what I set the alpha to in the lighting model function. I've tried removing the alpha assignment in the surface function also but that doesn't seem to help. As far as I know I don't have access to that lighting info from the surface function either.

    Anyone know how to do this?
     
  2. Kelly G

    Kelly G

    Joined:
    Oct 29, 2010
    Posts:
    35
    Hello again. I did some searching around. It seems that someone else had the exact same problem before.

    http://forum.unity3d.com/threads/74397-Alpha-Blending-and-Surface-Shader-Lighting-Models?highlight=surface+alpha+specular


    So it looks like the output of the custom light model internally is intentionally masked to include RGB only (ColorMask RGB), if I understand this post correctly. The person who responded suggested opening the compiled shader and removing the directive which masks it. This code could then be used to make a shader with the desired effect. I think this solution would be difficult to work with, though.

    I was wondering if it was not possible to access this directive from just the regular surface shader code?
     
  3. Arno1975

    Arno1975

    Joined:
    Aug 14, 2013
    Posts:
    43
    I know this is an old post...but could you please tell me how to apply the shader. I really like it.

    What images do you use and what kind of a water script
     
    Last edited: Jun 4, 2014
  4. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,616
    Hello. Thanks for noticing!

    I basically just used Unity's Daylight Simple Water prefab that comes in Unity's standard assets and simply changed the shader. Unity's prefab already includes the geometry and the script for moving the waves. It also has the bump map and texture for the waves that I used ("WaterBump" and "Water Fallback" in "Standard Assets/water (basic)/source/textures/").

    I opened up "Water Fallback" in my paint program and changed it to greyscale.

    The other thing you need is a cubemap of your environment for the cubemap parameter. For that I used a script that someone posted on either the forum or the wiki, that renders a cubemap through the editor. See if you can find that.

    I actually have a new version of this shader which includes my crude solution for the problem that I had originally posted above, as well as a few other improvements. I'll see if I can post it tomorrow for anyone who might be interested.