Unity 5 Mobile Water Shader

Unity 5 Mobile Water Shader, as for me enough cheap with a good set of possible effects.

Shader "Water\MobileWater" {
Properties{
_WaterContrast("Water Contrast", Range(0, 1)) = 0.3
_WaterSpeed("Water Speed", Range(0.01, 2)) = 0.4
_WaterDepth("WaterDepth", Range(0, 1)) = 0.3
_WaterTile("Water Tile", Range(1, 10)) = 2.5
_WaveNormal("Wave Normal", 2D) = "bump" {}
_SpecularGloss("Specular Gloss", Range(0.5, 20)) = 1.5
_SpecularPower("Specular Power", Range(0, 2)) = 0.5
_WaveWind("Wave Wind", Range(0, 1)) = 0.5
_WaveSpeed("Wave Speed", Range(0.01, 1)) = 0.4
_WaveHeight("Wave Height", Range(0, 50)) = 0.5
_WaveTile1("Wave Tile X", Range(10, 500)) = 400
_WaveTile2("Wave Tile Y", Range(10, 500)) = 400
_CoastColor("Coast Color", COLOR) = (0.17647, 0.76863, 0.82353, 1)
_CoastDepth("Coast Depth", COLOR) = (0, 1.0, 0.91373, 1)
_OceanColor("Ocean Color", COLOR) = (0.03529, 0.24314, 0.41961, 1)
_OceanDepth("Ocean Depth", COLOR) = (0.25098, 0.50980, 0.92549, 1)
_IslandMask("Island Mask", 2D) = "white" {}
_FoamDiffuse("Foam texture", 2D) = "white" {}
_FoamTileX("Foam Tile X", Range(0, 2.0)) = 0.5
_FoamTileY("Foam Tile Y", Range(0, 2.0)) = 0.5

}
SubShader{
Tags{ "LightMode" = "ForwardBase" }
Pass{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert 
#pragma fragment frag 
#pragma target 2.0

uniform sampler2D _FoamDiffuse,_IslandMask,_WaveNormal;
uniform float _WaveHeight,_WaterContrast,_WaveTile1,_WaveTile2,_WaterTile,_FoamTileX,_FoamTileY,_WaveWind,_WaterDepth,_WaveSpeed,_WaterSpeed,_SpecularGloss,_SpecularPower;
uniform float4 _Normal,_IslandFoam, _CoastColor, _CoastDepth, _OceanColor, _OceanDepth;

float4 costMaskF(float2 posUV){ return tex2Dlod(_IslandMask, float4(posUV,1.0,1.0));}

struct vertexOutput {
float4 pos : SV_POSITION;
float3 _Color : TEXCOORD0;
float3 _Depth : TEXCOORD1;
float4 _Normal : TEXCOORD2;
float4 _IslandFoam : TEXCOORD3;
};

vertexOutput vert(appdata_base a)
{
vertexOutput o;
float2 uv = a.texcoord.xy;
float4 pos = a.vertex;
// coast setup
float2 posUV = uv;
float4 coastMask = costMaskF(posUV); // mask for coast in blue channel
float animTimeX = uv.y *_WaveTile1 + _Time.w * _WaveSpeed; // add time for shore X
float animTimeY = uv.y *_WaveTile2 + _Time.w * _WaveSpeed; // add time for shore Y
float waveXCos = cos(animTimeX)+1;
float waveYCos = cos(animTimeY);
// coast waves
pos.z += (waveXCos * _WaveWind * coastMask) * coastMask;
pos.y += (waveYCos * _WaveHeight * _WaveWind * 0.25) * coastMask;
o.pos = mul(UNITY_MATRIX_MVP, pos);
// custom uv
float2 foamUV = float2(a.vertex.x *_FoamTileX, a.vertex.z *_FoamTileY);
float2 normalUV = float2(uv.x * 2.0, uv.y * 2.0) * 4.0;
// reflections
float3 lightPos = float3(-22.0, -180.0, -6.80);
float3 lightDir = float3(15.0, 1.0, 10.0);
float3 lightVec = normalize(lightPos - o.pos.xyz);
float lightRef = (1.0 - (dot(lightDir, lightVec)));
lightRef = lightRef * 0.25 + (lightRef * lightRef); // get rid of left side
// edge and depth water
float step = saturate(_WaterDepth);
float depthX = (a.vertex.x * 0.22 - 1.0); // centering depth area
float depthY = (a.vertex.z * 0.22 - 1.5); // centering depth area
float depth = pow((depthX * depthX + depthY * depthY) * 0.006,3);
float edge = saturate(step - (1.0 - depth) * 0.5);
// Vertex Custom Output
o._Color.rgb = lerp(_CoastColor.rgb, _OceanColor.rgb, edge);
o._Depth.rgb = lerp(_CoastDepth.rgb, _OceanDepth.rgb, edge);
o._IslandFoam.xy = posUV;
o._IslandFoam.zw = foamUV + float2(1-_Time.x, 1-_Time.x)*0.5;
o._Normal.xy = normalUV*_WaterTile + float2(0, _Time.x * _WaterSpeed); 
o._Normal.w = 1.0 - saturate(lightRef *(length((lightPos.x - (o.pos.z - 35.0))) * 0.002) * _SpecularGloss); // spec coeff
o._Normal.z = (sin((a.vertex.x - _Time.w) - (a.vertex.z + _Time.x) * 5) + 1.0) * 0.5; // normal coeff
return o;
}

float4 frag(vertexOutput i) : COLOR {
float4 normal = tex2D(_WaveNormal, i._Normal.xy);
float3 foam = float3(tex2D(_FoamDiffuse, float2(i._IslandFoam.z, i._IslandFoam.w - _Time.x)).r, 1.0, 1.0);
float3 mask = tex2D(_IslandMask, i._IslandFoam.xy).rgb*foam;
mask.g += _WaterContrast; // contrast point
float4 color = float4(lerp(i._Depth, i._Color, (normal.x * i._Normal.z) + (normal.y * (1.0 - i._Normal.z))), 0.5)
+ exp2(log2((((normal.z) * i._Normal.z)*(1-mask.b*0.75) // waves light
+ (normal.w * (1.0 - i._Normal.z))*(1-mask.b*0.75) // waves light
)* i._Normal.w ) * 3 ) * _SpecularPower ; // narrowing 
color = float4(lerp(color, float4(1, 1, 1, mask.x), mask.x) * mask.yyyy); // blend with foam
color.w *= mask.g; // adjust an alpha to add more colors 
return color;
} ENDCG }} Fallback "Unlit/Texture" }

