//==================================================== // Water //==================================================== // By EVOLVED // www.evolved-software.com //==================================================== #define ChromaticAberration 1 //-------------- // un-tweaks //-------------- matrix ViewProj:ViewProjection; matrix ViewInv:ViewInverse; float time:Time; //-------------- // tweaks //-------------- float2 ViewSize; float3 WaterIndex1[25]; float4 WaterIndex2[50]; float2 WaterIndex3[15]; float3 WaterSize; float4 WaterTileSize; float4 WaterHeight; float2 WaterScale={1.75f,2.25f}; float4 WaterSpeed={-0.02f,-0.02f,0.03f,-0.02f}; float WaterBump=0.1f; float3 WaterColor={0.2,0.6,0.5}; float2 DetailScale={25,20}; float4 DetailSpeed={0.0025f,-0.0025f,0.01f,-0.01f}; float DetailBump=0.2f; float3x3 TBN={float3(1,0,0),float3(0,0,1),float3(0,1,0)}; float3 LightPosition; float3 LightColor; float3 SpecularColor; float SpecularPow=128.0f; float4 FogRange; float3 FogColor1; float3 FogColor2; float3 HeightFog; float4 HeightFogColor; //-------------- // Textures //-------------- texture DepthTexture ; sampler DepthSampler=sampler_state { Texture=; MagFilter=Point; MinFilter=Point; MipFilter=Point; }; texture WaterTexture ; sampler WaterSampler=sampler_state { Texture=; }; texture WaterHTexture ; sampler WaterHSampler=sampler_state { Texture=; MagFilter=Linear; MinFilter=Point; MipFilter=None; }; texture DetailTexture ; sampler DetailSampler=sampler_state { Texture=; }; texture RefractTexture ; sampler RefractSampler=sampler_state { Texture=; ADDRESSU=CLAMP; ADDRESSV=CLAMP; ADDRESSW=CLAMP; }; texture ReflectTexture ; sampler ReflectSampler=sampler_state { Texture=; ADDRESSU=CLAMP; ADDRESSV=CLAMP; ADDRESSW=CLAMP; }; //-------------- // structs //-------------- struct In_AboveWater { float4 Pos:POSITION; float2 Tex1:TEXCOORD0; float2 Tex2:TEXCOORD1; float2 Index1:TEXCOORD2; float2 Index2:TEXCOORD3; float2 Index3:TEXCOORD4; }; struct Out_AboveWater { float4 Pos:POSITION; float4 Tex1:TEXCOORD0; float4 Tex2:TEXCOORD1; float4 Proj:TEXCOORD2; float4 ReflProj:TEXCOORD3; float3 WPos:TEXCOORD4; float3 ViewPos:TEXCOORD5; float3 ViewVec:TEXCOORD6; float3 LightVec:TEXCOORD7; }; struct In_UnderWater { float4 Pos:POSITION; float2 Tex1:TEXCOORD0; float2 Tex2:TEXCOORD1; float2 Index1:TEXCOORD2; float2 Index2:TEXCOORD3; float2 Index3:TEXCOORD4; }; struct Out_UnderWater { float4 Pos:POSITION; float4 Tex1:TEXCOORD0; float4 Tex2:TEXCOORD1; float4 Proj:TEXCOORD2; }; //-------------- // vertex shader //-------------- Out_AboveWater VS_AboveWater(In_AboveWater IN) { Out_AboveWater OUT; float3 NewPos=(IN.Pos.xyz*WaterSize.z)+WaterIndex1[IN.Index1.x].xyz; float2 NewUv=(NewPos.xz/WaterTileSize.xy); OUT.Tex1=float4(NewUv*WaterScale.x,NewUv*WaterScale.y)+(time*WaterSpeed); OUT.Tex2=float4(NewUv*DetailScale.x,NewUv*DetailScale.y)+(time*DetailSpeed); float MaxUvOffset=abs(IN.Tex1.y)*WaterIndex2[IN.Index1.y].z*abs(IN.Tex1.x); float ClampUvOffset=WaterIndex2[IN.Index1.y].y; float FlipUvOffset=WaterIndex2[IN.Index1.y].x; float2 UvOffset1=(float2(0,-1*MaxUvOffset)+(float2(IN.Tex1.y,lerp(IN.Tex1.x,-IN.Tex1.x,FlipUvOffset))*ClampUvOffset)*WaterIndex3[IN.Index3.x].y)/WaterSize.xy; float2 UvOffset2=(float2(0,1*MaxUvOffset)+(float2(IN.Tex2.y,lerp(IN.Tex2.x,-IN.Tex2.x,FlipUvOffset))*ClampUvOffset)*WaterIndex3[IN.Index3.x].y)/WaterSize.xy; float Height1=tex2Dlod(WaterHSampler,float4(OUT.Tex1.xy+(UvOffset1*WaterScale.x),0,0)).w+tex2Dlod(WaterHSampler,float4(OUT.Tex1.zw+(UvOffset1*WaterScale.y),0,0)).w-1; float Height2=tex2Dlod(WaterHSampler,float4(OUT.Tex1.xy+(UvOffset2*WaterScale.x),0,0)).w+tex2Dlod(WaterHSampler,float4(OUT.Tex1.zw+(UvOffset2*WaterScale.y),0,0)).w-1; float LerpHeight=saturate(WaterIndex2[IN.Index1.y].w+WaterIndex3[IN.Index3.x]); float HeightScale=1-pow(saturate(length(ViewInv[3].xz-NewPos.xz)/WaterHeight.w),3); NewPos.y=WaterHeight.x+(lerp(tex2Dlod(WaterHSampler,float4(OUT.Tex1.xy,0,0)).w+tex2Dlod(WaterHSampler,float4(OUT.Tex1.zw,0,0)).w-1,lerp(Height1,Height2,0.5),LerpHeight)*WaterHeight.y*HeightScale); OUT.Pos=mul(float4(NewPos,IN.Pos.w),ViewProj); OUT.Proj=float4(OUT.Pos.x*0.5+0.5*OUT.Pos.w,0.5*OUT.Pos.w-OUT.Pos.y*0.5,OUT.Pos.w,OUT.Pos.z); OUT.ReflProj=float4(OUT.Pos.x*0.5+0.5*OUT.Pos.w,0.5*OUT.Pos.w+OUT.Pos.y*0.5,OUT.Pos.w,OUT.Pos.w); OUT.ReflProj.y=OUT.ReflProj.y-1.0f; OUT.WPos=NewPos; float3 ViewVec=ViewInv[3].xyz-NewPos; OUT.ViewPos=ViewVec; OUT.ViewVec=mul(ViewVec,TBN); float3 LightPos=LightPosition-NewPos; OUT.LightVec=mul(LightPos,TBN); return OUT; } Out_UnderWater VS_UnderWater(In_UnderWater IN) { Out_UnderWater OUT; float3 NewPos=(IN.Pos.xyz*WaterSize.z)+WaterIndex1[IN.Index1.x].xyz; float2 NewUv=(NewPos.xz/WaterTileSize.xy); OUT.Tex1=float4(NewUv*WaterScale.x,NewUv*WaterScale.y)+(time*WaterSpeed); OUT.Tex2=float4(NewUv*DetailScale.x,NewUv*DetailScale.y)+(time*DetailSpeed); float MaxUvOffset=abs(IN.Tex1.y)*WaterIndex2[IN.Index1.y].z*abs(IN.Tex1.x); float ClampUvOffset=WaterIndex2[IN.Index1.y].y; float FlipUvOffset=WaterIndex2[IN.Index1.y].x; float2 UvOffset1=(float2(0,-1*MaxUvOffset)+(float2(IN.Tex1.y,lerp(IN.Tex1.x,-IN.Tex1.x,FlipUvOffset))*ClampUvOffset)*WaterIndex3[IN.Index3.x].y)/WaterSize.xy; float2 UvOffset2=(float2(0,1*MaxUvOffset)+(float2(IN.Tex2.y,lerp(IN.Tex2.x,-IN.Tex2.x,FlipUvOffset))*ClampUvOffset)*WaterIndex3[IN.Index3.x].y)/WaterSize.xy; float Height1=tex2Dlod(WaterHSampler,float4(OUT.Tex1.xy+(UvOffset1*WaterScale.x),0,0)).w+tex2Dlod(WaterHSampler,float4(OUT.Tex1.zw+(UvOffset1*WaterScale.y),0,0)).w-1; float Height2=tex2Dlod(WaterHSampler,float4(OUT.Tex1.xy+(UvOffset2*WaterScale.x),0,0)).w+tex2Dlod(WaterHSampler,float4(OUT.Tex1.zw+(UvOffset2*WaterScale.y),0,0)).w-1; float LerpHeight=saturate(WaterIndex2[IN.Index1.y].w+WaterIndex3[IN.Index3.x]); float HeightScale=1-pow(saturate(length(ViewInv[3].xz-NewPos.xz)/WaterHeight.w),3); NewPos.y=WaterHeight.x+(lerp(tex2Dlod(WaterHSampler,float4(OUT.Tex1.xy,0,0)).w+tex2Dlod(WaterHSampler,float4(OUT.Tex1.zw,0,0)).w-1,lerp(Height1,Height2,0.5),LerpHeight)*WaterHeight.y*HeightScale); OUT.Pos=mul(float4(NewPos,IN.Pos.w),ViewProj); OUT.Proj=float4(OUT.Pos.x*0.5+0.5*OUT.Pos.w,0.5*OUT.Pos.w-OUT.Pos.y*0.5,OUT.Pos.w,OUT.Pos.z); return OUT; } //-------------- // pixel shader //-------------- float4 PS_AboveWater(Out_AboveWater IN) : COLOR { float2 ViewProj=(IN.Proj.xy/IN.Proj.z); float Depth=tex2D(DepthSampler,ViewProj+ViewSize).w-IN.Proj.w; clip(Depth); float4 NormalMap=tex2D(WaterSampler,IN.Tex1.xy)+tex2D(WaterSampler,IN.Tex1.zw); float Foam=tex2D(DetailSampler,IN.Tex2.zw+(NormalMap*0.2f)).w*((1-saturate(Depth*0.02f))+pow(NormalMap.w*0.5,4)); NormalMap.xyz=lerp(NormalMap.xyz-1,tex2D(DetailSampler,IN.Tex2+(NormalMap*0.1f)).xyz*2-1,DetailBump); NormalMap.xyz=normalize(NormalMap.xyz); float3 LightVec=normalize(IN.LightVec); float Light=dot(NormalMap,LightVec); float3 View=normalize(IN.ViewVec); float Fresnel=pow(1-dot(NormalMap,View),5); float Specular=pow(saturate(dot(-View,reflect(LightVec,NormalMap.xyz))),SpecularPow); NormalMap.xy *=WaterBump*saturate(Depth*0.0025f); float3 Reflection=tex2D(ReflectSampler,(IN.ReflProj.xy/IN.ReflProj.z)+NormalMap); NormalMap.xy *=saturate(tex2D(DepthSampler,ViewProj+NormalMap).w-IN.Proj.w); #if ChromaticAberration== 1 float3 Refraction; Refraction.x=tex2D(RefractSampler,ViewProj+(NormalMap*1.2f)).x; Refraction.y=tex2D(RefractSampler,ViewProj+NormalMap).y; Refraction.z=tex2D(RefractSampler,ViewProj+(NormalMap/1.2f)).z; #else float3 Refraction=tex2D(RefractSampler,ViewProj+NormalMap); #endif Refraction=lerp(Refraction,WaterColor*LightColor,(NormalMap.w*0.25f)*Light); LightVec=IN.WPos-LightPosition; float ViewVecL=length(IN.ViewPos.xyz); float4 FogDist=saturate(float4(pow(ViewVecL.xx/FogRange.xy,FogRange.zw),length(LightVec)/(FogRange.x*2),exp(-((IN.WPos.y-HeightFog.x)/HeightFog.y)*HeightFog.z)*HeightFogColor.w)); float4 Fog=float4(lerp(HeightFogColor.xyz,lerp(FogColor2,FogColor1,FogDist.z),FogDist.x),saturate((FogDist.w*FogDist.y)+FogDist.x)); return float4(lerp(lerp(Refraction,Reflection,Fresnel)+(Specular*SpecularColor)+Foam,Fog.xyz,Fog.w),Depth*0.05f); } float4 PS_UnderWater(Out_UnderWater IN) : COLOR { float2 ViewProj=(IN.Proj.xy/IN.Proj.z); float Depth=tex2D(DepthSampler,ViewProj+ViewSize).w-IN.Proj.w; clip(Depth); float3 NormalMap=tex2D(WaterSampler,IN.Tex1.xy)+tex2D(WaterSampler,IN.Tex1.zw)-1; NormalMap +=(tex2D(DetailSampler,IN.Tex2+(NormalMap*0.25f))-0.5f)*DetailBump; NormalMap=normalize(NormalMap); NormalMap.xy *=WaterBump; NormalMap.xy *=saturate(tex2D(DepthSampler,ViewProj+NormalMap).w-IN.Proj.w); #if ChromaticAberration== 1 float3 Refraction; Refraction.x=tex2D(RefractSampler,ViewProj+(NormalMap*1.1f)).x; Refraction.y=tex2D(RefractSampler,ViewProj+NormalMap).y; Refraction.z=tex2D(RefractSampler,ViewProj+(NormalMap/1.1f)).z; #else float3 Refraction=tex2D(RefractSampler,ViewProj+NormalMap); #endif return float4(Refraction,Depth*0.04f); } //-------------- // techniques //-------------- technique AboveWater { pass p1 { vertexShader = compile vs_3_0 VS_AboveWater(); pixelShader = compile ps_3_0 PS_AboveWater(); SrcBlend=srcalpha; ColorWriteEnable=7; CullMode=ccw; } } technique UnderWater { pass p1 { vertexShader = compile vs_3_0 VS_UnderWater(); pixelShader = compile ps_3_0 PS_UnderWater(); SrcBlend=srcalpha; ColorWriteEnable=7; CullMode=cw; } }