Search code examples
unity-game-engineshaderhlsl

Which parts of this water shader are resposible for the transparancy?


I have a water shader here and I want to know what code is responsible for transparency.

Currently the water is transparent, that is the other thing i would like to change. I hoped the RenderType is "RenderType"="transparent" but it is "RenderType"="Opaque" .... and i couldn't find transparent code in this shader.

Maybe you know the parts of the code causes the transparency?

This is the water shader

Shader "FX/Water" {
 Properties {
     _WaveScale ("Wave scale", Range (0.02,0.15)) = 0.063
     _ReflDistort ("Reflection distort", Range (0,1.5)) = 0.44
     _RefrDistort ("Refraction distort", Range (0,1.5)) = 0.40
     _RefrColor ("Refraction color", COLOR)  = ( .34, .85, .92, 1)
     [NoScaleOffset] _Fresnel ("Fresnel (A) ", 2D) = "gray" {}
     [NoScaleOffset] _BumpMap ("Normalmap ", 2D) = "bump" {}
     WaveSpeed ("Wave speed (map1 x,y; map2 x,y)", Vector) = (19,9,-16,-7)
     [NoScaleOffset] _ReflectiveColor ("Reflective color (RGB) fresnel (A)", 2D) = "" {}
     _HorizonColor ("Simple water horizon color", COLOR)  = ( .172, .463, .435, 1)
     [HideInInspector] _ReflectionTex ("Internal Reflection", 2D) = "" {}
     [HideInInspector] _RefractionTex ("Internal Refraction", 2D) = "" {}

     //
     _EmissionColor("Color", Color) = (0.000000,0.000000,0.000000,1.000000)
     _EmissionMap("Emission", 2D) = "white" { }
     [Toggle] _DynamicEmissionLM("Dynamic Emission (Lightmapper)", Int) = 0
 }


 // -----------------------------------------------------------
 // Fragment program cards


 Subshader {
     Tags { "WaterMode"="Refractive" "RenderType"="Opaque" }
     Pass {
 CGPROGRAM
 #pragma vertex vert
 #pragma fragment frag
 #pragma multi_compile_fog
 #pragma multi_compile WATER_REFRACTIVE WATER_REFLECTIVE WATER_SIMPLE

 #if defined (WATER_REFLECTIVE) || defined (WATER_REFRACTIVE)
 #define HAS_REFLECTION 1
 #endif
 #if defined (WATER_REFRACTIVE)
 #define HAS_REFRACTION 1
 #endif


 #include "UnityCG.cginc"

 uniform float4 _WaveScale4;
 uniform float4 _WaveOffset;

 #if HAS_REFLECTION
 uniform float _ReflDistort;
 #endif
 #if HAS_REFRACTION
 uniform float _RefrDistort;
 #endif

 struct appdata {
     float4 vertex : POSITION;
     float3 normal : NORMAL;
 };

 struct v2f {
     float4 pos : SV_POSITION;
     #if defined(HAS_REFLECTION) || defined(HAS_REFRACTION)
         float4 ref : TEXCOORD0;
         float2 bumpuv0 : TEXCOORD1;
         float2 bumpuv1 : TEXCOORD2;
         float3 viewDir : TEXCOORD3;
     #else
        float2 bumpuv0 : TEXCOORD0;
         float2 bumpuv1 : TEXCOORD1;
         float3 viewDir : TEXCOORD2;
     #endif
     UNITY_FOG_COORDS(4)
 };

 v2f vert(appdata v)
 {
     v2f o;
     o.pos = UnityObjectToClipPos(v.vertex);


     // scroll bump waves
     float4 temp;
     float4 wpos = mul (unity_ObjectToWorld, v.vertex);
     //temp.xyzw = wpos.xzxz * _WaveScale4 + _WaveOffset;
     temp.xyzw = wpos.yzyz * _WaveScale4 + _WaveOffset;
     o.bumpuv0 = temp.xy;
     o.bumpuv1 = temp.wz;

     // object space view direction (will normalize per pixel)
     o.viewDir.xzy = WorldSpaceViewDir(v.vertex);

     #if defined(HAS_REFLECTION) || defined(HAS_REFRACTION)
     o.ref = ComputeNonStereoScreenPos(o.pos);
     #endif

     UNITY_TRANSFER_FOG(o,o.pos);
     return o;
 }

 #if defined (WATER_REFLECTIVE) || defined (WATER_REFRACTIVE)
 sampler2D _ReflectionTex;
 #endif
 #if defined (WATER_REFLECTIVE) || defined (WATER_SIMPLE)
 sampler2D _ReflectiveColor;
 #endif
 #if defined (WATER_REFRACTIVE)
 sampler2D _Fresnel;
 sampler2D _RefractionTex;
 uniform float4 _RefrColor;
 #endif
 #if defined (WATER_SIMPLE)
 uniform float4 _HorizonColor;
 #endif
 sampler2D _BumpMap;

 half4 frag( v2f i ) : SV_Target
 {
     i.viewDir = normalize(i.viewDir);

     // combine two scrolling bumpmaps into one
     half3 bump1 = UnpackNormal(tex2D( _BumpMap, i.bumpuv0 )).rgb;
     half3 bump2 = UnpackNormal(tex2D( _BumpMap, i.bumpuv1 )).rgb;
     half3 bump = (bump1 + bump2) * 0.5;

     // fresnel factor
     half fresnelFac = dot( i.viewDir, bump );

     // perturb reflection/refraction UVs by bumpmap, and lookup colors

     #if HAS_REFLECTION
     float4 uv1 = i.ref; uv1.xy += bump * _ReflDistort;
     half4 refl = tex2Dproj( _ReflectionTex, UNITY_PROJ_COORD(uv1) );
     #endif
     #if HAS_REFRACTION
     float4 uv2 = i.ref; uv2.xy -= bump * _RefrDistort;
     half4 refr = tex2Dproj( _RefractionTex, UNITY_PROJ_COORD(uv2) ) * _RefrColor;
     #endif

     // final color is between refracted and reflected based on fresnel
     half4 color;

 #if defined(WATER_REFRACTIVE)
     half fresnel = UNITY_SAMPLE_1CHANNEL( _Fresnel,         
      float2(fresnelFac,fresnelFac) );
     color = lerp( refr, refl, fresnel );
     #endif

     #if defined(WATER_REFLECTIVE)
     half4 water = tex2D( _ReflectiveColor, float2(fresnelFac,fresnelFac) );
     color.rgb = lerp( water.rgb, refl.rgb, water.a );
     color.a = refl.a * water.a;
     #endif

     #if defined(WATER_SIMPLE)
     half4 water = tex2D( _ReflectiveColor, float2(fresnelFac,fresnelFac) );
     color.rgb = lerp( water.rgb, _HorizonColor.rgb, water.a );
     color.a = _HorizonColor.a;
     #endif

     UNITY_APPLY_FOG(i.fogCoord, color);

     //o.Emission = c.rgb * tex2D(_Illum, IN.uv_Illum).a;


     return color;
 }
 ENDCG

     }
 }

 }

