The water wake is really simple, it’s the standart Water Surface Splash prefab from the particles packet.
2 Particle sources 1 smaller in the front and 1 in the back for the engine. The engine’s particle system is linked to the Horizontal InputAxis to create larger particles when the user applies more throttle.
I used the Patricles/AlphaBlended shader for particles, but really its nothing special.
Maybe a plane with some wave textures on both side of the boat would improve that, but it’s just a demo until now, if I get a real nice looking ship behavior, you will find it here one day 
The Script for the boat below @the end of the post, atm the water.position is the waterlevel for all 4 points where the ship is pushed up, so i don’t need normals just, a float value for the difference to the water plane for this 4 points.
Where do i find the shader code that does the displacement, A view in the Shadercode reveals that the first part is doing the Highquality setting calculations. I Copied that shader Code below, And I have no clue where the displacement takes place -.-
I Would rebuild the displacement calculations in c# if I would understand the shader code ^^
v2f vert(appdata_full v)
{
v2f o;
half3 worldSpaceVertex = mul(_Object2World,(v.vertex)).xyz;
half3 vtxForAni = (worldSpaceVertex).xzz;
half3 nrml;
half3 offsets;
Gerstner (
offsets, nrml, v.vertex.xyz, vtxForAni, // offsets, nrml will be written
_GAmplitude, // amplitude
_GFrequency, // frequency
_GSteepness, // steepness
_GSpeed, // speed
_GDirectionAB, // direction # 1, 2
_GDirectionCD // direction # 3, 4
);
v.vertex.xyz += offsets;
// one can also use worldSpaceVertex.xz here (speed!), albeit it'll end up a little skewed
half2 tileableUv = mul(_Object2World,v.vertex).xz;
o.bumpCoords.xyzw = (tileableUv.xyxy + _Time.xxxx * _BumpDirection.xyzw) * _BumpTiling.xyzw;
o.viewInterpolator.xyz = worldSpaceVertex - _WorldSpaceCameraPos;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
ComputeScreenAndGrabPassPos(o.pos, o.screenPos, o.grabPassPos);
o.normalInterpolator.xyz = nrml;
o.viewInterpolator.w = saturate(offsets.y);
o.normalInterpolator.w = GetDistanceFadeout(o.screenPos.w, DISTANCE_SCALE);
return o;
}
half4 frag( v2f i ) : COLOR
{
half3 worldNormal = PerPixelNormal(_BumpMap, i.bumpCoords, VERTEX_WORLD_NORMAL, OVERALL_BUMP_STRENGTH);
half3 viewVector = normalize(i.viewInterpolator.xyz);
half4 distortOffset = half4(worldNormal.xz * REALTIME_TEXTURE_BUMP_STRENGTH * i.grabPassPos.z * i.normalInterpolator.w, 0, 0);
half4 screenWithOffset = i.screenPos + distortOffset;
half4 grabWithOffset = i.grabPassPos + distortOffset;
half4 rtRefractionsNoDistort = tex2Dproj(_RefractionTex, UNITY_PROJ_COORD(i.grabPassPos));
half refrFix = UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(grabWithOffset)));
half4 rtRefractions = tex2Dproj(_RefractionTex, UNITY_PROJ_COORD(grabWithOffset));
#ifdef WATER_REFLECTIVE
half4 rtReflections = tex2Dproj(_ReflectionTex, UNITY_PROJ_COORD(screenWithOffset));
#endif
#ifdef WATER_EDGEBLEND_ON
if (LinearEyeDepth(refrFix) < i.screenPos.z)
rtRefractions = rtRefractionsNoDistort;
#endif
half3 reflectVector = normalize(reflect(viewVector, worldNormal));
half3 h = normalize ((_WorldLightDir.xyz) + viewVector.xyz);
float nh = max (0, dot (worldNormal, -h));
float spec = max(0.0,pow (nh, _Shininess));
half4 edgeBlendFactors = half4(1.0, 0.0, 0.0, 0.0);
#ifdef WATER_EDGEBLEND_ON
half depth = UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos)));
depth = LinearEyeDepth(depth);
edgeBlendFactors = saturate(_InvFadeParemeter * (depth-i.screenPos.w));
edgeBlendFactors.y = 1.0-edgeBlendFactors.y;
#endif
// shading for fresnel term
worldNormal.xz *= _FresnelScale;
half refl2Refr = Fresnel(viewVector, worldNormal, FRESNEL_BIAS, FRESNEL_POWER);
// base, depth reflection colors
half4 baseColor = ExtinctColor (_BaseColor, i.viewInterpolator.w * _InvFadeParemeter.w);
#ifdef WATER_REFLECTIVE
half4 reflectionColor = lerp (rtReflections,_ReflectionColor,_ReflectionColor.a);
#else
half4 reflectionColor = _ReflectionColor;
#endif
baseColor = lerp (lerp (rtRefractions, baseColor, baseColor.a), reflectionColor, refl2Refr);
baseColor = baseColor + spec * _SpecularColor;
// handle foam
half4 foam = Foam(_ShoreTex, i.bumpCoords * 2.0);
baseColor.rgb += foam.rgb * _Foam.x * (edgeBlendFactors.y + saturate(i.viewInterpolator.w - _Foam.y));
baseColor.a = edgeBlendFactors.x;
return baseColor;
}
The Ship code with the throttle influencing the Particle size.
using UnityEngine;
public class RC_SHip : MonoBehaviour {
public Transform water;
public Transform bowSplash;
public Transform engineSplash;
public ParticleEmitter MotorEmitter;
private Rigidbody MyRigidbody;
// Use this for initialization
void Start () {
MyRigidbody = GetComponent<Rigidbody>();
MyRigidbody.useGravity = true;
}
void FixedUpdate() {
float[] forceValue = new float[4];
forceValue[0] = Mathf.Max(((transform.position + 2*transform.forward + transform.right).y - water.position.y-0.2f)*-5f + 0.5f*Mathf.Sin(Time.time*5)+2.7f, 0);
forceValue[1] = Mathf.Max(((transform.position + 2*transform.forward - transform.right).y - water.position.y-0.2f)*-5f + 0.5f*Mathf.Sin(Time.time*5)+2.7f, 0);
forceValue[2] = Mathf.Max(((transform.position - 2*transform.forward + transform.right).y - water.position.y-0.2f)*-5f + 0.5f*Mathf.Sin(Time.time*5)+2.7f, 0);
forceValue[3] = Mathf.Max(((transform.position - 2*transform.forward - transform.right).y - water.position.y-0.2f)*-5f + 0.5f*Mathf.Sin(Time.time*5)+2.7f, 0);
MyRigidbody.AddForceAtPosition(Vector3.up*forceValue[0], (transform.position + 2*transform.forward + transform.right));
MyRigidbody.AddForceAtPosition(Vector3.up*forceValue[1], (transform.position + 2*transform.forward - transform.right));
MyRigidbody.AddForceAtPosition(Vector3.up*forceValue[2], (transform.position - 2*transform.forward + transform.right));
MyRigidbody.AddForceAtPosition(Vector3.up*forceValue[3], (transform.position - 2*transform.forward - transform.right));
bowSplash.position = new Vector3(bowSplash.position.x, 0.05f, bowSplash.position.z);
engineSplash.position = new Vector3(engineSplash.position.x, 0.05f, engineSplash.position.z);
float throttle = Input.GetAxis("Vertical");
if(Mathf.Abs(throttle) > 0.1) {
MotorEmitter.emit = true;
MotorEmitter.minSize = Mathf.Abs(throttle*1.5f);
MotorEmitter.maxSize = Mathf.Abs(throttle*2.0f);
}else{
MotorEmitter.emit = false;
}
MyRigidbody.AddForceAtPosition(transform.forward*throttle*7 - throttle*transform.right*Input.GetAxis("Horizontal")*3, transform.position - transform.forward*3-transform.up*0.5f);
}
}