Description

The Particle Upsampling sample uses a combination of rendering techniques to simulate a cloud of particles casting shadows on a model and a floor object. The particles are rendered into a lower-resolution offscreen surface, and then up-sampled to the screen to lower the cost of the high depth complexity.

Screenshot

APIs Used

  • GL_OES_depth_texture/GL_ARB_depth_texture
  • GL_OES_texture_half_float
  • GL_NV_framebuffer_blit
  • GL_NV_texture_border_clamp

Shared User Interface

The Graphics samples all share a common app framework and certain user interface elements, centered around the "Tweakbar" panel on the left side of the screen which lets you interactively control certain variables in each sample.

To show and hide the Tweakbar, simply click or touch the triangular button positioned in the top-left of the view.

Technical Details

The Particle Upsampling sample uses a combination of rendering techniques to simulate a cloud of particles casting shadows on a model and a floor object. The particles are rendered into a lower-resolution offscreen surface, and then up-sampled to the screen to lower the cost of the high depth complexity.

The sample makes use of the following techniques:

  • Half-resolution off-screen scene rendering with full-resolution UI rendering
  • Reduced-resolution particle rendering with cross-bilateral upsampling
  • Soft particle rendering using hardware-depth fetches
  • Particle shadows using half-angle slicing [Ikits et al. 2004]
  • Depth-prepass rendering to reduce overdraw

This sample uses the following extensions, to enable functionalities that may not be available in base OpenGL or GLES:

  • GL_OES_depth_texture (or GL_ARB_depth_texture) is used to access the raw values of the 16-bit hardware depth buffer, for rendering soft particles (performing a soft depth test in the particle's fragment shader), and for upsampling the particle with a depth-aware filter.
  • GL_OES_texture_half_float is used to optionally render the particles to FP16 color buffers (instead of 8-bit-per-channel by default), for both the light buffer pass and the eye-rendering pass. Using FP16 precision for the particle blending reduces quantization artifacts which are especially noticeable when moving the camera.
  • GL_EXT_framebuffer_blit is used to perform a bilinear upsampling of the half-resolution final scene colors to the screen resolution, as well as optionally to perform a point-filtered downsampling of the scene depths to the particle's resolution.
  • GL_ARB_texture_border_clamp is used for the light-buffer fetches in the opaqueColor fragment shader, to get the pixels outside the light buffer to be fully lit.

Rendering Process

The high-level rendering loop is in SceneRendering.cpp, in SceneRenderer::renderFrame().

  1. The particles are depth-sorted along the half-angle vector (midway between the light direction and the view direction). This is done using a CPU radix sort. In this SDK sample, the particle's vertices are assumed to be static and are placed in a static Vertex Buffer Object. The depth-sorted particle indices are placed in a dynamic Element Buffer Object and updated every frame, using a double-buffering scheme to avoid blocking the rendering thread when updating the buffer.

  2. A reduced-resolution depth buffer is generated, storing the depths of the opaque geometry in the scene for the particles to be depth-tested against later on.

    Note: If "Z Pre-Pass" is enabled, the opaque geometry is first drawn to a full-resolution depth buffer (depth pre-pass) and then downsampled to reduced resolution. Otherwise, if "Z Pre-Pass" is disabled, the opaque geometry is directly drawn to the reduced-resolution depth buffer.

  3. The sorted particles are rendered in batches either front-to-back or back-to-front depending on the relative orientations of the view vector and the light vector. For each batch, the particles of this batch are first blended to the light buffer and then blended to the reduced-resolution output buffer, fetching the light buffer. The precision of these 2 buffers can be toggled between 8-bit and 16-bit per channel using the "Use FP16" button in the GUI.

  4. The opaque geometry is drawn in full-resolution to the full-resolution scene color buffer, fetching the light buffer to receive shadows from the particles. If "Z Pre-Pass" is enabled, then the full-resolution depth buffer from step 2 is used to speed up this pass.

  5. Finally, the scene color buffer is upsampled to the display resolution with a simple bilinear texture fetch.

Acknowledgments

This SDK sample is essentially a port of Simon Green's OpenCL "smokeParticles" demo with a static particle system.

See Also