Features:
- Efficient shader optimized for mobile devices
- Realtime refraction of anything on opposite side of water plane
- Sin blend between 2 normal maps for smooth normal animation
- UV Panning normal maps
- Reflection Cubemap
- Renders in Opaque queue with no expensive transparency cost
- Separate settings for fog over and under water
- Separate settings for far clip planes over and under water (quality)
- Controls for Transparency, RefractionFactor, ReflectionFactor, RenderTextureSize, Tiling, FogSettings, etc
Here's some more screenshots and a video: (Sorry for bad quality)
And here's the relevent vertex and surface shaders (in CG):
void vert (inout appdata_full v, out Input o)
{
fixed4 epos = mul(UNITY_MATRIX_MV, v.vertex );
o.eyeZ = -epos.z;
o.ref = mul( _TextureMatrix, epos );
o.viewDir = ObjSpaceViewDir( v.vertex );
}
void surf (Input IN, inout SurfaceOutput o)
{
//Normal map with uv pan based on time:
fixed4 speed = _Speed * _Time;
fixed2 UV_Pan0 = IN.uv_Normal + speed.xy;
fixed2 UV_Pan1 = IN.uv_Normal + speed.yx;
fixed4 normA =
fixed4(UnpackNormal( tex2D(_Normal,UV_Pan0.xy)).xyz, 1.0 );
fixed4 normB = fixed4(UnpackNormal( tex2D(_Normal2,UV_Pan1.xy)).xyz, 1.0);
fixed4 norm =
lerp( normA, normB, (sin( _Time.x * _SinNormalSpeed ) * 0.8 + 1) * 0.5 );
norm = normalize( norm );
//Refract uvs of refractionTexture in xy
fixed4 uv2 = IN.ref;
fixed2 refractUVs =_RefractionFactor * norm.xy;
uv2.xy += refractUVs;
//calculate fresnel factor for hiding refraction at sheer angle:
fixed fresnel = saturate( dot( normalize( IN.viewDir ), norm.xzy ));
fresnel = 1.0 - pow( fresnel, _FresnelFactor ) + 0.5;
//lookup projected refractionTexture:
half4 refr =
_Color * tex2Dproj( _RefractionTexture, UNITY_PROJ_COORD(uv2) );
//lookup reflected cubemap texture:
half4 refl =
_ReflectionFactor * texCUBE( _ReflectionCube, WorldReflectionVector( IN, norm));
//linear fog falloff
half fogAmount = (IN.eyeZ - _FogStart) / _FogEnd;
//lerp between reflection and refraction, using fresnel:
half4 color = lerp( refl, refr, saturate( _Transparency * fresnel) );
//lerp btwn color and fog based on fogamount
color =
lerp( color, saturate(_SurfaceFogColor + norm.x), saturate(fogAmount) );
//unlit so assign to emission
o.Emission = color;
o.Albedo = 0.0;
o.Gloss = 0.0;
o.Alpha = 0.0;
o.Specular = 0.0;
}
-K



hi Katlan,
ReplyDeleteI tried to find this shader as you said you would upload it on Asset Store, but it is not there yet. I am working on a fish tank based project and I am dying to get the screen-space reflection-refraction working on mobile platforms. I am no CG coder, but I think this is what I exactly needed. Can you please share this with me or at least tell me how I would go about it? I also bought hard surface shaders standard, which has the screen-space reflection-refraction shader, but it is unbelievably slow even on iPhone5. Please help.
Regards,
Rohan
Hey Rohan, I'm just back to blogging, so I apologize for not responding earlier. I have not posted to the Asset Store (turns out, it's a lot of work!), but will consider posting the files here. I prefer not to, as I like to encourage people to do some work on their own. In this case, all the relevant code is above, so with a bit of work, you can recreate the files yourself.
DeleteDo you have any ideas on how to prevent refraction of objects above the water ? I am not using reflection or fog.
ReplyDeleteIf you set _RefractionFactor to 1 it should turn off Refraction completely. If you want to do it on a per-object basis, it's a bit more complex and you'd lose some performance. You'd have to make the shader a transparent shader, render only what you want refracted into _RefractionTexture, then render the water plane, with all refracted objects off, and all unrefracted objects on.
DeleteUnfortunately, shaders are somewhat single-use. They excel when they're efficient. But with efficiency, you lose flexibility. So my shader would need some tweaking to get per-layer/object refraction.