Solution

  • The #pragma multi_compile WATER_REFRACTIVE WATER_REFLECTIVE WATER_SIMPLE line allows the script to have different modes depending on global configuration. From the documentation:

    How multi_compile works

    Example directive:

    #pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
    

    This example directive produces two shader variants: one with FANCY_STUFF_OFF defined, and another with FANCY_STUFF_ON. At run time, Unity activates one of them based on the Material or global shader keywords. If neither of these two keywords are enabled, then Unity uses the first one (in this example, FANCY_STUFF_OFF).

    So in the case of this question, WATER_REFRACTIVE is enabled by default.

    If you look at the fragment shader, you'll see this #ifdefined section:

    #if defined(WATER_REFRACTIVE)
    half fresnel = UNITY_SAMPLE_1CHANNEL( _Fresnel,         
    float2(fresnelFac,fresnelFac) );
    color = lerp( refr, refl, fresnel );
    #endif
    

    To answer your immediate question, the transparency effect is where the refractive color refr is visible over the reflective color refl, which is determined by the _Fresnel and _BumpMap textures.

    You could make the water totally reflective by changing the shader here to just use color = refl; instead.

    However, another way of doing it starts with changing the mode of the shader by using Material.EnableKeyword on the water's Material to enable the WATER_SIMPLE keyword:

    water.material.EnableKeyword("WATER_SIMPLE"); 
    

    Doing this will use this #ifdefined section in the vertex shader instead of the previously mentioned one:

    #if defined(WATER_SIMPLE)
    half4 water = tex2D( _ReflectiveColor, float2(fresnelFac,fresnelFac) );
    color.rgb = lerp( water.rgb, _HorizonColor.rgb, water.a );
    color.a = _HorizonColor.a;
    #endif
    

    and we can see that it sets the output color's alpha as _HorizonColor.a. This means that with this mode, you would be able to set the water's transparency directly by changing the alpha of _HorizonColor