wave-harmonic / crest

A class-leading water system implemented in Unity
MIT License
3.5k stars 478 forks source link

Wave height queries appear to be dependent on camera position #140

Closed skaughtx0r closed 5 years ago

skaughtx0r commented 5 years ago

I was playing around with switching over from UWS to Crest, but I noticed there's an issue with the wave height queries. It seems like its very dependent on the camera position. See the video, I'm just changing camera angles using Cinemachine and the water seems to change dramatically affecting the physics on the boat.

https://www.youtube.com/watch?v=OIUj39MqQ34

I'm using Crest on master branch.

Am I doing something wrong or is this a bug?

Also with the very low FOV on the TV camera, the water becomes very flat.

huwb commented 5 years ago

Hey, cool video!

The ocean has a number of lods that are centered around the viewpoint. See the LOD data section here: https://github.com/huwb/crest-oceanrender/blob/master/TECHNOLOGY.md .

I think in this situation i would not sample the highest detail lods for the physics, as they will only cover an area near the camera. If you are using BoatAlignNormal then increase the Boat Width param. This is described in the Collision Shape for Physics section (of the above doc).

If you need the physics to be truly independent of viewpoint, you could compute the collision directly from the waves instead of using the LOD data, see the Gerstner Waves CPU section.

huwb commented 5 years ago

Oh the very low FOV thing - i had never thought about that before. I guess this is an issue for all distance based LODing. One thing you might try is to make the ocean detail follow the boat instead of the camera, maybe at certain times. You can do this by setting the Viewpoint on the ocean renderer to be the boat.

Or you can brute force the solution - just jack up the quality params described in Ocean Construction Parameters in https://github.com/huwb/crest-oceanrender until the problems go away! (but do test performance!)

Let me know how you get on, and I'd love to see more of your stuff in the future if you ever feel like posting!

skaughtx0r commented 5 years ago

Hey huwb, thanks for the quick response.

I tried setting it to follow the boat which did work, but the problem with that is that it's a multiplayer racing game and I'm running local simulations of all the boats for prediction, not just the one in view.

I also run a dedicated server that has no cameras and no graphics, so not sure if GPU readback will even work with that. It's in charge of simulating buoys and collisions with them.

Does the CPU wave calculation include wakes, flow, and particles? I haven't tried it yet, but I'll give that a shot next. UWS did it's wave height computations on the CPU, but it did not include boat wakes.

huwb commented 5 years ago

I naively would have thought running a sim for prediction might be ok enough even if the water is smoother or flatter than it should be - but maybe not.

I'm not sure either about the server running gpu sims, i guess not!

No the cpu only includes the gerstner waves, as you probably suspected. More could be added but im not sure how efficiently.

On efficiency, i have started experimenting with a more efficient way to execute CPU height queries, see my last comment on #127 .

skaughtx0r commented 5 years ago

It might be ok, if I change the Viewpoint to the boat that the camera is targeting and make the server use CPU. I will need to play with it a bit. I did have to modify the Viewpoint property on OceanRenderer, it needs to have a setter, so I can update it with the current camera target.

I tried the brute force method you mentioned, but changing the number of LODs seems to have no effect for me. I set it to 50 and it looks the same as 5.

5 LODs: crest5lods

50 LODs: crest50lods

huwb commented 5 years ago

Increasing the lods will increase the horizontal range of the surface (select the ocean in teh sceneview to inspect), but will not increase the detail/vert density. I think you are looking for the Base Vert Density value.

The Ocean Construction Parameters section of the readme was not really clear on this - just gave it a rewrite, hopefully it makes more sense now.

huwb commented 5 years ago

Closing due to inactivity / to keep issues ticking over. Hope you got something you are happy with? If you werent able to get a good result I'd be curious to hear in case theres anything i can point you towards, or in case there are improvements i could make in the future.

skaughtx0r commented 5 years ago

Hey huwb, I played around with using the CPU wave height queries, but it used up way too much CPU time. I may have to wait until it gets moved to job system (as I saw mentioned in another post). Currently I'm using UWS and it does all the FFT and wave height queries in a separate thread which works quite well. I'm probably doing close to 1000 height queries when several boats are on the water + buoys + other "floating" objects (yachts, docks, etc just using height offset).

One thing that might work for wakes, not sure if possible. Could CPU be used for wave heights and only use GPU readback for wakes and other localized effects.

I think the dedicated server would have to use CPU only, since there is no GPU.

Also, I was playing around with the wake generator and was having issues with it affecting my boats physics where the particles were being spawned by the propeller at the very back of the boat. It was causing the boat to bounce erratically. Is there some way to make the wake not affect the boat that is spawning it, or have some time delay? The boats can go close to 200 mph, so I was having some trouble keeping the wake spawn turning into a large spike.

huwb commented 5 years ago

Thanks for the notes.

