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.
  2. Dismiss Notice

I really need a mobile reflective shader.

Discussion in 'Shaders' started by arkon, Jun 3, 2014.

  1. arkon

    arkon

    Joined:
    Jun 27, 2011
    Posts:
    1,122
    I've been using the Reflective vertex lit shader on my boat model but on the iPad it complains that the shader isn't supported. But I can't find any equivalent mobile version. I've even tried Core Framework and nothing works right.

    I have a boat model with the camera fixed to the mast looking forwards and down slightly so you can see a lot of the boat as it's moving. Problem is there is the reflection in Core's mobile shader doesn't move unless something in front of the camera moves. So if a gun turret rotates it looks great with a nice reflective effect, but the boat itself because it is stationary with respect the camera, does not have any reflective effect.

    Anyone have any ideas how to solve this? Basically as the boat moves around the world I want it to have moving reflections or a cube or sphere map, any hack that works on mobile will do.
     
  2. twiesner

    twiesner

    Joined:
    Oct 4, 2011
    Posts:
    309
    Have you tried the water shader that comes with Unity's Standard Assets Package?
     
  3. arkon

    arkon

    Joined:
    Jun 27, 2011
    Posts:
    1,122
    Sorry, I mustn't have been clear. It's for the boat not the water. I want the metal on the boat to look shiny as it's moving.
     
  4. twiesner

    twiesner

    Joined:
    Oct 4, 2011
    Posts:
    309
    The following works on a ipad4

    Code (csharp):
    1. Shader "Mobile/mobile_Reflective" {
    2.     Properties {
    3.         _Cubemap ("Cubemap", Cube) = "_Skybox" {}
    4.         _Specular ("Specular", 2D) = "white" {}
    5.         _Normal ("Normal", 2D) = "bump" {}
    6.         _FresnelExponent ("Fresnel Exponent", Range(1, 8)) = 2.526316
    7.     }
    8.     SubShader {
    9.         Tags {
    10.             "RenderType"="Opaque"
    11.         }
    12.         Pass {
    13.             Name "ForwardBase"
    14.             Tags {
    15.                 "LightMode"="ForwardBase"
    16.             }
    17.          
    18.          
    19.             CGPROGRAM
    20.             #pragma vertex vert
    21.             #pragma fragment frag
    22.             #define UNITY_PASS_FORWARDBASE
    23.             #include "UnityCG.cginc"
    24.             #include "AutoLight.cginc"
    25.             #pragma multi_compile_fwdbase_fullshadows
    26.             #pragma exclude_renderers xbox360 ps3 flash d3d11_9x
    27.             #pragma target 3.0
    28.             uniform float4 _LightColor0;
    29.             uniform samplerCUBE _Cubemap;
    30.             uniform sampler2D _Specular; uniform float4 _Specular_ST;
    31.             uniform sampler2D _Normal; uniform float4 _Normal_ST;
    32.             uniform float _FresnelExponent;
    33.             struct VertexInput {
    34.                 float4 vertex : POSITION;
    35.                 float3 normal : NORMAL;
    36.                 float4 tangent : TANGENT;
    37.                 float2 texcoord0 : TEXCOORD0;
    38.             };
    39.             struct VertexOutput {
    40.                 float4 pos : SV_POSITION;
    41.                 float2 uv0 : TEXCOORD0;
    42.                 float4 posWorld : TEXCOORD1;
    43.                 float3 normalDir : TEXCOORD2;
    44.                 float3 tangentDir : TEXCOORD3;
    45.                 float3 binormalDir : TEXCOORD4;
    46.                 LIGHTING_COORDS(5,6)
    47.             };
    48.             VertexOutput vert (VertexInput v) {
    49.                 VertexOutput o;
    50.                 o.uv0 = v.texcoord0;
    51.                 o.normalDir = mul(float4(v.normal,0), _World2Object).xyz;
    52.                 o.tangentDir = normalize( mul( _Object2World, float4( v.tangent.xyz, 0.0 ) ).xyz );
    53.                 o.binormalDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w);
    54.                 o.posWorld = mul(_Object2World, v.vertex);
    55.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    56.                 TRANSFER_VERTEX_TO_FRAGMENT(o)
    57.                 return o;
    58.             }
    59.             fixed4 frag(VertexOutput i) : COLOR {
    60.                 i.normalDir = normalize(i.normalDir);
    61.                 float3x3 tangentTransform = float3x3( i.tangentDir, i.binormalDir, i.normalDir);
    62.                 float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
    63. /////// Normals:
    64.                 float2 node_1112 = i.uv0;
    65.                 float3 normalLocal = UnpackNormal(tex2D(_Normal,TRANSFORM_TEX(node_1112.rg, _Normal))).rgb;
    66.                 float3 normalDirection =  normalize(mul( normalLocal, tangentTransform )); // Perturbed normals
    67.                 float3 viewReflectDirection = reflect( -viewDirection, normalDirection );
    68.                 float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
    69.                 float3 halfDirection = normalize(viewDirection+lightDirection);
    70. ////// Lighting:
    71.                 float attenuation = LIGHT_ATTENUATION(i);
    72.                 float3 attenColor = attenuation * _LightColor0.xyz;
    73. /////// Diffuse:
    74.                 float NdotL = dot( normalDirection, lightDirection );
    75.                 float3 diffuse = max( 0.0, NdotL) * attenColor + UNITY_LIGHTMODEL_AMBIENT.rgb;
    76. ///////// Gloss:
    77.                 float gloss = 0.5;
    78.                 float specPow = exp2( gloss * 10.0+1.0);
    79. ////// Specular:
    80.                 NdotL = max(0.0, NdotL);
    81.                 float4 node_1 = texCUBE(_Cubemap,viewReflectDirection);
    82.                 float3 node_215 = (node_1.rgb*node_1.a*8.0);
    83.                 float node_223 = pow(1.0-max(0,dot(normalDirection, viewDirection)),_FresnelExponent);
    84.                 float node_11 = 0.4;
    85.                 float4 _Specular_var = tex2D(_Specular,TRANSFORM_TEX(node_1112.rg, _Specular));
    86.                 float3 specularColor = float3(_Specular_var.r,_Specular_var.r,_Specular_var.r);
    87.                 float3 specularAmb = (lerp((0.7*node_215),node_215,node_223)*((i.normalDir.g*node_11)+(1.0 - node_11))) * specularColor;
    88.                 float3 specular = (floor(attenuation) * _LightColor0.xyz) * pow(max(0,dot(halfDirection,normalDirection)),specPow) * specularColor + specularAmb;
    89.                 float3 finalColor = 0;
    90.                 float3 diffuseLight = diffuse;
    91.                 float node_286 = lerp(0.2,0,node_223);
    92.                 finalColor += diffuseLight * float3(node_286,node_286,node_286);
    93.                 finalColor += specular;
    94. /// Final Color:
    95.                 return fixed4(finalColor,1);
    96.             }
    97.             ENDCG
    98.         }
    99.         Pass {
    100.             Name "ForwardAdd"
    101.             Tags {
    102.                 "LightMode"="ForwardAdd"
    103.             }
    104.             Blend One One
    105.          
    106.          
    107.             Fog { Color (0,0,0,0) }
    108.             CGPROGRAM
    109.             #pragma vertex vert
    110.             #pragma fragment frag
    111.             #define UNITY_PASS_FORWARDADD
    112.             #include "UnityCG.cginc"
    113.             #include "AutoLight.cginc"
    114.             #pragma multi_compile_fwdadd_fullshadows
    115.             #pragma exclude_renderers xbox360 ps3 flash d3d11_9x
    116.             #pragma target 3.0
    117.             uniform float4 _LightColor0;
    118.             uniform sampler2D _Specular; uniform float4 _Specular_ST;
    119.             uniform sampler2D _Normal; uniform float4 _Normal_ST;
    120.             uniform float _FresnelExponent;
    121.             struct VertexInput {
    122.                 float4 vertex : POSITION;
    123.                 float3 normal : NORMAL;
    124.                 float4 tangent : TANGENT;
    125.                 float2 texcoord0 : TEXCOORD0;
    126.             };
    127.             struct VertexOutput {
    128.                 float4 pos : SV_POSITION;
    129.                 float2 uv0 : TEXCOORD0;
    130.                 float4 posWorld : TEXCOORD1;
    131.                 float3 normalDir : TEXCOORD2;
    132.                 float3 tangentDir : TEXCOORD3;
    133.                 float3 binormalDir : TEXCOORD4;
    134.                 LIGHTING_COORDS(5,6)
    135.             };
    136.             VertexOutput vert (VertexInput v) {
    137.                 VertexOutput o;
    138.                 o.uv0 = v.texcoord0;
    139.                 o.normalDir = mul(float4(v.normal,0), _World2Object).xyz;
    140.                 o.tangentDir = normalize( mul( _Object2World, float4( v.tangent.xyz, 0.0 ) ).xyz );
    141.                 o.binormalDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w);
    142.                 o.posWorld = mul(_Object2World, v.vertex);
    143.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    144.                 TRANSFER_VERTEX_TO_FRAGMENT(o)
    145.                 return o;
    146.             }
    147.             fixed4 frag(VertexOutput i) : COLOR {
    148.                 i.normalDir = normalize(i.normalDir);
    149.                 float3x3 tangentTransform = float3x3( i.tangentDir, i.binormalDir, i.normalDir);
    150.                 float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
    151. /////// Normals:
    152.                 float2 node_1113 = i.uv0;
    153.                 float3 normalLocal = UnpackNormal(tex2D(_Normal,TRANSFORM_TEX(node_1113.rg, _Normal))).rgb;
    154.                 float3 normalDirection =  normalize(mul( normalLocal, tangentTransform )); // Perturbed normals
    155.                 float3 lightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));
    156.                 float3 halfDirection = normalize(viewDirection+lightDirection);
    157. ////// Lighting:
    158.                 float attenuation = LIGHT_ATTENUATION(i);
    159.                 float3 attenColor = attenuation * _LightColor0.xyz;
    160. /////// Diffuse:
    161.                 float NdotL = dot( normalDirection, lightDirection );
    162.                 float3 diffuse = max( 0.0, NdotL) * attenColor;
    163. ///////// Gloss:
    164.                 float gloss = 0.5;
    165.                 float specPow = exp2( gloss * 10.0+1.0);
    166. ////// Specular:
    167.                 NdotL = max(0.0, NdotL);
    168.                 float4 _Specular_var = tex2D(_Specular,TRANSFORM_TEX(node_1113.rg, _Specular));
    169.                 float3 specularColor = float3(_Specular_var.r,_Specular_var.r,_Specular_var.r);
    170.                 float3 specular = attenColor * pow(max(0,dot(halfDirection,normalDirection)),specPow) * specularColor;
    171.                 float3 finalColor = 0;
    172.                 float3 diffuseLight = diffuse;
    173.                 float node_223 = pow(1.0-max(0,dot(normalDirection, viewDirection)),_FresnelExponent);
    174.                 float node_286 = lerp(0.2,0,node_223);
    175.                 finalColor += diffuseLight * float3(node_286,node_286,node_286);
    176.                 finalColor += specular;
    177. /// Final Color:
    178.                 return fixed4(finalColor * 1,0);
    179.             }
    180.             ENDCG
    181.         }
    182.     }
    183. }
     
  5. arkon

    arkon

    Joined:
    Jun 27, 2011
    Posts:
    1,122
    Thanks for your help twiesner it is much appreciated. It still doesn't look right so I'm going to have to bite the bullet and learn how to write shaders! I really wish this kind of thing was in the standard unity assets. There really needs to be some much better mobile shaders available.

    Thanks for trying though.
     
  6. arkon

    arkon

    Joined:
    Jun 27, 2011
    Posts:
    1,122
    @twiesner I have managed to cobble together a shader that does the job, well sort of but I am not sure I have done it in the fastest mobile way possible, any chance you or other shader guru can look at it and tell me how to improve it for mobile and am I doing the alpha merging right.

    I have a 32bit texture with the alpha channel being how much I want the cube map to affect the output, I'm calling tex2D twice for this which seems wrong to me. Here is my effort so far:-

    Code (CSharp):
    1. Shader "Mobile/MyMetalShader"
    2. {
    3.     Properties {
    4.       _MainTex ("Texture", 2D) = "white" {}
    5.       _Cube ("Cube env tex", CUBE) = "black" {}
    6.       _MixPower ("Mix Power", Range (1, 0.01)) = 0.5
    7.     }
    8.     SubShader {
    9.       Tags { "RenderType" = "Opaque" }
    10.       CGPROGRAM
    11.       #pragma surface surf Lambert
    12.       struct Input {
    13.           float2 uv_MainTex;
    14.           float3 worldRefl;
    15.       };
    16.       sampler2D _MainTex;
    17.       samplerCUBE _Cube;
    18.       fixed _MixPower;
    19.  
    20.       void surf (Input IN, inout SurfaceOutput o) {
    21.           o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;
    22.            o.Emission = texCUBE (_Cube, IN.worldRefl).rgb * tex2D (_MainTex, IN.uv_MainTex).a;
    23.       }
    24.       ENDCG
    25.     }
    26.     Fallback "Diffuse"
    27. }
     
  7. metaleap

    metaleap

    Joined:
    Oct 3, 2012
    Posts:
    589


    Yeah you can easily change this into a single tex2D call:

    Code (csharp):
    1.  
    2. fixed4 mytex = tex2D(_MainTex, IN.uv_MainTex);
    3. o.Albedo = mytex.rgb * 0.5;
    4. o.Emission = texCUBE (_Cube, IN.worldRefl).rgb * mytex.a;
    5.  
     
    arkon likes this.
  8. metaleap

    metaleap

    Joined:
    Oct 3, 2012
    Posts:
    589


    That's a very fine ultra-optimized shader pack and it sounds like you were slightly impatient in figuring out how their reflective shaders work. Posted in the CORE thread?
     
  9. arkon

    arkon

    Joined:
    Jun 27, 2011
    Posts:
    1,122
    I've already discussed this with Core. Their reflection shaders only show any kind of effect if the object is moving with respect to the camera. If the camera is fixed to the object in question and moving with it, the environment map doesn't move so the texture just looks flat and non reflective.

    My camera is fixed to the mast of a boat looking slightly downwards so the Core shaders don't show any effect. If however I detach the camera and let the boat sail past I see the reflective effect perfectly. The hacked shader I used above doesn't do this. As the boat pitches and yaws there is a movement on the reflective surfaces which gives a good illusion.

    In short I've toiled with the Core ones for days but can't get it to work in my set up.
     
  10. arkon

    arkon

    Joined:
    Jun 27, 2011
    Posts:
    1,122
    Thanks for this, I will put it in my shader thanks.