Queries#

Usage#

All providers which can be queried use a similar interface.

The providers built into our system perform queries asynchronously; queries are offloaded to the GPU or to spare CPU cores for processing. This has a few non-trivial impacts on how the query API must be used.

Firstly, queries need to be registered with an ID so that the results can be tracked and retrieved later. This ID needs to be globally unique, and therefore should be acquired by calling GetHashCode() on an object/component which will be guaranteed to be unique. A primary reason why sample helpers are useful is that they are objects themselves and therefore can pass their own ID, hiding this complexity from the user.

Secondly, even if only a one-time query is needed, the query function should be called every frame until it indicates that the results were successfully retrieved. Querying a second time using the same ID will stomp over the last query points. See SamplingHelpers.cs for example usage - its Sample() function should be called until it returns true. Posting the query and polling for its result are done through the same function.

Finally due to the above properties, the number of query points posted from a particular owner should be kept consistent across frames. The helper classes always submit a fixed number of points this frame, so satisfy this criteria.

Important

For each unique query ID:

  • Queries should only be made once per frame.

  • Number of query points posted should be kept consistent across frames.

Collision Shape#

The system has a few paths for computing information about the water surface such as height, displacement, flow and surface velocity. These paths are covered in the following subsections, and are configured on the Water Renderer using the Collision Source dropdown.

The system supports sampling collision at different resolutions. The query functions have a parameter Min Spatial Length which is used to indicate how much detail is desired. Wavelengths smaller than half of this min spatial length will be excluded from consideration.

To simplify the code required to get the water height or other data from C#, the SampleHeightHelper is provided.

Research

We use a technique called Fixed Point Iteration to calculate the water height. We gave a talk at GDC about this technique which may be useful to learn more: https://www.gdcvault.com/play/1023011/Fixed-Point-Iteration-A-Simple.

The Collision Area Visualizer debug component is useful for visualising the collision shape for comparison against the render surface. It draws debug line crosses in the Scene View around the position of the component.

GPU Queries#

This is the default and recommended choice for when a GPU is present. Query positions are uploaded to a compute shader which then samples the water data and returns the desired results. The result of the query accurately tracks the height of the surface, including all wave components and depth caches and other Crest features.

CPU Queries#

On platforms where a GPU is not present, or for authoritative servers, CPU queries are available.

Please see CPU Queries.

Flow#

Flow can also be queried which is done on the GPU only. Query against the Flow Provider or use the SampleFlowHelper.