Chair of Computer Graphics and Visualization

Sheet 5: Volume Rendering 1

Exercise: Basic Volume Raycasting (20 points)

In this exercise you will implement the core loop of a direct volume renderer. The provided application already creates a 3D texture from simple analytic scalar fields, renders the clipped front faces of the volume cube, and passes all required information to the fragment shader.

Your task is to complete the function tracePrimaryRay in Shader/cubeFS.glsl. The surrounding code already computes the ray direction, the distance to the volume boundary, the number of samples, the step size, and the opacity correction factor.

Implement front-to-back emission-absorption raycasting:

The shader already provides the geometric setup for one ray per fragment. The varying entryPoint is the position where the viewing ray enters the volume in texture coordinates. The uniform cameraPosInTextureSpace gives the camera position in the same coordinate system, so the ray direction is computed as normalize(entryPoint - cameraPosInTextureSpace).

The helper distanceToVolumeExit computes rayLength, the distance from the entry point to the point where the ray leaves the clipped volume bounds. From this length and the volume resolution voxelCount, the shader estimates how many voxels the ray crosses. Multiplying that estimate by oversampling gives sampleCount. The values stepLength = rayLength / sampleCount and delta = rayDirection * stepLength then define the spacing and direction of the ray-marching samples.

Top-down diagram of volume ray marching variables

Top view of a fragment ray through the volume. The shader starts at entryPoint, advances by delta, and stops at the volume exit or after early ray termination.

Inside the ray-marching loop, start with currentPoint = rayStart and an accumulated color of vec4(0.0). At each sample, read the scalar value from volume, map it through transferFunction, correct its opacity for the current step length, composite it front-to-back with under, and then advance currentPoint by delta.

Implement early ray termination and stop the raycasting when the accumulated alpha exceeds 0.95.

The opacity correction keeps the rendered volume visually stable when the sampling rate changes. Without it, increasing oversampling would add more samples with the same opacity, making the same volume appear too opaque. The shader uses opacityCorrection = 100.0 * stepLength and corrects the transfer-function alpha with correctedAlpha = 1.0 - pow(1.0 - transferAlpha, opacityCorrection). Equivalently, the remaining transparency is raised to the step-size-dependent exponent: 1.0 - correctedAlpha = pow(1.0 - transferAlpha, opacityCorrection). In this exercise, the factor 100.0 means that the transfer-function opacity is treated as being defined for a reference step length of about 0.01 in texture space.

The final program should resemble the example shown below.

Reference Solution

Loading

V toggle volume, R reset, T toggle transfer-function editor
1 clip in X, 2 clip in Y, 3 clip in Z
4 move clip in X, 5 move clip in Y, 6 move clip in Z
Q increase oversampling, W decrease oversampling
Up zoom in, Down zoom out
Left mouse drag rotate, Right mouse drag quick edit transfer function