Tag Archives: Vertex DIsplacement

800px600px_Blue_water

Water shader

Feautures:
Vertex displacement via supplied heightmap, Surface normals are recalculated for the displaced vertices.
Reflection via cubemap.
Color and normal texture with time based UV panning.

Shader "HeightMappedWater" {
    Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "white" {}
		_BumpMap ("Normal (Normal)", 2D) = "bump" {}
		_HeightMap ("Heightmap (R)", 2D) = "grey" {}
		_HeightmapStrength ("Heightmap Strength", Float) = 1.0
		_ExtrusionStrength ("Extrusion Strength", Float) = 1.0
		_HeightmapDimX ("Heightmap Width", Float) = 2048
		_HeightmapDimY ("Heightmap Height", Float) = 2048
		_Cube ("Cubemap", CUBE) = "" {}
		_CubeStrength ("Reflective", Range(0.0,1.0)) = 0.5
		_PanXSpeed ("UV Pan X Speed(-1.0 to 1.0)", Range(-1.0,1.0)) = 0.0
		_PanYSpeed ("UV Pan Y Speed(-1.0 to 1.0)", Range(-1.0,1.0)) = 0.0
	}

	SubShader{
		Tags { "Queue" = "Transparent" }
		Blend SrcAlpha OneMinusSrcAlpha // Alpha blending
		BlendOp Add
		Cull Back
		CGPROGRAM

			#pragma surface surf NormalsHeight vertex:vert alpha
			#pragma target 3.0

			struct Input
			{
				float2 uv_MainTex;
				float2 uv_HeightMap;
				float2 uv_BumpMap;
				float3 worldRefl;
          		INTERNAL_DATA
			};

			sampler2D _MainTex, _BumpMap, _HeightMap;
			float _HeightmapStrength, _HeightmapDimX, _HeightmapDimY,_ExtrusionStrength;
			float4 _Color;
			samplerCUBE _Cube;
      		float _CubeStrength;
      		float _PanXSpeed,_PanYSpeed;
      		float2 pannedUV;
      		
			void vert (inout appdata_full v) 
			{
				float4 tex = tex2Dlod (_HeightMap, float4(v.texcoord.xy,0,0));
					
				v.vertex.xyz += v.normal * (tex.rgb * _ExtrusionStrength);
			}
			
			void surf (Input IN, inout SurfaceOutput o)
			{
				pannedUV += fixed2(_PanXSpeed * _Time.y, _PanYSpeed * _Time.y);

				float3 normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap + pannedUV));

				float me = tex2D(_HeightMap,IN.uv_MainTex).x;
				float n = tex2D(_HeightMap,float2(IN.uv_HeightMap.x,IN.uv_HeightMap.y+1.0/_HeightmapDimY)).x;
				float s = tex2D(_HeightMap,float2(IN.uv_HeightMap.x,IN.uv_HeightMap.y-1.0/_HeightmapDimY)).x;
				float e = tex2D(_HeightMap,float2(IN.uv_HeightMap.x-1.0/_HeightmapDimX,IN.uv_HeightMap.y)).x;
				float w = tex2D(_HeightMap,float2(IN.uv_HeightMap.x+1.0/_HeightmapDimX,IN.uv_HeightMap.y)).x;

				float3 norm = normal;
				float3 temp = norm; //a temporary vector that is not parallel to norm
				if(norm.x==1)
					temp.y+=0.5;
				else
					temp.x+=0.5;

				//form a basis with norm being one of the axes:
				float3 perp1 = normalize(cross(norm,temp));
				float3 perp2 = normalize(cross(norm,perp1));

				//use the basis to move the normal in its own space by the offset
				float3 normalOffset = -_HeightmapStrength * ( ( (n-me) - (s-me) ) * perp1 + ( ( e - me ) - ( w - me ) ) * perp2 );
				norm += normalOffset;
				norm = normalize(norm);

				o.Normal = norm;
				o.Albedo = tex2D (_MainTex, IN.uv_MainTex + pannedUV).rgb * 1 - _CubeStrength;
				o.Albedo *= _Color.rgb;
				o.Emission = texCUBE (_Cube, WorldReflectionVector (IN, o.Normal)).rgb * _CubeStrength;
				o.Alpha = 0.8f;
			}

			inline fixed4 LightingNormalsHeight (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten)
			{
				viewDir = normalize(viewDir);
				lightDir = normalize(lightDir);
				s.Normal = normalize(s.Normal);
				float NdotL = dot(s.Normal, lightDir);
				_LightColor0.rgb = _LightColor0.rgb;

				fixed4 c;
				c.rgb = s.Albedo * saturate ( NdotL ) * _LightColor0.rgb * atten;
				c.a = 1.0;
				return c;
			}

		ENDCG
	}
	FallBack "VertexLit"
}