• No se han encontrado resultados

Warping

4.3.4 Algorithm

The pseudo-code for the algorithm is presented below with descriptions of the algorithm.

PROC RenderParallelVolume(root_node,projection_matrix)

END

(viewing_axis, shear_x, shear_y, warp_matrix) =

CalculateViewingParameters(projection_matrix);

(traversal_order)

=

CalculateTraversalOrders(viewing_axis, shear_x, shear_y);

RenderParallelNode(root_node, traversal_order);

Warpimage(warp_matrix);

RenderParalle!Volume calculates all v1ewmg parameters, then builds an array of node numbers according to the traversal order. CalculateViewingParameters performs a factorization of the projection matrix, and computes the primary viewing and shearing directions. The warp matrix is also computed. The RenderParalle/Volume function then begins a recursive rendering of the octree to an intermediate compositing image. Finally this compositing image is warped into the final image.

PROC CalculateTraversalOrders(viewing_axis, shear_x, shear_y)

CASE (viewing_axis)

X IF ( shear_x<O) IF (shear_y<O)

RETURN TraversalOrderTable[O) ELSE

RETURN TraversalOrderTable[2) END

ELSE

IF ( shear_y<O)

RETURN TraversalOrderTable[l) ELSE

RETURN TraversalOrderTable[3) END

END

Y IF ( shear_x<O) IF (shear_y<O)

RETURN TraversalOrderTable[4) ELSE

RETURN TraversalOrderTable[6) END

ELSE

IF (shear_y<O)

RETURN TraversalOrderTable[5) ELSE

RETURN TraversalOrderTable[7) END

END

Z IF (shear_x<O) IF (shear_y<O)

RETURN TraversalOrderTable[BJ ELSE

RETURN TraversalOrderTable[lO) END

ELSE

IF (shear_y<O)

RETURN TraversalOrderTable[9) ELSE

RETURN TraversalOrderTable[ll) END

END END

END

The CalculateTraversa/Order function uses the primary viewing direction and the shearing factors to calculate an ordered list of nodes used for the traversal order of the octree.

PROC RenderParallelNode(root_node, traversal_order) FOR ( i = 1 TO 8)

child_info

=

root_node.child[traversal_order[i));

IF (IsVisible(child_info))

END

IF (DataPresent(child_info))

ELSE END

IF (IsLeafNode(child_info)) PerformRendering(child_info);

ELSE

END

RenderParallelNode(child_info.node, traversal_order) ;

PerformPartialRendering(child_info);

END

RenderParalle/Node is recursive function which attempts to render the volume represented by the octree by traversing the octree to a maximum depth. The function accepts a node in the octree, and it loops through all of its children. For each of the child nodes:

If it is visible and the node is a leaf node with its data present, then it is rendered normally.

If it is visible and the node is a leaf node but its data is not present then it is rendered using the partial rendering function.

If it is visible and the node is not a leaf node and the data for the child nodes are present then the RenderParalle/Node function is called with this child node.

If it is visible and the node is not a leaf node but the data for the child nodes is not present, then the node is rendered using t e partial rendering function.

PROC PerforrnRendering(node_info) FOR(z 0 TO node_info.size)

u

=

node_info.x + (node_info.z + z) * shear_x;

v

=

node_info.y + (node_info.z + z) * shear_y;

FOR(y

=

0 TO node_info.size) FOR(x

=

0 TO node_info.size)

IF (IsOpaque(u + x, v + y))

x

=

x + SkipOpaquePixels(u + x, u + y) - 1;

ELSE

(colour, alpha)

=

CalculatePixel(node_info.data[x,y,z]);

CompositePixel(u + x, v + y, (colour,alpha));

END END END END END

PerformRendering renders the specified octree node using the raw data referenced in that node. The function loops through the node and composites the slices onto the intermediate image. During an individual scan-line runs of pixels (voxels) may be skipped if they are already opaque in the intermediate image. For non-opaque pixels the corresponding voxel is retrieved from the raw data. (It should be noted here that a variable modulus has to be used to reference this data as a 3 dimensional array, and this modulus would be calculated at the same stage as the traversal order.) Then using the CalculatePixel functio (which uses shade tables) the shading of that voxel is calculated. The resulting shaded pixel is then composited into the intermediate image.

PROC PerformPartialRendering(node_info) FOR(z 0 TO node_info.size)

u

=

node_info.x + (node_info.z + z) * shear_x;

v node_info.y + (node_info.z + z) * shear_y;

END END

FOR(y = 0 TO node_info.size)

END

FOR(x = 0 TO node_info.size)

END

IF (IsOpaque(u + x, v + y)) ELSE

END

x = x + SkipOpaquePixels(u + x, u + y) - 1;

voxe1

Trilinearinterpolate(node_info.corner_values, node_info.average_normal, node_info.average_gradient, node_info.size,

x, y, z);

(colour, alpha) = CalculatePixel(voxel);

CompositePixel(u + x, v + y, colour, alpha);

PerformPartia/Rendering renders a partial octree node by using trilinear interpolation of the values throughout the sub-volume. The compositing is performed in exactly the same fashion as the PerformRendering function but the calculation of the voxel relies on the Trilinear Interpolate function. This function uses the voxel values at each comer of the sub-volume, the average nonnal of opaque voxels in the volume, and the average gradient of opaque voxels in the volume to determine a particular voxel value. ~ote: In the actual implementation, and as mentioned in a previous section, a incremental version of the trilinear interpolation function is used to rapidly calculate the voxel values.)

PROC CompositePixe1(comp_x, comp_y, colour, alpha)

END

IF (alpha > TRANSPARENT_VALUE)

END

comp_image[comp_x,comp_y] = comp_image[comp_x,comp_y] OVER {colour,alpha);

IF (comp_image[comp_x,comp_y) .alpha >= OPAQUE_VALUE) comp_f1ags[comp_x,comp_y] =TRUE;

END

This function composites a pixel into the compositing image (intermediate image) using the OVER operator. If the resultant pixel becomes completely opaque then that pixel is flagged as being opaque and will then be skipped in future passes.

PROC SkipOpaquePixe1s(comp_x, comp_y)

i = 0;

WHILE (EndOfScanline(comp_x + i, comp_y)) IF (comp_flags[comp_x + i, comp_y])

i

=

i + 1;

ELSE

RETURN i;

END

I~

END RETURN i;

SkipOpaquePixels calc lates the length of a run of opaque pixels in the compositing image. In the original Shear-Warp a algorithm used forests of trees (implemented as offsets in each pixel) to allow this skipping to be efficient). In this implementation bit flags are used for each pixel and rapid bit manipulation functions are used to scan runs. (For long runs, on a 32-bit processor, 32 pixels may be skipped in one machine instruction.) We found that this approach allowed for simpler and more flexible coding as well s slightly improving the efficiency.

PROC IsOpaque{comp_x, comp_y)

RETURN comp_flags[comp_x, comp_y];

END

This returns whether the specified pixel in the intermediate image is opaque or not.