Water 4 Displacement

I have a Problem getting the Displacement for a Point with the Water 4.

What I want is, to get the displacement amount y for a certain point xz to get a floating object.

I find a GerstnerDisplace : Displace script whitch inherits from Displace and does not add anything, so I dont se any use in that anyway, or where do I miss the point of this script?
The Displace script chances in onEnable() or onDisable() 2 Keywords in the Shader
and functions that got commented out of the code that would’nt return very usefull results beside of 0, and (1,1,1).

Now Beside the question of how can this GerstnerDisplace Script show anything in the EditorWindow when it is empty, whitch is kind of a mystery to me, Shader code in generall is the same mystery, so I didn’t find much usefull there.


Which leads me to the important question, how can i get the Displacement for a certain point on the water plane?
Can I acces shader values and get the needed value from there, or how should I proceed?

The whole floating thing with a volume under water creates a force up (buoyancy), and so on should be clear.

Thanks for any Solution or any Idea/Help were to find one :wink:
Gamma

Here is a little demo that shows the inteded functionality: http://www.3d-live.ch/ship/

The Up/down movement of the RC ship here is just a Sinus curve.
If someone has an idea how to get the Displacement from the waves, would be great to replace the sinus curve values with real height values from the waves.

If someone has an clue about this shader stuff, I’would be happy to get some help :wink:

What you need is for UT to add a “get height” function in Water4. It’s available in Water3 and the community ocean shader (http://www.unifycommunity.com/wiki/index.php?title=Ocean_Shader_Project).

Pretty much what bigkahuna said… Water4 removed scripting functionality and Unity team has basically said it’s only good for eye candy. The only way I can see using the Water4 asset is to try and replicate the shader code in your boat controller or at least a few of the wave functions to try and get a “close” representation of the movement of the water. Or make the water less pronounced and fake the boat movement kind of like what you already have in your demo.

Your water wake effect by the way is beautiful! If you would be willing to share I’d be very grateful! I still have not lost hope for using the water4 asset myself personally as it runs very efficiently and would look good in my case. Unfortunately what I am simulating is large galleon type ships which don’t bob as much as roll slowly with the ocean waves. I plan on trying to simulate the curves on the controller like I mentioned above for the largest waves and then just ignore the chop but I have not had time as of yet to work on it in detail. If I get anything done I’ll let you know.

I didn’t see that, yes it is very nice! If you don’t mind my asking, how did you do it? I’ve hacked a boat wake in the community ocean shader but I think you’re is nicer.

@rutecht - If you want to simulate heaving / rolling of a boat you’ll need the tangent / normal of the water surface in addition to the height. Those are all available in both Water3 and the community ocean shader. I bugged UT for it in Water3 during that beta test but didn’t think to ask them if they kept it in water4… unfortunately they didn’t. I’m still sticking with the community ocean but do agree that Water4 is much nicer than Water3 and seems to run very well. Perhaps with “Water5” they’ll give us everything we want… :wink:

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 :wink:

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);
	}
}

The guy you need to ask is Ole, the UT developer who wrote both Water3 and Water4. I don’t see his name listed on the “People” page of unity3d.com, but he’s the fellow who I spoke with when they were developing Water3. I’d send an email to support@ to his attention and be sure to clearly note that your issue is regarding Water4. That with a bit of luck and you’ll hopefully get a reply.

Thank you, I will stop annoying everyone here, and target him with my problem.
If I get or find a solution, I will revive the thread

@bigkahuna

I actually had a working hack of water3 that took care of my ship on the waves and controller etc… all finished. When I upgraded to 3.4 it broke my code… I figured instead of trying to make it work with water3 again I’d just upgrade my code to water4 at which time I found they removed the code that made my whole project possible. So right now I can either A. fix my code to work with 3, B. hope and pray that 3.4.1 fixes our complaints about the water4, C. make a hack of water4 like I did with 3 to make it work which 3.5 will probably break, or finally D. just put off the rolling motion aspect of my game till Im close to finish and use / hack a usable solution of whatever they have released at that time…

@Gamma

Thank you so much for posting your wake code… I have played around with the emitters too but working with particles is more of an art than a science and yours looks so nice I really appreciate it!

I’d say go with A, D, or “E” (which would be to use the community ocean shader). I’ve been using the community ocean shader in 3.4 and it works fine. I had to make a number of changes to get it to work (and have no idea what I did to fix it) but whatever I did was fairly minor. Ole, the UT developer who wrote Water3 and Water4, is aware of your issue but I have no timeline on when it might be fixed/added. Personally, I’m more impressed with Water4 than Water3 on some levels, but not on others. I still think the community water shader is miles ahead in visual realism for ocean type water.

Does anyone know if there is a GetHeight function yet in Water4?

1 Like

Hi there –

This thread is now 4 years old – but I could not find a solution anywhere else – so I post what I came up with here. I put it into the Unitys GerstnerDisplace script – but the code can be used everywhere – make sure to provide the used Water4 material instance though.

using System;
using UnityEngine;

