Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Games WaveWorks 2 in Unity

Discussion in 'Projects In Progress' started by snacktime, Mar 5, 2021.

  1. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    I was thinking of releasing this as open source. And I hit an issue that is stumping me so I thought well why not try to take advantage here. If an actual domain expert is willing to put in some time to help me solve this, I'll commit to open sourcing it. FYI if you know what the problem is just by looking at it and turn out to be right, that counts. But I'm assuming I'll need to package this all up and send it to someone directly so they can have the complete code. So I need to pick just one person for that scenario.


    So to start here is the issue, it's fairly obvious something is being inverted and possibly stretched here. Although verifying against the reference and looking at the wireframes, the meshing and heights all look correct.

    upload_2021-3-5_13-29-58.png


    WW internal data is left handed Z up and their demo renders with GLFW3. So there is some coordinate translation I had to do. Plus it's native meshing works off of transforming all the vertices in the vertex shader. Plus there is a lot of packing uvs into float4 and then unpacking and using against world coordinates. So there could be some incorrect swizzling going on.

    But... I also have a version using a different meshing system where it looks mostly correct. It's the same core ww logic as all the sampling is abstracted out. So that tells me a lot is probably right. And WW uses world positions for everything here. So I'm thinking/hoping that I'm missing something quite simple.

    The WW meshing is they hand you single indice/vertice buffers when you create the quad tree, which contains 16 unique patch meshes. Per frame you query the quad tree with camera matrices and get back indexes into the buffers and a scale/offset. So culling is baked in here. It was designed to work with draw indexed, and I'm using DrawMeshInstanced which is the closest equivalent in Unity. I'm also using NativeArray's so I can just pass pointers directly to native and have it fill out the nodes there. It's all very performant although some final optimizations on the Unity side to be done (fill out DrawMeshInstanced matrices in jobs). I need to get this rendering issue fixed before final polishing.

    This is in HDRP. The hlsl to do all the displacement and sampling for normals/gradients/etc is all separated out into helpers, so it's easily adaptable to any render pipeline.


    I did most of the integration using Better Shaders. And then moved to a low level vert/frag setup for the final frag shader. As the actual shading is all world position based and calculating light/reflections/specular/fresnel directly. I'm doing custom sky/scattering anyways so this low level approach fits my context well. If you wanted to really integrate this well into the normal HDRP shading flow I strongly suggest Better Shaders. Mainly due to all the sampling a Shader Graph port would be some work.

    WW supports DX11/12 and Vulkan. My native plugin hardcodes DX11 resource types. It also uses a low level DX11 CopyResource due to some limitations with Unity's api in using external texture2d arrays. But making it work with DX12/Vulkan would I think be fairly straight forward.

    I might end up open sourcing this even if I don't get help. But helping me solve this will ensure it happens, as just working with someone will force me to package it up cleanly.

    Also for those that don't know and most won't unless they have worked with FFT water. Every open source solution you will find out there is pure crap in terms of being usable in an actual game. The best I found did 200+ compute dispatches per frame. FFT water takes some very specific optimization techniques like butterfly and others and is non trivial. And unless you do those it's worthless. That's just the bar now days. Plus good LOD is non trivial.

    Nvidia's implementation is amazingly performant. The actual FFT generation is barely a blip on the gpu. The heavy work is all in the shading. Which also means it's easily tunable performance wise. The quad tree system also allows full control over mesh density and has as far as I can tell infinite LOD levels. The default is 15. It's a concentric geomorphed LOD that is based on distance from camera.
     
  2. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    This is a screen where I'm using different meshing. It's actually the Crest water system meshing I extracted. The shading though uses the exact same WW includes/queries for obtaining normals and displacement. How it applies them is different. It looks mostly correct although it's hard to know 100% with such simple shading and how noisy the water is.

    upload_2021-3-5_15-46-2.png
     
  3. Bartolomeus755

    Bartolomeus755

    Joined:
    Jun 20, 2013
    Posts:
    283
    It would be awesome to have Waveworks 2 for Unity, unfortunately I'm not able to help.... ;)
     
  4. la-gandyra

    la-gandyra

    Joined:
    Apr 8, 2021
    Posts:
    2
    Hey, so I've recently started writing a ww integration too. And I wanted to ask how did you do the extraction of the data because I have the feeling that returned arrays from c++ to Unity aren't correct at least how I do it. And since I'm new to Unity I don't really know what to do with all the data on the Unity side. So I would really appreciate it if you could maybe point me in the right direction regarding these issues.
     
  5. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Textures are tricky. Texture2D you can bind to the ww texture via CreateExternalTexture. Texture2dArray you can't. I passed the array pointers to C via GetNativeTexturePtr() and then every frame copied the ww arrays using Direct3D CopyResource which is a fast gpu copy.

    I can share approaches but this integration requires knowing a pretty big surface area of Unity and that's beyond giving simple pointers to. The texture handling was the only real tricky part other then converting right to left handed in all the right places, which ended up being my issue in the original post. A single bad swizzle.

    Make sure all your interop with ww happens in the render thread via a proper render plugin setup, that's important.
     
  6. la-gandyra

    la-gandyra

    Joined:
    Apr 8, 2021
    Posts:
    2
    Thank you for the input, I have made some progress and I am able to get the quadtree information to unity and draw it using drawmeshedinstanced. Now from my understanding I have to pass the other parameters I got from WaveWorks to a Shader with an instancing buffer.

    Now my Problem is that the Textures remain black after I copyied them with CopyResource. I think my Render Plugin setup is correct because I'm able to change Textures by calling UpdateSubresource and write some random values into them but I can't seem to get CopyResource to work.
     
  7. veddycent

    veddycent

    Joined:
    Jul 22, 2013
    Posts:
    107
    This is very interesting and would be fantastic if you manage to get it integrated!
    Have you managed to make anymore progress?

    Just like @Bartolomeus I'm always intrigued with realtime ocean simulations :D
     
    Bartolomeus755 likes this.
  8. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Yes I got it working. The shading is unlit, completely custom lighting a port of their demo shaders basically. You can't actually replicate the shading in HDRP/URP lit, the lighting models just don't support what is needed for proper refraction/reflection. So proper fully integrated shading would be a significant amount of work.

    Attenuation to land masses is impossible to do well. You can scale all the WW output easily enough but that's basically the height is all, you can't make waves bunch up near shore. Not a deal breaker for some games but it's not great.

    So it's not that usable as is, and I think not that interesting for a modern game. There is one game I know of using it, Atlas. And since Sea of Thieves the bar has gone up again, so I don't see much of a future for WW. Performant FFT is really the only problem WW is solving well, and they do it really really well. But everything else about it is sort of meh for a closed source solution.
     
  9. veddycent

    veddycent

    Joined:
    Jul 22, 2013
    Posts:
    107
    Nice!
    It would be cool to play around with it so if you feel like sharing that would be appreciated but no pressure :)