Author: eilemann@gmail.com
State: Design
Overview
This features adds support for a new type of decomposition and recomposition, whereby each contributing channel renders one or multiple subsamples for full-scene anti-aliasing (FSAA) or depth-of-field (DOF).
Applications might already do multi-pass software FSAA/DOF, either during rendering or when the application is idle. Equalizer does not yet have a notion of idle/non-idle rendering.
Design
The application will do the adding of the frustum jitter, since it is the one which knows how many FSAA and/or DOF samples are desired. Therefore it needs to know in Channel::frameDraw which sample out of how many it should render.
The default implementation of Channel::applyFrustum will use the subpixel sample description to compute an FSAA jitter using a pre-defined lookup table. It will add this jitter to the frustum supplied by getFrustum.
Applications which have their own SWAA settings will use the subpixel sample description to calculate how many passes with which samples have to be rendered, e.g., if it desires to render 16 samples on a 4-time decomposition, the application will render 4 passes out of a 16-value jitter lookup table on each channel.
It is the application's responsibility to provide a blended result of the sub-passes on each channel. This should not be an overhead, since the application could already compute the accumulation and averaging before.
Compositing
API
vmml::Vector2f Channel::getJitter() const; vmml::Vector2i Channel::getSubpixel() const;
File Format
compound
{
subpixel [ index size ]
}
Implementation
Modify eqPly to do idle SWAA:
EqPly
static const uint32_t sampleSize
FrameData
uint32_t _idleStep
bool _idleMode
Channel
FBO* _accumBuffer
uint32_t _primeNumberTable
Config::startFrame
if view is idle
idleMode = true
idleStep++
else
idleMode = false
commit frame data
Channel::frameViewFinish
frameAssemble is done and back buffer is ready
if view is idle
if first idle step
reset accum buffer
accumulate back buffer to accum buffer
compute average in back buffer
Channel::applyFrustum
frustum = getFrustum()
jitter = getJitter();
frustum += jitter;
glFrustum( ... );
Compositor?
Channel::_lookupPrimeNumberTable( channel ID )
Channel::_generateFloatRand( begin, end )
Channel::_computeJitterStep
subset_size = ( sample_size * sample_size ) / nb_channels
idx = ( idle_step * getPrimeNumber()) % subset_size
global_jitter = ( id_channel * subset_size ) + idx
Channel::_computeJitter
Compute normalized jitter area (idle step, channel index)
Compute pixel size on near plane (frustum)
Compute random sample position in normalized coordinates
jitter = jitter area * pixel size * random position
Attn: Floating point rounding errors!
--------------------------------------------------
Current idle AA in Eq application:
Channel::frameAssemble()
assemble input frames into back buffer
if view is idle
if first idle step
reset accum buffer
accumulate back buffer to accum buffer
compute average in back buffer
Channel::frameDraw()
if view is idle
get idle step # and jitter frustum
render
Idle AA with AA compounds:
Channel::frameAssemble
if first idle step
reset accum buffer
if has more than one jitter step or view is idle
for each jitter step in input frames
assemble input frames with jitter step in back buffer
accumulate back buffer in accum buffer
++n
compute average in back buffer
increase application idle steps done by n
Channel::frameDraw()
jitter step = f(application idle step, Channel jitter param)
jitter step = idle_step * jitter_grp_size + jitter_offset
render
Issues
1. Do we need a one-dimensional or two-dimensional subpixel description for each source channel?
This depends on Q2. My feeling is a one-dimensional attribute is easier.
2. How do I compute my current jitter area?
The number of jitter areas, i.e, the number of FSAA or DOF samples, is an application parameter. The current jitter area within each Channel::frameDraw is a function of the current idle step and the channel's subpixel description.
Open Issue: the function itself. The jitter values for all channels in the first pass should be evenly distributed over the total subpixel grid.
Idea: Divide the sample grid into the number of channels to get a subset of pixels for each channel. For each pass, compute (pass_number * rnd_prime_number) % size to get kind of a randomized distribution. The size parameter is the size of the pixel subset for the current channel.