diff options
| author | Jason Maskell <[email protected]> | 2016-05-09 10:39:54 +0200 |
|---|---|---|
| committer | Jason Maskell <[email protected]> | 2016-05-09 10:39:54 +0200 |
| commit | 79b3462799c28af8ba586349bd671b1b56e72353 (patch) | |
| tree | 3b06e36c390254c0dc7f3733a0d32af213d87293 /demo/doc | |
| download | waveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.tar.xz waveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.zip | |
Initial commit with PS4 and XBone stuff trimmed.
Diffstat (limited to 'demo/doc')
| -rw-r--r-- | demo/doc/ImplementationNotes.txt | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/demo/doc/ImplementationNotes.txt b/demo/doc/ImplementationNotes.txt new file mode 100644 index 0000000..c4aa25b --- /dev/null +++ b/demo/doc/ImplementationNotes.txt @@ -0,0 +1,305 @@ +// This code contains NVIDIA Confidential Information and is disclosed +// under the Mutual Non-Disclosure Agreement. +// +// Notice +// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES +// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless +// expressly authorized by NVIDIA. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved. +// +// NVIDIA Corporation and its licensors retain all intellectual property and proprietary +// rights in and to this software and related documentation and any modifications thereto. +// Any use, reproduction, disclosure or distribution of this software and related +// documentation without an express license agreement from NVIDIA Corporation is +// strictly prohibited. +// + + + +/ * + * WaveWorks 1.3 demo - explanatory implementation notes + * + */ + +The WaveWorks 1.3 demo was first shown at GTC in 2013 to demonstrate the capabilities of the +WaveWorks library. + +The demo is a 'vanilla' client of WaveWorks (in the sense that it uses a stock distribution, +with no back doors etc.), however there is interesting additional functionality implemented +in the application and layered on top of the WaveWorks library. The goal of this document is +to call out and explain the main points of interest in the additional functionality. + +Note that the source code for the demo is not normally shared outside NVIDIA, and it is possible +that elements of the app-side functionality will be incorporated as library features at some +future time, so please take extra care to protect this source from disclosure. + + + +/ * + * Hull sensors + * + */ + +Hull sensors are used for vessel physics and vessel spray. + +Conceptually, a hull sensor is a device located at some fixed point on the hull of the vessel which +is capable of reporting the displacement of the water surface at its current location. + +Hull sensors are implemented on the CPU using the readback feature in WaveWorks. + +There are two kinds of hull sensor: + +- a 'generic' hull sensor, which is located at some point on the skin of the main hull of the vessel + +- a rim sensor, which is located at the free edge of the hull, near where it meets the deck + +Generic sensors are used to report relative water depth for vessel physics, and also to detect when +the relative motion of the hull and the ocean surface might trigger the generation of spray. + +Rim sensors are used to detect when the ocean surface has over-topped the deck, which allows additional +spray to be generated to simulate the resulting extreme churn, and also to disguise the vertical wall of water +that would otherwise be revealed. + + + +/ * + * Hull sensors setup + * + */ + +Hull sensor locations are initialized in OceanHullSensors::init() from the vessel's mesh data. The +locations are initialized using jittered area-based stratified sampling, in order to ensure unbiased +sampling with minimal aliasing. + +The initialization code is somewhat tailored expediently to known properties of the vessel's mesh data. +(In a production implementation, it is expected that fine-tuning of sensor locations would be done at +authoring time as part of the asset pipeline) + +The hull sensor implementation is hard-coded to generate ~20K generic sensors and ~2K rim sensors. + +Classes of interest: OceanHullSensors, BoatMesh + + + +/ * + * Hull sensor updates + * + */ + +Conceptually, the hull sensor update pipeline is very simple: + + 1: transform sensor positions to world space and calculate world-space coords for displacement lookup + 2: query the displacements from the simulation + +However, the query step is complicated by the fact that the WaveWorks simulation is parameterized +over *undisplaced* coordinates. In other words, the displaced coordinates are calculated as follows: + + xyDisplaced = xyUndisplaced + displacement(xyUndisplaced) + +A simple re-arrangement of the above equation gives us: + + xyUndisplaced = xyDisplaced - displacement(xyUndisplaced) + +In other words: to look up the height displacement for some world-space xy location, we need to know +the equivalent undisplaced xy location from which the ocean surface was displaced. + +Within the demo, this job is done by the OceanSurfaceHeights class. OceanSurfaceHeights uses iterative +refinement to build a cache of world-space to displacement lookups over some specified region of world +space, each frame. This is done in OceanSurfaceHeights::updateHeights(). + +OceanSurfaceHeights also builds a conceptually-equivalent dataset on the GPU, so that world-space to +height lookups can be performed from inside shaders. This dataset is generated by simply rendering +a patch of ocean surface into a texture mapped onto world space, with each texel taking the value +of the xyz displacement at the equivalent world location. This is done in +OceanSurfaceHeights::updateGPUHeights(). + +Classes of interest: OceanHullSensors, OceanSurfaceHeights + + + +/ * + * Vessel physics + * + */ + +The demo uses a bespoke physics implementation which takes a few minor liberties and makes minor +simplifications in order to achieve the desired results in the most straightforward way. + +The main physics update is done in OceanVessel::updateVesselMotion(), and the high-level order of +operation is: + +1: calculate pitch, roll and displacement forces by summing pressure contributions over the wet hull +area (i.e. by sampling only from sensors with a positive head of water) + +2: calculate displacements at bow and stern, and by comparing with values from previous frame calculate +the yaw-axis shear rate of the ocean surface + +3: evolve the physics state of the vessel using pseudo-dynamics ('pseudo' because there is no coupling +between pitch/roll/yaw axes). Height is simulated using a simple buoyancy vs drag model. Roll and pitch +use additional moments due to the eccentricity of the centre of pressure relative to the centre of mass +(in the case of roll, this is the familiar righting moment). Yaw is simulated using an ad-hoc spring-mass +system + +4: update vessel matrices + +5: calculate motion of vessel-mounted camera + +6: ensure wake is kept stable with respect to nominal heading + +Classes of interest: OceanVessel + + + +/ * + * Vessel spray + * + */ + +Hull sensor results are used to calculate the likelihood of a spray particle being emitted. This is done +using a 'spray generator' per hull sensor. A spray generator can emit zero to many spray particles in any +one frame. Spray generation is updated once per frame in OceanSpray::updateSprayGenerators(). + +The implementation uses a stochastic model in order to avoid the aliasing that can arise when large +coherent particle batches are emitted simultaneously from many sensors. Each frame, each spray generator +calculates the mean number of spray particles that the generator would expect to emit over the current +frametime interval (this is in general a non-integer quantity). This expected emission count is then +used to parameterize a randomized Poission process to produce an actual integer number of particles to +be emitted from a particular generator in a particular frame. + +Generic spray generators are implemented to emit the most spray when the waterline is nearby *and* the +hull-normal component of the relative hull-water velocity is high. + +Rim generators are implemented to implement the most spray when the waterline is high above the location +of the generator. + +When generic spray is being emitted, the spray velocity is calculate as follows: + +1: the velocity of the contact line is calculated and used as the starting point for the spray velocity +calculation. The goal here is to capture the squeezing rate of a wedge of water between the ocean surface +and a falling hull. For example, the contact line in a nearly flat-to-flat interaction will move very +quickly indeed, and hence will produce high-velocity spray. + +2: a hypothetical spray direction is calculated based on the direction of the contact line and the hull +normal + +3: this hypothetical spray direction is compared by dot product with an 'nominal' spray direction up and +along the hull. The goal here is to discard longitudinal or lateral velocity components + +4: the resulting value is used to modulate the spray velocity that is calculated from the motion of the +contact line alone. + +5: finally, the actual spray direction is randomized over the wedge of space between the hull and the +ocean surface + +Rim spray is emitted from a random location between the rim spray generator and the waterline directly +above, with initial velocity randomized within limits to follow the hull motion at the moment of emission. + +Once a spray particle has been emitted, it is added to a collection of active spray particles, and these +are added to a GPU particle system once per frame using the InitSprayParticlesCS to initialize their state +on the GPU. The entire set of simulated GPU particles is evolved using SimulateSprayParticlesCS, which +handles killing of particles by lifetime or else when they fall to the ocean surface. Surviving particles +are driven by a simple wind/gravity model, with some additional acceleration added to penalise vessel +intersections. + +Classes of interest: OceanSpray + + + +/ * + * Vessel wake and spray recycling + * + */ + +The basic wake of the vessel is implemented using a simple lookup into a pair of maps relative to the +nominal (un-yaw'd) vessel location, one map supplying perturbed normals, the other foam density. + +This is augmented by a local foam map, which is used to capture and 'recycle' falling spray particles. + +Each frame, all the spray particles are rendered into this foam map by OceanSpray::renderToFoam(). +This pass uses a geometry shader - RenderParticlesToFoamGS- to efficiently reject any particles that +are not currently participating in an interaction with the ocean surface. + +Surviving particles are expanded to quads and progressively accumulated in the local foam match each +frame, to give the impression of spray smoothly and progressively building up on the ocean surface +at the landing location. + +Classes of interest: OceanSpray, OceanSurface + + + +/ * + * Vessel imprints and variable tessellation rate + * + */ + +If the ocean surface were rendered using the unmodified output from the WaveWorks simulation, it would +produce results that make the vessels appear to be full of water! In the demo, we avoid this by generating +a hull profile for each vessel which can then be sampled by the ocean surface shader to modify ocean +surface displacements in places where there would otherwise be an intersection. + +The effect of this is to create 'imprints' of each vessel in the ocean surface. This works well because +it is a good approximation to physical reality and therefore it does not suffer from any of the artefacts +or corner-cases that might affect, say, a depth-based or stencil-based alternative. + +Hull profiles are generated by rendering each vessel to a depth texture from directly above, each frame, +in order to accuratelty take account of changes in vessel attitude. This is done in +OceanVessel::renderVesselToHullProfile(). + +Hull profiles are also used to determine vessel proximity in the hull shader ('hull' meant in the DirectX +pipeline stage sense, here). Areas of the ocean under or near a vessel are tessellated more densely than +areas of open water - this has 2 benefits: 1/ gives a tighter fit between the vessel imprint and the hull +of the vessel; 2/ generates smooth intersection profiles between open-water waves and the hull (aliasing +on these intersection profiles shows up more clearly than for open-water waves). + +Classes of interest: OceanVessel, OceanSurface + + + +/ * + * Funnel smoke simulation and rendering + * + */ + +The funnel smoke comprises two interesting implementation aspects: + +1: a GPU noise-based advection scheme to give plausible shape and structure to the particles that make up the +plume of smoke. + +2: particle shadow mapping to generate self-shadowing information for the plume. The plume is lit entirely +using this self-shadowing information - there is no artistic element, other than the usual particle opacity +map. For more details, see: +https://developer.nvidia.com/sites/default/files/akamai/BAVOIL_ParticleShadowsAndCacheEfficientPost.pdf + +The design intent of the GPU particle system is for the CPU to manage the number of particles that are +active in the simulation, with the goal of expressing the simulation workload in a way that is maximally +GPU-friendly. This is done by emitting particles into the simulation at a constant rate, with new particles +replacing old particles on a FIFO basis (this is accomplished by simply wrapping the emission index +each time it runs off the end of the simulation buffer). + +The physical model for particle simulation is composed of a buoyancy term (which dimihishes gradually +over time as the plume loses its heat), and a term driven by the drag of a turbulent 'wind' velocity +field on the particle motion. The turbulent velocity field is the key to the quality of the results, +since all of the complexity and detailed structure in the plume is determined by the influence of this +field. + +We use a curl noise field for this (curl noise is a divergence-free noise field derived from some +field potential. See: http://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph2007-curlnoise.pdf). +The underlying potential field is a 4D 3-octave Perlin noise field. The fourth dimension allows +the noise field to itself evolve over time, this contributes significantly to the sense of roll +and churn in the plume. + +Finally, the particles are depth-sorted on the GPU each frame in order to give correct rendering results. + +Classes of interest: OceanSmoke |