NURBS ray tracing

Curves

The general form of NURBS is defined as:

C ( u ) = i n N i , k ( u ) w i P i i n N i , k ( u ) w i C(u) = \frac {\sum_{i}^{n}N_{i,k}(u)w_iP_i} {\sum_{i}^{n}N_{i,k}(u)w_i}

, where N is the B-Spline basis function, n is the number of control points, w i w_i are the weights, P i P_i are control points, and k is the degree.

The B-Spline basis function of degree 0 is defined as:

N i , 0 ( u ) = { 1 if  u i u < u i + 1 0 otherwise N_{i,0}(u) = \begin{cases} 1 & \text{if}~ u_i \leq u < u_{i+1} \\ 0 & \text{otherwise} \end{cases}

For higher degrees, the B-Spline basis functions are defined recursively:

N i , n ( u ) = u u i u i + k u i N i , k 1 ( u ) + u i + k + 1 u u i + k + 1 u i + 1 N i + 1 , k 1 ( u ) N_{i,n}(u) = \frac{u - u_i}{u_{i+k} - u_i} N_{i,k-1}(u) + \frac{u_{i+k+1} - u}{u_{i+k+1} - u_{i+1}} N_{i+1,k-1}(u)

, where are knots, k k is the degree.

Surely, calculating this function when rendering every frame is horribly slow, but luckily, we're able to simplify this if we know what degree we want.

Interpolation in Graphics World

Part 3 Cubic Convolution

Cubic convolution provides a fast way to interpolate the texture data, which Keys originally proposed. With this method, texture sampling can be simplified to taking four samples, multiplying them with four weights, and adding all of them together. It takes discrete image data and an interpolation kernel and outputs continuous data. The convolution kernel is the following:

u ( s ) : = { ( a + 2 ) s 3 ( a + 3 ) s 2 + 1 if  0 s 1 a s 3 5 a s 2 + 8 a s 4 a if  1 s 2 0 otherwise u(s):= \begin{cases} (a + 2)|s|^3 - (a + 3)|s|^2 + 1 & \text{if } 0 \leq |s| \leq 1 \\ a|s|^3 - 5a|s|^2 + 8a|s| - 4a & \text{if } 1 \leq |s| \leq 2 \\ 0 & \text{otherwise} \end{cases}

Where a a is a constant, we usually choose 0.5 -0.5 as the value. To apply the above kernel, we use the following function:

g ( x ) = i c i u ( x x i h ) g(x) = \sum_{i} c_{i}u(\frac {x - x_{i}} {h})

Where i i is the index of the input image data, c i c_{i} is the colour value, and x x is the interpolation point. Because u ( s ) u(s) is 0 0 if s s is not in the range of [ 2 , 2 ] [-2, 2] , x i x_i can only be the four nearest indexes to x x .

For example, if x x is 5.5, then x i x_i can only be 4 4 , 5 5 , 6 6 and 7 7 , and the parameter s s of the kernel function u ( s ) u(s) can only be 1.5 1.5 , 0.5 0.5 , 0.5 -0.5 and 1.5 -1.5 . We then take the four pixels and multiply them by u ( s ) u(s) , resulting in:

g ( 5.5 ) = u ( 1.5 ) c 4 + u ( 0.5 ) c 5 + u ( 0.5 ) c 6 + u ( 1.5 ) c 7 g(5.5) = u(1.5)c_{4} + u(0.5)c_{5} + u(-0.5)c_{6} + u(-1.5)c_{7}

Interpolation in Graphics World

Part 2 Splines

In the last article, we discussed polynomial interpolation. It works, but we will struggle to find coefficients for big data sets. Instead of using polynomial interpolation, we can use splines to solve this issue.

Splines define multiple pieces of a curve and keep the curve smooth by ensuring the tangent of each point on the curve is continuous. Therefore, it does not need to increase the degree when we add more values to interpolate. This article is going to discuss some commonly used splines.

B-Spline Curves

The form of the B-Spline is defined recursively.

S n , t ( x ) : = i a i B i , n ( x ) S_{n,t}(x) := \sum_{i} a_iB_{i,n}(x)

Where n n is the degree of the spline; t t is knots; a a is control points; B B is the B-spline basis function, defined by:

B i , 0 : = { 1 if  t i x t i + 1 0 otherwise B_{i,0} := \begin{cases} 1 & \text{if } t_i \leq x \leq t_{i+1} \\ 0 & \text{otherwise} \end{cases}
B i , n ( x ) : = B_{i,n}(x) :=

Interpolation in Graphics World

Part 1 Polynomial Interpolation

Interpolation is commonly used in computer programs. The most common interpolation method is linear interpolation, which takes two values and generates continuous uniform distributed results. For example, say we have a data set [10, 30, 40, 0]. The linear interpolation result of the data set will be like the following:

Linear Interpolation

As the figure shows, linear interpolation does generate a continuous result. However, the curve that it generates could be smoother. Sometimes, we may not want those sharp corners. For example, if we're going to describe a spherical object, those sharp corners may make it look bad; Or if we are trying to interpolate an image, we may find the interpolated image weird.

To address this issue, we should use interpolation methods which generate smooth results.

Polynomial Interpolation

The data set [10, 30, 40, 0] contains four values, which means to describe a curve passing all four points, we need a three-degree polynomial, a x 3 + b x 2 + c x + d = y ax^3+bx^2+cx+d=y . Where a a , b b , c c and d d are coefficients, we will need to find them out. It is easy because with known x x and y y values, we can create a linear system based on them and use matrices to solve the issue.

The linear system based on the data set is:

{ y 1 = a x 1 3 + b x 1 2 + c x 1 + d y 2 = a x 2 3 + b x 2 2 + c x 2 + d y 3 = a x 3 3 + b x 3 2 + c x 3 + d y 4 = a x 4 3 + b x 4 2 + c x 4 + d \begin{cases} y_{1} = a \cdot x_{1}^3 + b \cdot x_{1}^2 + c \cdot x_{1} + d \\ y_{2} = a \cdot x_{2}^3 + b \cdot x_{2}^2 + c \cdot x_{2} + d \\ y_{3} = a \cdot x_{3}^3 + b \cdot x_{3}^2 + c \cdot x_{3} + d \\ y_{4} = a \cdot x_{4}^3 + b \cdot x_{4}^2 + c \cdot x_{4} + d \\ \end{cases}

And the matrix form of the above is:

Multisample Anti-aliasing

The Image Distoration Issue and Anti-aliasing Algorithms

In 3D rendering, aliasing or image distortion is a difficult part that requires a lot of calculations to solve. It distorts images and makes images a bit ugly. For example, the following image was rendered by my SWRenderer project without any anti-aliasing:

Aliasing Issue

The edges of the box are jagged.

Aliasing Issue

Luckily, there are a few ways to tackle this issue. The simplest way is supersampling. It is to divide each pixel into multiple subpixels, render each subpixel and output the average value of the subpixels for each pixel. However, despite this method being able to solve the issue perfectly, it needs too much calculation and is almost impossible to use in realtime rendering. Instead, multisample is more commonly used.

The multisample algorithm only renders each pixel once, but it still gives an excellent result.

The Algorithm

Pixel Coverage

Say we are rendering a triangle like the above. The blue points are the subsamples, and the red triangle is the triangle we are rendering.

Without multisampling, the output image may look like the following, as only pixel 5 is fully covered by the triangle.

Pixel Coverage

To make the image better, we divide pixels which are not fully covered by a triangle into a couple of subpixels. Instead of rendering them, we only use them to calculate the coverage of the pixel. If a pixel is fully covered, we deem the coverage of the pixel to be 100%.