Explanation:

_IslandMask – use 4 channel:

.r –  use this for select an areas where do you want to have the foam.

.g – use this for light and color information

.b – use this for select an areas where do you want to have the waves.

.a – for alpha

_WaveNormal - use this for a wave, color and specular effects.


This is an example, you can make your own texture, also you need to add foam.


Coast

Setting example

                    

Unity 5 unlit shadow cutout cast receive shaders

Unity unlit shaders with shadow and cutout – it can be useful:

Unlit shadow cast

Shader "UnlitShadows/UnlitShadowCast" {
Properties{ _MainTex("Base (RGB)", 2D) = "white" {} }
SubShader{ Pass{ SetTexture[_MainTex] } } FallBack "VertexLit" }

Unlit shadow cast cutout

Shader "UnlitShadows/UnlitShadowCastCutout" {
Properties{ _Color("Main Color", Color) = (1,1,1,1) _MainTex("Base (RGB)", 2D) = "white" {} _Cutoff("Cutout", Range(0,1)) = 0.5 }
SubShader{ Pass{ Alphatest Greater[_Cutoff] SetTexture[_MainTex] } } Fallback "Transparent/Cutout/VertexLit" }

Unlit shadow receive

Shader "UnlitShadows/UnlitShadowReceive" {
Properties{ _MainTex("Base (RGB)", 2D) = "white" {} }
SubShader{ Pass{ SetTexture[_MainTex] } Pass { Blend DstColor Zero Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase
#include "AutoLight.cginc"
struct v2f {
float4 pos : SV_POSITION; LIGHTING_COORDS(0,1) };
v2f vert(appdata_base v) {
v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); TRANSFER_VERTEX_TO_FRAGMENT(o);
return o; }
fixed4 frag(v2f i) : COLOR{
float attenuation = LIGHT_ATTENUATION(i);
return attenuation;
} ENDCG } } Fallback "VertexLit" }

Unlit shadow receive cutout

Shader "UnlitShadows/UnlitShadowReceive" {
Properties{ _Color("Main Color", Color) = (1,1,1,1) _MainTex("Base (RGB)", 2D) = "white" {}	_Cutoff("Cutout", Range(0,1)) = 0.5 }
SubShader{ Pass{ Alphatest Greater[_Cutoff] SetTexture[_MainTex] }	Pass{ Blend DstColor Zero Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase
#include "AutoLight.cginc"
struct v2f {
float4 pos : SV_POSITION; LIGHTING_COORDS(0,1) };
v2f vert(appdata_base v) {
v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); TRANSFER_VERTEX_TO_FRAGMENT(o);
return o; }
fixed4 frag(v2f i) : COLOR{
float attenuation = LIGHT_ATTENUATION(i);
return attenuation;
} ENDCG } } Fallback "Transparent/Cutout/VertexLit" } 
Posted in abuse by admin

