Algorithm 16 presents our version of the cell-projection algorithm. The cell-projection algorithm projects each tetrahedron and face onto the image as the first step. The pro- jections are stored in terms of intersection records, which represent a certain primitive is projected upon a certain pixel. For each pixel in the image, a list of intersection records are maintained. Screen space projections of vertices are computed and stored in the SSC array. Then the projections of tetrahedra and faces are computed and cor- responding intersection records are inserted into the PerPixelIntersectionLists array. Because the pixel coordinates are implicitly stored in array indices of PerPixelInter- sectionLists array, the inserted records only store a pointer to the face or tetrahedron. After the projections of all tetrahedra and faces are processed, the PerPixelIntersec- tionLists array contain a list for each pixel, which stores all tetrahedra and faces that project onto that pixel.
The algorithm constructs the image pixel by pixel by computing the intensity con- tributions of each intersection record. Tetrahedra and face intersection records are treated differently while calculating the intensity, but the output intensity structure is identical. The intensity contribution structure contains two pieces of data. The first one is the camera distance to the entry point of the tetrahedron or the face. This data is used in visibility sorting of intersection records. The second piece of data is the intensity contribution of the ray that travels through the tetrahedron or the face.
After the intensities are computed, the results are sorted according to the camera distance. Then starting from near to far, the intensity contributions are composed into a single intensity value, which is assigned as the pixel intensity.
The calculation of tetrahedron intensity contributions is described in Algorithm 17. The algorithm starts by finding the entry and exit points of the ray on the tetrahedron (cf. Figure 5.5 (a)). It samples points along the line segment between the entry and
SurfaceAndVolumeRenderer() begin
//Calculate the screen-space coordinates of each vertex SSC=ComputeScreenSpaceProjections(Vertices);
//Group the lists storing every ray-tetrahedron and ray-face intersections for each pixel
IntersectionRecord PerPixelIntersectionLists[Width][Height];
//Fill out the PerPixelIntersectionLists list via the projection of tetrahedra and faces onto the screen foreach (tetrahedron t in volume data) do
ProjectionPixels=ExtractProjectionPixels(t,SSC); foreach (pixel p in ProjectionPixels) do
PerPixelIntersectionLists[p.x][p.y]+=t; foreach face f in surface data do
ProjectionPixels=ExtractProjectionPixels( f ,SSC); foreach (pixel p in ProjectionPixels) do
PerPixelIntersectionLists[p.x][p.y]+= f ; foreach Pixel p with indices i,j do
list=PerPixelIntersectionLists[i][j];
IntensityContrib IntensityContribList=NULL; //Cast the ray for the current pixel Ray R=new Ray(i, j);
//Compute the intensity contributions of each intersection with R
foreach (IntersectionRecord ir in list) do if (ir is tetrahedron intersection) then
IntensityContribList+=CalculateTetrahedronIntensityContrib(ir, R); else if (ir is surface intersection) then
IntensityContribList+=CalculateSurfaceIntensityContrib(ir, R); //Sort the intensity contributions according to eye
distances
SortIntensityContributions(IntensityContribList);
//Compose the intensity contributions in sorted order
Color c = ComposeIntensityContributions(IntensityContribList); Image[i][ j]=c;
end
exit points. The intensity of each sample is calculated by interpolating the intensi- ties of tetrahedron vertices. The interpolated intensity also contains the alpha channel value representing the transparency. The sampled intensities are combined into a sin- gle intensity. While combining the intensities, front-to-back alpha-blending is used and the alpha channel value is corrected for each sample. The contribution of each intensity value is proportional to the segment length of the sample. For a fully-opaque volume, only the entry intensity matters because the ray will lose all of its intensity at the beginning.
The intensity of vertices are determined by the defects associated with the atom defining the vertex. The quantified defect values of an atom a are converted into the intensity values using the following equation:
a.Color =BaseColor+
a.PositionalDefect × PositionalDefectColor × PositionalDefectMultiplier+ a.ExtraAtomDefect × ExtraAtomColor × ExtraAtomMultiplier+
a.VacancyDefect × VacancyColor × VacancyDefectMultiplier
The color and error multipliers used in the equation are tunable by the user. Algo- rithm 18 calculates the surface intensity contributions. The color and transparency of the faces and the lighting parameters are tunable by the user.
The algorithm for computing the surface intensities starts by finding the intersec- tion point between the face and the ray. The distance from the camera to the intersec- tion point is computed. The intensity of intersection is computed using interpolation of the intensities of face vertices. The normal for the intersection point is calculated. If the shading mode is flat, the face normal is used. If shading mode is smooth, the vertex normals are interpolated. Figure 5.5 (b) demonstrates the face ray intersection and the light-normal angle. We use Phong illumination model for this rendering mode. The main focus in this rendering mode is still the volume rendering part; hence, a simpler lighting model is user-friendly and works well.
CalculateTetrahedronIntensityContrib(ir, R) begin
IntensityContrib ic;
tetrahedron t=ir.tetrahedron;
//Calculate the entry and exit points of the ray on the tetrahedron
[EntryPoint, ExitPoint]=findIntersectionPoints(t, R); ic.distance=|Camera − EntryPoint| ;
//Calculate the sample length d=|ExitPoint − EntryPoint| /NumOfSamples ; ic.int=0, 0, 0, 0;
//Sample points along the line segment in the tetrahedron
for (i=0 upto NumOfSamples) do
//Find the position and the intensity of the sample point via linear interpolation
point p=i×EntryPoint+(NumOfSamples−i)×ExitPointNumOfSamples ; Intensity pInt=InterpolateIntensity(p, t);
//Add the contribution of current sample on ic.int ic.int=CombineIntensity(ic.int, pInt, d);
return ie; end
Algorithm 17: Calculation of tetrahedron intensity contributions.
CalculateSurfaceIntensityContrib(ir, R) begin
IntensityContrib ic; face f =ir.face;
//Compute the ray-face intersection point IntersectionPoint=findIntersectionPoint(f, R);
ic.distance=|Camera − IntersectionPoint| ; ic.int=InterpolateIntensity(IntersectionPoint, f );
//Use interpolated vertex formals or face normal depending on the shading model
N=getNormal(IntersectionPoint, f ); foreach (Light l) do
//Calculate the intensity contribution for each light source using Phong illumination model and add to the intensity
ic.int += Calculated intensity for light source l; return ic;
end