Processing math: 0%
\def\Lout{L_\mathrm{out}} \def\Lin{L_\mathrm{in}} \def\ith{i^\mathrm{th}}
up to Schedule & Notes

Computing \mathbf{C} and \mathbf{\alpha}

For each pixel, we have to evaluate the discrete VRI, \Lout = \displaystyle \sum_{i=0}^n C_i\ \alpha_i\ \left(\ \prod_{j=0}^{i-1}\ (1-\alpha_j)\ \right)

Let \ell(t) be the line from the eye through the pixel and let \ell(t_i) be the 3D position on that ray in the middle of the \ith interval, as shown below:

For i = n we'll let C_i\ \alpha_i = \Lin for the backlighting.

However, for i \lt n, we need to evaluate C_i and \alpha_i.

Computing \mathbf{\alpha_i}

The step size, \Delta s, is a constant set by the user. A smaller \Delta s will give more accurate renderings, but will take more time.

Since \alpha_i = \tau_i\ \Delta s, we need only to compute \tau_i.

The CT is provided as a volume consisting of CT numbers in Hounsfield units, and is usually converted to a 3D texture of attenuation coefficients, \tau(x,y,z), at each of the discrete (x,y,z) points in the CT volume.

An accurate conversion would require a knowledge of the parameters of the CT (such as voltage), but the usual process is to just linearly transform the CT numbers into the range [0,1].

To determine \tau_i, we need to look up \tau( \ell(t_i) ) in the 3D texture.

Since \ell(t_i) is usually not at the integer coordinates of one of the texels, we ask the GPU to compute a tri-linear blend of the eight nearest texels. That's done in OpenGL with the usual

glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );

and the texture unit is set up with

glActiveTexture( GL_TEXTURE0 + VOLUME_TEXTURE_UNIT );  // VOLUME_TEXTURE_UNIT = ID of texture unit
glBindTexture( GL_TEXTURE_3D, volumeTextureID );       // volumeTextureID = ID of texture

So computing \alpha_i = \tau_i\ \Delta s is pretty straightforward.

Computing \mathbf{C_i}

We'll use the Phong illumination model to bounce light off of "surfaces" in the volume:

Then C_i = k_d\ N \cdot L + k_s\ (R \cdot V)^n

The direction, L, to the light and the direction, V, to the viewer are known. And n is the shininess constant.

Ways to determine k_d are discussed in the Transfer Functions lecture.

The surface normal, N, will be the defined using the gradient of the attenuation field, or \nabla \tau(x,y,z) = ( {\partial\: \tau \over \partial\: x}, {\partial\: \tau \over \partial\: y}, {\partial\: \tau \over \partial\: z} )

Since the gradient points in the direction of fastest increase of \tau, it will point in to a surface, since density increases when going from above a surface to below a surface.

Since the surface normal, N, should point out from a surface, we define N = - {\nabla \tau \over |\nabla \tau|}

Computation of the gradient is discussed in the Computing Gradients lecture.

For volume rendering, it's often sufficient to use only the diffuse term of the Phong model.

up to Schedule & Notes