Amulet Of Dreams

aod-icon

Classik HOPA game! You will have help on this path: the Amulet of Worlds to serve as a portal connecting the edges of reality, and a small Goblin to squeeze into places no human could.

Game Designer, Product Manager, Scripter, QA

Diffuse approximation for consoles

Final Oren-Nayar diffuse with Fresnel approximaton from research.tri-ace.com (0) in HLSL.

   //////////////////////////////////////////////////
	// a = roughness				//
	// f0 = fresnel   				//
	// LdN = dot( light_direction, surface_normal ) //
	// VdN = dot( view_direction, surface_normal )  //
	// LdV = dot( light_direction, view_direction ) //
	//////////////////////////////////////////////////
	float fTheta = f0+dot((1.0f-f0), pow(2.0f, -9.60232*pow(VdH,8.0f)-8.58092*VdH));
	float Bp = 0.0f;
	float Bpl = LdV-(VdN*LdN);	
	float Fr = (1.0f-(0.542026f*(a*a)+0.303573f*a)/((a*a)+1.36053f))*
		(1.0f-(pow(1.0f-VdN,5.0f-4.0f*(a*a)))/((a*a)+1.36053f))*
		((-0.733996*(a*a*a)+1.50912*(a*a)-1.16402*a)*(pow(1.0f-VdN,1.0f+(1.0f/(39.0f*(a*a*a*a)+1.0f))))+1.0f);
	float Lm = (max(1.0f-(2.0f*a),0.0f)*(1.0f-(1.0f-pow(LdN,5.0f)))+min(2.0f*a,1.0f))*((1.0f-0.5f*a)*LdN+(0.5*a)*(pow(LdN,2.0f)));
	float Vd = ((a*a)/(((a*a)+0.09f)*(1.31072f+0.995584f*VdN)))*(1.0f-(pow(1.0f-LdN,(1.0f-0.3726732*(VdN*VdN))/(0.188566f+0.38841*VdN))));
	if (Bpl < 0.0f)
		Bp = 1.4f*VdN*LdN*(LdV-(VdN*LdN));
	else 
		Bp = LdV-((VdN*LdN));
	float aDiffuse = (21.0f/(20.0f*pi))*(1.0f-f0)*((Fr*Lm)+(Vd*Bp));

Spec BRDF ref

////////////////////////
//LD - Light direction//
//VD - View direction //
//N  - Normal         //
//a  - Roughness      //	
////////////////////////
float pi				= 3.14159265358979323;
float a 				= roughness * roughness;
float3 H				= normalize(LD + VD);
float HdotN	  			= dot( N, H );
float VdotH				= dot( VD, H );
float VdotN				= saturate(dot( N, VD ));
float LdotN				= saturate( dot( LD, N ));
float LdotH				= saturate(dot( N, H ));

//Normal Distribution Function//
////////////BECKMANN////////////
float NDF_Beckmann = 1.0 / ( pi * a * a ( pow( NdotH, 4.0f ) ) ) * exp ( ( pow( NdotH, 2.0f) - 1.0f ) / a * a * ( pow( NdotH, 2.0f ) ) );

////////////////////////////////
//////////BLINN_PHONG///////////
float NDF_BlinnPhong = ( 1.0f / ( pi * a * a ) ) * ( pow( NdotH, 2.0 / ( a * a ) - 2.0f ) );

////////////////////////////////
////GGX(TROWBRIDGE-REITZ)///////
float NDF_TrowReitz = ( a * a ) / pi * ( pow( (pow( NdotH, 2.0f ) * ( a * a - 1.0f ) + 1.0f ), 2.0) );


////////////////////////////////
////////////G-TERM//////////////
//////SIMPLE(Implicit)//////////
float G_Simple = LdotN * VdotN;

////////////////////////////////
//////////KELEMEN///////////////
float G_Kelemen = ( LdotN * VdotN ) / ( pow( VdotH, 2.0f ) );

////////////////////////////////
////////////NEUMANN/////////////
float G_Neumann = ( LdotN * VdotN ) / max( LdotN, VdotN );

////////////////////////////////
////////BECKMANN////////////////
float G_Beckmann = 0.0;
float c = VdotN / ( a * sqrt( 1.0f - ( pow( VdotN, 2.0f ) ) ) );
if ( c < 1.6) {
	G_Beckmann = ( 3.535f * c + 2.181 * pow(c, 2.0f ) ) / ( 1.0f + 2.276 * c + 2.577 * pow(c, 2.0f ) );
}
else {
	G_Beckmann = 1.0f;
}

