Srend Manual

Alpha Compositing along Rays : Ray Casting

There can be confusion in the lingo of "ray casting" and "ray tracing". Here, "ray casting" means simply collecting emissions from each sample point along a ray. Consider each sample to have an RGBA value. RGB values (red, green, blue) are each in [0.0, 1.0] which correspond to RGB image formats as byte values in [0,255]. The alpha value is opacity in [0.0,1.0] where alpha = 0.0 means transparent and alpha = 1.0 means opaque.

One can composite these sample emissions either front2back or back2front. There are advantages with each. Front2back can be useful if samples along the entire ray are available because one can stop anytime the composited alpha value is close enough to being opaque; this is called "early ray termination" which reduces needless work on data which cannot be seen. Back2front is slightly simpler, but it can have advantages in a distributed rendering job because rays always diverge and, hence, further volume data requires less work; bricks further away require less work, will be rendered sooner and can be composited first while nearer bricks are still being rendered. Srend currently uses back2front because data bricks are rendered independently (early ray termination is not practical), but it does not yet exploit the fact that furthest bricks are rendered sooner.

ray cast sampling
Alpha Compositing : calculation

Consider a sample s with R,G,B, and a for red, green, blue, and alpha each within [0.0,1.0]. We start with the composited result \(c_1\) having values \((r_1,g_1,b_1,a_1) \) where \(r_1 = R_1 a_1, g_1 = G_1 a_1, b_1 = B_1 a_1, a_1 = a_1\). This is a "pre-multipled-by-alpha" vector for compositing.

\(r_i = r_{i-1}(1-a_{i}) + r_{i}\)
\(g_i = g_{i-1}(1-a_{i}) + g_{i}\)
\(b_i = b_{i-1}(1-a_{i}) + b_{i}\)
\(a_i = a_{i-1}(1-a_{i}) + a_{i}\)

The ith values on the left store the composited values, and the ith values on the right are the pre-multiplied sample values. We end up with \(c_N = (r_N,g_N,b_N,a_N) \). Call this composited value \(c_j\) for the jth brick .

If we do this along the same ray which passes through M bricks, we have as set of composited values \(c_1, c_2, ..., c_M\). We leave these values multiplied with alpha, and we composite the brick values \(c_j\) in back2front order just as we composited samples within each brick. The result c is our image which we write to disk as an RGB image by scaling the r, g, and b values from [0.0,1.0] to [0,255] for bytes. To write an RGBA image, also write out the a value.

We have not divided out alpha, and we do not. We consider our background to be black or RGBA = (0,0,0,1). Composite the final c RGBA value to this black background for an RGB image, and it amounts to leaving RGB multiplied by alpha.

Note that order matters for compositing (compositing is not commutative), yet compositing is associative when we do it in this pre-multiplied alpha fashion. To prove this, show that compositing \(c_1\) and \(c_2\) then compositing that with \(c_3\), is the same as compositing \(c_1\) with the compositing of \(c_2\) and \(c_3\).

Compositing "back2front", but viewing from \(\infty\) to the eye (outside2in)

This can be useful for some purposes, and Srend does it by providing a negative dt value, say dt = -.25 . We still composite from the "back to front" meaning from outside to in, but we switch to front2back compositing.

\(r_i = r_{i-1} + r_i(1-a_{i-1})\)
\(g_i = g_{i-1} + g_i(1-a_{i-1})\)
\(b_i = b_{i-1} + b_i(1-a_{i-1})\)
\(a_i = a_{i-1} + a_i(1-a_{i-1})\)

Srend makes this adjustment from a negative dt value in srend_render for ray casting sampling along rays and in the composer/finisher when compositing brick images.