namespace UnityStandardAssets.Water
{
    [ExecuteInEditMode]
    [RequireComponent(typeof(WaterBase))]
    public class GerstnerDisplace : Displace
    {
        protected Material m_Water4;
        protected static Vector4   s_GAmplitude;       //"Wave Amplitude"
        protected static Vector4   s_GFrequency;       //"Wave Frequency"
        protected static Vector4   s_GSteepness;       //"Wave Steepness"
        protected static Vector4   s_GSpeed;           //"Wave Speed"
        protected static Vector4   s_GDirectionAB;     //"Wave Direction"
        protected static Vector4   s_GDirectionCD;     //"Wave Direction"

        protected void Start()
        {
            RefreshGerstnerSettings();
        }

        [ContextMenu("Refresh Gerstner Wave Settings")]
        public void RefreshGerstnerSettings()
        {
            if ( m_Water4 == null )
            {
                m_Water4 = GetComponent<WaterBase>().sharedMaterial;
            }

            if ( m_Water4 != null )
            {
                s_GAmplitude = m_Water4.GetVector("_GAmplitude");
                s_GFrequency = m_Water4.GetVector("_GFrequency");
                s_GSteepness = m_Water4.GetVector("_GSteepness");
                s_GSpeed = m_Water4.GetVector("_GSpeed");
                s_GDirectionAB = m_Water4.GetVector("_GDirectionAB");
                s_GDirectionCD = m_Water4.GetVector("_GDirectionCD");
            }
        }

        public struct DirPoint
        {
            public Vector3 position;
            public Vector3 normal;
            public DirPoint(Vector3 pos, Vector3 norm)
            {
                position = pos;
                normal = norm;
            }
        }

        public DirPoint GetDisplacmentAtPosition(Vector3 pos)
        {
            Vector4 AB = new Vector4(
            s_GSteepness.x * s_GAmplitude.x * s_GDirectionAB.x,
            s_GSteepness.x * s_GAmplitude.x * s_GDirectionAB.y,
            s_GSteepness.y * s_GAmplitude.y * s_GDirectionAB.z,
            s_GSteepness.y * s_GAmplitude.y * s_GDirectionAB.w);

            Vector4 CD = new Vector4(
            s_GSteepness.z * s_GAmplitude.z * s_GDirectionCD.x,
            s_GSteepness.z * s_GAmplitude.z * s_GDirectionCD.y,
            s_GSteepness.w * s_GAmplitude.w * s_GDirectionCD.z,
            s_GSteepness.w * s_GAmplitude.w * s_GDirectionCD.w);


            Vector4 dotABCD = new Vector4(
            s_GFrequency.x * (s_GDirectionAB.x * pos.x + s_GDirectionAB.y * pos.z), //dotABxy
            s_GFrequency.y * (s_GDirectionAB.z * pos.x + s_GDirectionAB.w * pos.z), //dotABzw
            s_GFrequency.z * (s_GDirectionCD.x * pos.x + s_GDirectionCD.y * pos.z), //dotCDxy
            s_GFrequency.w * (s_GDirectionCD.z * pos.x + s_GDirectionCD.w * pos.z)  //dotCDzw
            );

            float time;
#if UNITY_EDITOR
            time = (float)UnityEditor.EditorApplication.timeSinceStartup;
#else
        time = Time.time;
#endif
            Vector4 gTime = s_GSpeed * time;

            //half4 COS = cos (dotABCD + TIME);
            Vector4 COS = new Vector4(
            Mathf.Cos(dotABCD.x + gTime.x ),
            Mathf.Cos(dotABCD.y + gTime.y ),
            Mathf.Cos(dotABCD.z + gTime.z ),
            Mathf.Cos(dotABCD.w + gTime.w )
            );

            //half4 SIN = sin (dotABCD + TIME);
            Vector4 SIN = new Vector4(
            Mathf.Sin(dotABCD.x + gTime.x ),
            Mathf.Sin(dotABCD.y + gTime.y ),
            Mathf.Sin(dotABCD.z + gTime.z ),
            Mathf.Sin(dotABCD.w + gTime.w )

            );

            float offsetX = COS.x * AB.x + COS.y * AB.z + COS.z * CD.x + COS.w * CD.z;
            float offsetZ = COS.x * AB.y + COS.y * AB.w + COS.z * CD.y + COS.w * CD.w;
            pos.x += offsetX;
            pos.z += offsetZ;
            pos.y = SIN.x * s_GAmplitude.x + SIN.y * s_GAmplitude.y + SIN.z * s_GAmplitude.z + SIN.w * s_GAmplitude.w;

            Vector3 normal = new Vector3(-offsetX, 2f, -offsetZ);

            return new DirPoint(pos, normal);
        }

    }
}

There are some issues however…

I did not find a way to get the height y directly above a position x z – but the displacement from this point. Gerstner-waves translate also in x z (controlled by the steepness) – and at this time I was not able to get the wave height directly above a position – what I got is the displacement of the given position. – I’m not even sure if this can be done in a reasonable performant way.

2559062--178165--GerstnerWaveDisplacementExample.jpg

In this Picture – the magenta Ray is the up-vector starting at the queried position. The yellow cross is the displaced position and the green ray is the not normalized normal of it.

For me this is of no practical use – I need the height directly above a given position – but maybe this helps someone else – for a simple buoyancy fake script this might be sufficient.

1 Like

old thread but still… anybody wondering about the same, the displacement gets done in the WaterInclude.cginc file.