Can imagine that will be too expensive. Crest allows you to add loads of gerstner waves which are expensive to compute on the CPU.

Moving it onto a thread would be doable, or jobs. The former would probably mean more backwards compatibility but the latter is sexier and probably significantly faster due to burst compiler goodness. I'll start a new issue to track any developments here. I'm not sure when i'll have time to look at it, but i'm interested to look at it so theres a will at least!

I'm not sure what that CPU/GPU breakdown for wakes vs waves gives us? I did not understand.

Do you mean the dynamic wake is affecting the floating physics and causing it to jump around? Yeah i've run into similar things and managed to work around it by offsetting where the wake is generated and tweaking/hacking. Is it the case that you don't want the dynamic/local waves from wakes to affect the buoyancy at all?

skaughtx0r commented 5 years ago

I'm trying to keep up with Unity updates while developing this game, will probably try moving to 2018.3 soon, so I'm all for using jobs over normal threads. I've been meaning to look into using the job system myself also.

From what I could tell the CPU wave query gives you accurate heights regardless of where the ocean viewpoint is set (for objects far away from the camera). So I was thinking that could be used for waves, but use the GPU readback for boat wakes and other dynamic effects. This may still be over kill as I haven't done any real game play tests yet. The main thing I worry about is watching recorded replays, because I store position / rotation of all the boats on the course during races, then you can go back and watch replay and change which boat you're following.

Yeah, dynamic wake affects the physics causing boat to jump quite a bit. I may just need to play with offsetting the wake further backwards as the boat speed increases. I do want the wakes to affect the boats, it just doesnt feel right when the wake is affecting the boat you're driving pushing the back end up. Maybe another possibility is to make it so when the wake is spawned, it doesn't start at the max amplitude, instead it first grows over time before it reaches that amplitude, then starts to dissipate?

Here's a quick video I made testing wakes https://youtu.be/L25fApxXU9A

huwb commented 5 years ago

I am experimenting with moving gerstner queries to jobs + burst. the results so far seem to be very compelling - in my last test i'm doing 500 queries against 6 wave components and the job cost is around 0.05ms for most of the jobs, 0.08ms max, so the wall clock running time is less than 0.1ms. Also this the jobs run multi threaded so if there are spare cores it will basically run for "free". Crazy stuff.

The full implementation will need to do quite a lot more work than this early test (many more waves evaluations), but this looks like a very good start. It will take a fair bit of work to fully integrate it. Using jobs makes everything more complicated in terms of scheduling work and working out how data should flow through updates. But the results seem to be worth making the effort.

I'm not sure how well this stuff can sit alongside whats there already, in terms of being able to turn it on or off. It doesnt help that it relies on packages that are still in preview which i have mixed feelings about depending on. In any case I'll aim to eventually have something that can be pushed back to master but if I don't get that far i'll either get it pushed to a branch, or in the worst case publish a patch.

huwb commented 5 years ago

Cool video btw

Yes the cpu will give accurate queries, but be aware that if the visual mesh is lod'd down a lot it may not match the cpu shape! specifically if the cpu queries includes small wavelengths, these may not be present in the visual mesh, and you may notice disparities. the boat width param mentioned above can be used to filter out these high frequencies.

regarding other dynamic effects that are in crest right now - the boat wakes are entirely gpu and no readback is required. i hope to create particles at wave crests which does require cpu readback at the moment (#93), but after seeing a bunch of tweets about gpu particle systems in unity im wondering if that could be entirely gpu as well.

for a replay you'll want to make sure the rigidbodies have the right velocity, then hopefully most of the dynamic effects should just work, unless im missing something.

are you using the object water interaction script to generate the wake (like the example boats?). this script is a bit of a hack and was definitely not designed to work on high speed boats. you probably want it to lie a fair bit ahead of your boat (so that the dynamic waves have a chance to move) (Velocity Position Offset) and you may want to elongate the shape a lot so that it overlaps across frames (perhaps FactorParallel on the material on this object). When i'm debugging this stuff i turn on wireframe in the scene view, and then enable the MeshRenderer on the water interaction object, so you can see where it is. Finally you may want to drastically increase gravity which will speed up the waves - perhaps try multiplying up _Gravity in UpdateDynWaves.shader as a test. You might also increase gravity for the gersnter waves, theres a control for this on the spectrum.

the alternative for the wake is to write your own - you need to write a shader that will add or remove from the x component of the dynamic waves, to push it up or down respectively. a dumb example is the RippleTest GO which has a simple geo/shader that adds an upwards force to an area of water (toggles on and off). with experimentation it might be possible to get a better wake, and/or coerce the water to do what you're looking for.

huwb commented 5 years ago

Opened a PR #157 - i think its in a good enough state to jump on if you have time. I could use additional testing and feedback before considering a merge to master.

Could we move any discussion specifically about water height queries to that PR so i have it in one place. Thanks!