//////////////////////////////// 
////////COOK-TORRANCE///////////
float G_CookTorr = min( 1.0f, min( ( 2.0f * HdotN * VdotH ) / VdotH, ( 2.0f * HdotN * LdotN ) / VdotH ) );

////////////////////////////////
/////////GGX(SMITH-WALTER)////////////
float G_GGXL = ( 2.0f * LdotN ) / ( LdotN + sqrt(a * a + ( 1.0f - a * a ) * ( pow(LdotN, 2.0f ) ) ) );
float G_GGXV = ( 2.0f * VdotN ) / ( VdotN + sqrt(a * a + ( 1.0f - a * a ) * ( pow(VdotN, 2.0f ) ) ) );
float G_GGX_SmithWalter = G_GGXV * G_GGXL; 

////////////////////////////////
/////GGX(SMITH-BECKMANN)////////
float G_GGXL = LdotN / ( a * sqrt(1.0f - ( pow(LdotN, 2.0f ) ) ) );
float G_GGXV = VdotN / ( a * sqrt(1.0f - ( pow(VdotN, 2.0f ) ) ) );
float G_GGX_SmithBeckmann = G_GGXV * G_GGXL; 

////////////////////////////////
/////GGX(SMITH-SCHLICK)/////////
float k = a * sqrt( 2.0f / pi );
float G_GGXL = LdotN / ( LdotN * ( 1.0f - k ) + k );
float G_GGXV = VdotN / ( VdotN * ( 1.0f - k ) + k );
float G_GGX_SmithSchlick = G_GGXV * G_GGXL; 

////////////////////////////////
///////////FRESNEL//////////////
//////////SHLICK////////////////
float F0 = FRESNEL; //Reflectance at normal incidence
float F_Schlick = F0 + ( 1.0f - F0) * pow(1.0f - VdotH, 5.0f );

////////////////////////////////
/////////COOK-TORRANCE//////////
float Eta = ( 1.0f + sqrt(F0 ) ) / ( 1.0f - sqrt(F0 ) );
float c = VdotH;
float g = sqrt(pow(Eta, 2.0f ) + pow(c, 2.0f ) - 1.0f );
float F = 0.5f * (pow( ( g - c ) / ( g + c ) , 2.0f ) * ( 1.0f + (pow( ( ( g + c ) * c - 1.0f ) / ( ( g - c ) * c + 1.0f ), 2.0f ) ) ) );

HDR Image assemble

We have several LDR with different exposure and we need to make a one HDR image.

Let’s nubmer of this LDR images will be
$$
j=1..n
$$
The exposure time of image j
$$
\Delta t_j
$$

Let response of a point on the sensor element will be the exposure X. We will base on the principle of reversibility, which is a physical property electronic imaging systems, based this exposure can be defined:  $$ E * \Delta t \\ E \text{- Illumination,}\: \Delta T \text{- time} $$

Unfortunatelly pixel value in photo not equal X. Lets make:
$$
\text{pixel value}\: i,\: \text{in image} j = Z_{ij}
$$
then
$$ Z_{ij} = f(X) = f(E_i\Delta t_j)
$$
f – camera response function (0) – converts the exposure to the pixel value

We can find this function or it can be assumed to match the sRGB standard, gamma correction curve with
$$
\gamma = 2.2
$$
In this case (where we now this function)
$$
f^-1(Z_{ij}) = E_i\Delta t_j
$$
then
$$
E_j = \frac{f^-1(Z_{ij})}{\Delta t}
$$
At this moment we have a problem, it’s impossible to restore luminance using one image, because we will lose information in underexposed and overexposed pixels.
In other words we need to take information from all images with different weighting.
$$
w(Z)\: -\: \text{function used to attenuate the contribution of poorly exposed pixels}
$$
$$
E_i = \frac{\sum\limits_{j=1}^n(\frac{w(Z_{ij}f^-1(Z_{ij}}{\Delta t})}{\sum\limits_{j=1}^nw(Z_{ij})}
$$

We assume that the LDR images are captured in sRGB so we can use the Luminance standard computation wich I describe earlier(1)
Also
$$
Z_{ij} \in [0;1] $$

float weight1 ( float lum) 
{
float res = 1.0 - pow((2.0 * lum - 1.0), 12.0);
return res;
}

Edit UVs Grid in Maya

We have a Grid tool in UV Editor, for repositions any currently selected UV to its nearest grid intersection in UV texture space.

GridUV

But the problem is that we have MAXIMUM in Grid U and Grid V number of grid lines set to 1024.

1024_gridUV

But what if we need or have more high res texture? Something like 2048 or even 4096?

You can download performPolyGridUV4096, just unzip to the root Maya folder (2014,2015 certainly works).

Now you will have an ability to set up to 4096.

4096