Reflective shader with pixel lights and shadows

Hey guys,

I’m a total n00b at shading. I was however to come up with this, based on the UnityPro Water Shader.

It does real-time reflections quite nicely. It doesn’t do shadows, however.

I’ve also tried adding a pixel light pass, but whenever I add it it overwrites everything else (only that pass makes it through).

Shader "RTReflection" { 
Properties {
	_Difuse ("Difuse (RGB)", 2D) = "" {}
	_SpecColor ("Spec Color", Color) = (1,1,1,1)
	_WaveScale ("Texture Scale", Range (0,4)) = 1
	_ReflAmm ("Reflection Intensity", Range (0,2)) = 1
	_ReflDistort ("Reflection distort", Range (0,1.5)) = 0.44
	_ReflColor ("Reflection color", COLOR)  = ( .34, .85, .92, 1)
	_Shininess ("Shininess", Range (0.01, 1)) = 0.7
	_Fresnel ("Fresnel (A) ", 2D) = "gray" {}
	_BumpMap ("Bumpmap (RGB) ", 2D) = "bump" {}
	_HorizonColor ("Simple water horizon color", COLOR)  = ( .172, .463, .435, 1)
	_ReflectionTex ("Internal Reflection", 2D) = "" {}
	
}


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

Subshader { 
	Tags { "WaterMode" = "Refractive" }
	
	
	Pass {
		
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest 
#pragma fragmentoption ARB_fog_exp2
#pragma multi_compile_builtin
#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"
#include "AutoLight.cginc"



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

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

struct v2f {
	V2F_POS_FOG;
	#if defined HAS_REFLECTION || defined HAS_REFRACTION
	float3 ref;
	#endif
	float2 bumpuv[3];
	float3 viewDir;
	LIGHTING_COORDS
}; 

v2f vert(appdata v)
{
	v2f o;
	PositionFog( v.vertex, o.pos, o.fog );
	
	// scroll bump waves
	float4 temp;
	temp.xyzw = (v.vertex.xzxz);
	o.bumpuv[0] = temp.xy * float2(.4, .45);
	o.bumpuv[1] = temp.wz;
    o.bumpuv[2] = temp.wz;
	
	// object space view direction (will normalize per pixel)
	o.viewDir.xzy = ObjSpaceViewDir(v.vertex);
	
	#if defined HAS_REFLECTION || defined HAS_REFRACTION
	// calculate the reflection vector
	float3x4 mat = float3x4 (
		0.5, 0, 0, 0.5,
		0, 0.5 * _ProjectionParams.x, 0, 0.5,
		0, 0, 0, 1
	);	
	o.ref = mul (mat, o.pos);
	#endif
	
	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;
sampler2D _Difuse;
uniform float4 _ReflColor;
uniform float _ReflAmm;
uniform float _WaveScale;

half4 frag( v2f i ) : COLOR
{
	i.viewDir = normalize(i.viewDir);
	
	// combine two scrolling bumpmaps into one
	half3 bump1 = tex2D( _BumpMap, i.bumpuv[0] ).rgb;
	half3 bump2 = tex2D( _BumpMap, i.bumpuv[1] ).rgb;
	half3 dif = tex2D( _Difuse, i.bumpuv[2] ).rgb;
	half3 bump = bump1 + bump2 -1;
	
	// fresnel factor
	half fresnelFac = dot( i.viewDir, bump);
	
	// perturb reflection/refraction UVs by bumpmap, and lookup colors
	
	#ifdef HAS_REFLECTION
	float3 uv1 = i.ref; uv1.xy += bump * _ReflDistort;
	half4 refl = tex2Dproj( _ReflectionTex, uv1 );
    refl = refl * _ReflColor;
	#endif
	half4 color;
	
	#ifdef WATER_REFLECTIVE
	color.rgb = lerp( dif.rgb, refl.rgb*_ReflAmm, dif.rgb );
	color.a = 0.01;
	#endif
	return color;
}
ENDCG	
}
Pass {
Blend One One
 Material {
				Diffuse (1,1,1,1)
                Shininess [_Shininess]
                Specular [_SpecColor]
            }
		
			Lighting On
            SeperateSpecular On
				SetTexture [_Difuse] {
				Combine primary,  constant
    }



}

}

}

Is there anyway to get pixel lighting and shadows on this thing? Oh, and maybe normal maps :smile:

Thank you!

I think you have no shadows because you don’t have any shadowcollector or shadowreciever passes. This is what unity uses to draw shadows.

Adding
Fallback “VertexLit”, 2
Might do it. It might mess up the shader though.

You might also need to do some lighting calculations also using DiffuseLight functions.

For normal maps you need to calculate the tangent space light direction in the shader
v2f vert (appdata_tan v)
{
… vertex shader code

// This calculates the tangent space needed for bump maps
TANGENT_SPACE_ROTATION;
// convert the lightdirection into tangent space
o.lightDirTan = mul(rotation, ObjSpaceLightDir(v.vertex));


}

Then in the fragment shader do something like this

// Grabs the normal from the normalmap color and offsets it since normals go from -1 to 1
float3 normalFromBumpMap = tex2D(_BumpTex, i.uv.xy).xyz * 2 - 1;

//Then use that bump normal as the surface normal in the lighting calculations and use light in tangent space
half4 color = DiffuseLight(i.lightDirTan, normalFromBumpMap , textureColor, LIGHT_ATTENUATION(i));

It’s not a simple process. Hope this somehow helps.