I've been working on a water shader and I've basically am trying to modify evolved's original water shader with one that I found on here that does "waves" in the vertex shader portion
Shader code
float4x4 WorldVP;
float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldInverseTranspose;
float4x4 ViewProj:ViewProjection;
float4x4 ViewInv:ViewInverse;
//camera position used to determine if camera is underwater or not.
float3 cameraPosition;
// Colour of the water surface
//float3 depthColour = {0.078f, 0.5176f, 0.9f}; //light blue to dark blue water
//float3 depthColour = {0.1, 0.1, 0.9}; //light blue to dark blue water
//float3 bigDepthColour = {0.13f, 0.13f, 0.15f};
// Colour of the water surface
float3 depthColour = {0.0078f, 0.5176f, 0.7f};
// Colour of the water depth
float3 bigDepthColour = {0.039f, 0.0196f, 0.145f};
float3 extinction = {7.0f, 30.0f, 40.0f}; // Horizontal
float time = 0;
float oct1Scale = 0.0005;
float oct2Scale = 0.002;
float oct3Scale = 0.005;
float oct2Time = 1.5;
float oct3Time = 0.8;
float oct1Power = 5.0;
float oct2Power = 0.75;
float oct3Power = 0.125;
float oct1Scroll = 0.01;
float oct2Scroll = 0.02;
float oct3Scroll = 0.06;
float sampleWidth = 20.0;
float sampleHeight = 40.0;
float FarPlane = 15000.0f - 0.1f;
float2 WaterScale={5.0f,5.0f};
float WaterBump=0.025f;
float2 Speed1={-0.05f,-0.1f};
float2 Speed2={0.02f,-0.04f};
float3 RefractColor={1.1f,1.1f,1.0f};
float3 ReflectColor={1.0f,1.1f,1.25f};
texture Texture0
<string resourceName = "";>;
sampler2D layer1Sampler = sampler_state
{
texture = <Texture0>;
magFilter = linear;
minFilter = linear;
mipFilter = linear;
addressU = wrap;
addressV = wrap;
};
texture FoamTX <string resourceName = "";>;
texture viewPositionTX <string Name=""; >;
texture WaterReflectTX <string Name=""; >;
texture WaterbumpTX <string Name=""; >;
texture WaterRefractTX <string Name=""; >;
texture DepthTX <string Name=""; >;
sampler2D DepthSampler=sampler_state
{
Texture = <DepthTX>;
ADDRESSU = WRAP;
ADDRESSV = WRAP;
ADDRESSW = WRAP;
//MagFilter = None;
//MinFilter = None;
//MipFilter = None;
};
sampler2D foam=sampler_state
{
Texture = <FoamTX>;
};
sampler2D viewPosition=sampler_state
{
Texture = <viewPositionTX>;
};
sampler2D WaterRefract=sampler_state
{
Texture = <WaterRefractTX>;
ADDRESSU = CLAMP;
ADDRESSV = CLAMP;
ADDRESSW = CLAMP;
MagFilter = None;
MinFilter = None;
MipFilter = None;
};
sampler2D WaterReflect=sampler_state
{
Texture = <WaterReflectTX>;
//ADDRESSU = CLAMP;
//ADDRESSV = CLAMP;
//ADDRESSW = CLAMP;
//MagFilter = None;
//MinFilter = None;
//MipFilter = None;
};
sampler2D Waterbump=sampler_state
{
Texture = <WaterbumpTX>;
MagFilter = Linear;
MinFilter = Point;
MipFilter = None;
};
struct VertexShaderInput
{
float4 Position : POSITION;
float2 TexCoord : TEXCOORD;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float fresnel : COLOR0;
float2 TexCoord : TEXCOORD0;
float4 ClipPos : TEXCOORD1;
float3 ViewPos : TEXCOORD2;
float4 RefrProj : TEXCOORD3;
float4 ReflProj : TEXCOORD4;
float2 Depth : TEXCOORD5;
float3x3 TBN : TEXCOORD6;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 wPos = mul( input.Position, World );
float2 sXY = wPos.xz;
float3 samples;
samples.x = tex2Dlod( layer1Sampler, float4( sXY * oct1Scale + time * oct1Scroll ,0.0f, 0.0f ) ).r;
samples.y = tex2Dlod( layer1Sampler, float4( sXY * oct2Scale + time * oct2Scroll ,0.0f, 0.0f ) ).g;
samples.z = tex2Dlod( layer1Sampler, float4( sXY * oct3Scale + time * oct3Scroll ,0.0f, 0.0f ) ).b;
samples *= 6.283185308f;
float height1 = samples.x * oct1Power;
height1 += sin( samples.y + time * oct2Time ) * oct2Power;
height1 += sin( samples.z + time * oct3Time ) * oct3Power;
sXY.x += sampleWidth;
samples.x = tex2Dlod( layer1Sampler, float4( sXY * oct1Scale + time * oct1Scroll ,0.0f, 0.0f ) ).r;
samples.y = tex2Dlod( layer1Sampler, float4( sXY * oct2Scale + time * oct2Scroll ,0.0f, 0.0f ) ).g;
samples.z = tex2Dlod( layer1Sampler, float4( sXY * oct3Scale + time * oct3Scroll ,0.0f, 0.0f ) ).b;
samples *= 6.283185308f;
float height2 = samples.x * oct1Power;
height2 += sin( samples.y + time * oct2Time ) * oct2Power;
height2 += sin( samples.z + time * oct3Time ) * oct3Power;
sXY = float2( wPos.x, wPos.z + sampleWidth );
samples.x = tex2Dlod( layer1Sampler, float4( sXY * oct1Scale + time * oct1Scroll ,0.0f, 0.0f ) ).r;
samples.y = tex2Dlod( layer1Sampler, float4( sXY * oct2Scale + time * oct2Scroll ,0.0f, 0.0f ) ).g;
samples.z = tex2Dlod( layer1Sampler, float4( sXY * oct3Scale + time * oct3Scroll ,0.0f, 0.0f ) ).b;
samples *= 6.283185308f;
float height3 = samples.x * oct1Power;
height3 += sin( samples.y + time * oct2Time ) * oct2Power;
height3 += sin( samples.z + time * oct3Time ) * oct3Power;
float3 norm = normalize( float3( height1 - height2, sampleHeight, height1 - height3 ) );
wPos.y += height1;
// float4 worldPosition = mul(float4(input.Position.xyz, 1), World);
float4 viewPosition = mul(wPos, View);
output.Position = mul(viewPosition, Projection);
//output.Position = mul(float4(worldPosition.xyz,1.0), ViewProj);
//mul(worldPosition, ViewProj);
float3 lightDir = normalize( wPos - cameraPosition );
float viewDotNorm = -reflect( lightDir, input.Normal );
float fresnelFactor = 1 - pow(viewDotNorm, 0.5);
output.fresnel = saturate(fresnelFactor + 0.3);
output.TexCoord = input.TexCoord;
output.ClipPos = output.Position;
output.ViewPos = viewPosition;
output.RefrProj=float4(output.Position.x*0.5+0.5*output.Position.w,
0.5*output.Position.w-output.Position.y*0.5,
output.Position.w,
output.Position.w);
//output.ReflProj=float4(output.Position.x*0.5+0.5*output.Position.w,
//0.5*output.Position.w+output.Position.y*0.5,
//output.Position.w,
//output.Position.w);
//output.ReflProj.y=output.ReflProj.y-1.0f;
output.ReflProj.x = 0.5 * (output.Position.w + output.Position.x);
output.ReflProj.y = 0.5 * (output.Position.w - output.Position.y);
output.ReflProj.z = output.Position.w;
output.ReflProj.w = output.Position.w;
output.TBN[0] = normalize(mul(input.Tangent, (float3x3)WorldInverseTranspose));
output.TBN[1] = normalize(mul(input.Binormal, (float3x3)WorldInverseTranspose));
output.TBN[2] = normalize(mul(input.Normal, (float3x3)WorldInverseTranspose ));
//output.TBN[2] = norm;//normalize(mul(input.Normal, (float3x3)WorldInverseTranspose ));
// output.TBN[0] = normalize(mul(input.Tangent, (float3x3)World));
//output.TBN[1] = normalize(mul(input.Binormal, (float3x3)World));
//output.TBN[2] = normalize(mul(input.Normal, (float3x3)World));
output.Depth.x = output.Position.z;
output.Depth.y = output.Position.w;
return output;
}
struct PixelShaderOutput
{
float4 Color : COLOR0;
float4 Normal : COLOR1;
float4 Depth : COLOR2;
};
//REFLECTION SHADER
PixelShaderOutput PixelShaderFunction(VertexShaderOutput input)
{
PixelShaderOutput output;
//float2 screenTexCoords = 0.5 * (float2(input.ClipPos.x, input.ClipPos.y) / input.ClipPos.w) + 0.5;
//screenTexCoords.y = 1 - screenTexCoords.y;
float2 screenTexCoords = float2(0.5, -0.5) * (float2(input.ClipPos.x, input.ClipPos.y) / input.ClipPos.w) + 0.5;
// Get the terrain depth
float sceneViewZ = tex2D(viewPosition, screenTexCoords).r;
// Get the water plane depth
float waterViewZ = length(input.ViewPos) / FarPlane;
// Get the range of depth from waterplane to terrain
float depthRange = (sceneViewZ - waterViewZ);
const float shoreFalloff = 0.5f;
const float shoreScale = 10.0f;
// calculate a transparency value using a power function
float alpha = ((pow(depthRange ,shoreFalloff)))*5; //max(pow(depthRange, shoreFalloff) * FarPlane * shoreScale, 0);
//float3 WaterColor = depthColour / (pow(depthRange , 0.5)*20);
//float3 WaterColor = depthColour / saturate((pow(depthRange , 0.5)*20)) ;
//WaterColor = lerp(foamt, WaterColor ,clamp(alpha,0,1));
//float3 WaterColor = lerp(depthColour,bigDepthColour, pow(depthRange , 0.5)*20);
//this will make smaller ripples closer to the shore line and larger ones further out
float dist = (input.Depth.x / input.Depth.y - 0.9f) * 10.0f;
//float2 wScale;
//wScale.x = 50;/// dist ;
//wScale.y = 50;/// dist ;
float4 Distort1 = tex2D(Waterbump, input.TexCoord);
Distort1 = (Distort1 + tex2D(Waterbump, input.TexCoord* WaterScale*4+(time*Speed1)) +
tex2D(Waterbump, input.TexCoord* WaterScale*16+(time*Speed1)) +
tex2D(Waterbump, input.TexCoord* WaterScale*64+(time*Speed1)) +
tex2D(Waterbump, input.TexCoord* WaterScale*256+(time*Speed1)) )/5;
float4 Distort2 = tex2D(Waterbump, input.TexCoord);
Distort2 = (Distort2 + tex2D(Waterbump, input.TexCoord* WaterScale*4+(time*Speed2)) +
tex2D(Waterbump, input.TexCoord* WaterScale*16+(time*Speed2)) +
tex2D(Waterbump, input.TexCoord* WaterScale*64+(time*Speed2)) +
tex2D(Waterbump, input.TexCoord* WaterScale*256+(time*Speed2)) )/5;
//float4 Distort1=tex2D(Waterbump,input.TexCoord);// * WaterScale*4+(time*Speed1);
//float4 Distort2=tex2D(Waterbump,input.TexCoord);// * WaterScale*4+(time*Speed2);
//Distort1 = Distort1 * WaterScale*4+(time*Speed1);
float4 Distort= (Distort1 + Distort2)-1.0;
Distort=Distort*(input.RefrProj.z*WaterBump);//*alpha);
float3 Refraction=tex2Dproj(WaterRefract,input.RefrProj+Distort); //*RefractColor;
float3 Reflection=tex2Dproj(WaterReflect,input.ReflProj+Distort); //*ReflectColor;
//float2 projcoord=(input.ReflProj.xy / input.ReflProj.z);
//float3 Reflection=tex2D(WaterReflect,projcoord+Distort);
// How fast will colours fade out. You can also think about this
// values as how clear water is. Therefore use smaller values (eg. 0.05f)
// to have crystal clear water and bigger to achieve "muddy" water.
float fadeSpeed = 0.15f;
// Water transparency along eye vector.
float visibility = 4.0f;
float3 WaterColor = lerp(depthColour,bigDepthColour, pow(depthRange , 0.5));
float3 waveColor = lerp(WaterColor,depthColour ,alpha);// + foamt;
// WaterColor = lerp( WaterColor , waveColor, alpha*0.5 );
//Refraction = Refraction*Refraction;
//Reflection = Reflection*Reflection;
//float3 Water = lerp(Refraction,Reflection,saturate(alpha));//input.fresnel);
float3 Water = lerp(Refraction,Reflection,input.fresnel);
//float3 Water = (Refraction*(1-input.fresnel) + Reflection*(input.fresnel));
//Water = (Water*WaterColor);
//Water = lerp(foamt,WaterColor,alpha*2);
Water = lerp(Water,WaterColor, .3);//depthRange+depthRange+depthRange+depthRange);
//**************************************************************************
//this is perfect for scrolling water down a river or a waterfall
//float3 foamt=tex2D(foam,input.TexCoord* WaterScale*10+(time*Speed1));
//output.Color = float4( foamt, alpha );
//**************************************************************************
float3 foamt=tex2D(foam,input.TexCoord* WaterScale*1000);
//we want to restrict the foam only to the parts of the shore that are close to ground
//like a beach look
float3 foam = WaterColor;
//foam.x = 0;
//foam.y = 0;
//foam.z = 0;
//if( alpha < 0.5 )
//{
foam = lerp(foam, foamt,alpha/2);
//}
//Water = waveColor;
output.Color = float4( Water, alpha );
//float3 normalFromMap = Distort.rgb;//*saturate(alpha);
float3 modelNormal = normalize(Distort.r*input.TBN[0] + Distort.g*input.TBN[1] + Distort.b*input.TBN[2]);
float3 modelNormal1 = normalize(input.TBN[2]);
modelNormal += modelNormal1;
//modelNormal = lerp(modelNormal,modelNormal1, 0.7);
modelNormal = normalize(modelNormal);
//output.Normal = float4(0.5f+normalize(mul(Distort,float3x3(input.TBN[0],input.TBN[1],input.TBN[2])))*0.5f,1);
output.Normal = float4(modelNormal.rgb * 0.5 + 0.5, alpha );
float Depth1 = input.Depth.x / input.Depth.y;
float3 Refraction11=tex2Dproj(DepthSampler,input.RefrProj+Distort);
//float3 Depth=tex2Dproj(Depth1,input.RefrProj+Distort);
output.Depth = Depth1;
return output;
}
technique Reflect
{
pass Pass1
{
VertexShader = compile vs_3_0 VertexShaderFunction();
PixelShader = compile ps_3_0 PixelShaderFunction();
AlphaBlendEnable = true ;
SrcBlend = SrcAlpha;
DestBlend = InvSrcAlpha;
//CullMode = ccw;
CullMode = None;
//SrcBlend = SrcAlpha;
//DestBlend = InvSrcAlpha;
//FillMode = WireFrame;
//CullMode = cw;
}
}
Now everything works fine except that when you introduce the waves that planar reflections do no follow the waves as I believe they should.
Now there relevant portion of code is:
float3 Reflection=tex2Dproj(WaterReflect,input.ReflProj+Distort); //*ReflectColor;
//float2 projcoord=(input.ReflProj.xy / input.ReflProj.z);
//float3 Reflection=tex2D(WaterReflect,projcoord+Distort);
Now it is my understanding that both tex2Dproj and tex2D with the calculated projected textcoords do the same exact thing. You get the nice reflection on a flat surface. I also thought this would get the reflction to follow the wave such as in this sample
http://gamedev.stackexchange.com/questions/61113/accounting-for-waves-when-doing-planar-reflections
So I guess there is two parts to this question
1: how do you account for vertex "waves" while doing planar reflections
2: How to you calculate "foam" at the shore line and on the edge of waves?
I know question 2 is probably the easier to answer but each time I try to use the alpha value for based on the "depth" then I get a sharp cut-off and or it tiles across the entire water surface
here is a link for the "foam" I would like to achieve
http://www.garagegames.com/community/forums/viewthread/124292/2
Any help on these two questions would be amazing because I've been banging my head for days.
I can build a project example if anyone needs it.
thank you