Research Topic - Computer Graphics

August 24, 2019

I would like to write this blog to thank Dr. Xue Dong Yang during my graduate studies in computer graphics.

He instructed us step by step to fully understand Ray Tracing & Volumn Rendering algorithms and write the source code to realize them.

Ray Tracing

Main

import java.io.*;
public class MainBody {
    public static void main(String[] args) throws IOException {
        int i, j;
        double C = 0;

        //get transform matrix
        MyModel.Mwc = Mwc_Mcw.Mwc(
          MyModel.VRP[0], MyModel.VRP[1], MyModel.VRP[2],
          MyModel.VPN[0], MyModel.VPN[1], MyModel.VPN[2],
          MyModel.VUP[0], MyModel.VUP[1], MyModel.VUP[2]);

        MyModel.Mcw = Mwc_Mcw.Mcw(
          MyModel.VRP[0], MyModel.VRP[1], MyModel.VRP[2],
          MyModel.VPN[0], MyModel.VPN[1], MyModel.VPN[2],
          MyModel.VUP[0], MyModel.VUP[1], MyModel.VUP[2]);

        //scan each pixel in the image
        for (i = 0; i < MyModel.ROWS; i++)
            for (j = 0; j < MyModel.COLS; j++) {
                // construct the ray, V, started from the CenterOfProjection, P0,
                // and passing through the pixel (i, j);
                ray_construction.generate(j, i);
                C = ray_tracing.main(MyModel.P0, MyModel.V0);
                if (C != 0)
                    MyModel.image[j][i] = (int) C;
            }
        // output the final image;
        FileOutputStream out = null;
        out = new FileOutputStream("C:/Users/CHAO/Desktop/output_image.raw");
        for (i = 0; i < MyModel.ROWS; i++)
            for (j = 0; j < MyModel.COLS; j++)
                out.write(MyModel.image[j][i]);
        out.close();
    }
}

MWC -> MCW

public class Mwc_Mcw {
    public static double[][] get_matrix(
      double VRP_x, double VRP_y, double VRP_z,
      double VPN_x, double VPN_y, double VPN_z,
      double VUP_x, double VUP_y, double VUP_z, String mark) {

        double u_x, u_y, u_z;
        double v_x, v_y, v_z;
        double n_x, n_y, n_z;
        double n_value, u_value, v_value;
        double R[][] = new double[4][4];
        double T[][] = new double[4][4];
        double M[][] = new double[4][4];

        // n = VPN / |VPN|
        n_value = Math.sqrt(VPN_x * VPN_x + VPN_y * VPN_y + VPN_z * VPN_z);
        n_x = VPN_x / n_value;
        n_y = VPN_y / n_value;
        n_z = VPN_z / n_value;

        // u = VUP X VPN / |VUP X VPN|
        u_value =
          Math.pow((VUP_y * VPN_z - VPN_y * VUP_z), 2) +
          Math.pow((VPN_x * VUP_z - VUP_x * VPN_z), 2) +
          Math.pow((VUP_x * VPN_y - VPN_x * VUP_y), 2);
        u_value = Math.sqrt(u_value);

        u_x = (VUP_y * VPN_z - VPN_y * VUP_z) / u_value;
        u_y = (VPN_x * VUP_z - VUP_x * VPN_z) / u_value;
        u_z = (VUP_x * VPN_y - VPN_x * VUP_y) / u_value;

        // v = VPN X u / |VPN X u|
        v_value =
          Math.pow((VPN_y * u_z - u_y * VPN_z), 2) +
          Math.pow((u_x * VPN_z - VPN_x * u_z), 2) +
          Math.pow((VPN_x * u_y - u_x * VPN_y), 2);
        v_value = Math.sqrt(v_value);

        v_x = (VPN_y * u_z - u_y * VPN_z) / v_value;
        v_y = (u_x * VPN_z - VPN_x * u_z) / v_value;
        v_z = (VPN_x * u_y - u_x * VPN_y) / v_value;

        R[0][0] = u_x;
        R[1][0] = u_y;
        R[2][0] = u_z;
        R[3][0] = 0.0;

        R[0][1] = v_x;
        R[1][1] = v_y;
        R[2][1] = v_z;
        R[3][1] = 0.0;

        R[0][2] = n_x;
        R[1][2] = n_y;
        R[2][2] = n_z;
        R[3][2] = 0.0;

        R[0][3] = 0.0;
        R[1][3] = 0.0;
        R[2][3] = 0.0;
        R[3][3] = 1.0;

        // Because R is an orthogonal matrix,invertible matrix of R is equal to R's
        // transposed matrix

        // Matrix of T
        T[0][0] = 1.0;
        T[1][0] = 0.0;
        T[2][0] = 0.0;
        T[3][0] = -VRP_x;

        T[0][1] = 0.0;
        T[1][1] = 1.0;
        T[2][1] = 0.0;
        T[3][1] = -VRP_y;

        T[0][2] = 0.0;
        T[1][2] = 0.0;
        T[2][2] = 1.0;
        T[3][2] = -VRP_z;

        T[0][3] = 0.0;
        T[1][3] = 0.0;
        T[2][3] = 0.0;
        T[3][3] = 1.0;

        if (mark == "mcw") {
            // get the invertible matrix of T
            T[3][0] *= (-1);
            T[3][1] *= (-1);
            T[3][2] *= (-1);

            // get the invertible matrix of R
            R[1][0] = v_x;
            R[2][0] = n_x;

            R[0][1] = u_y;
            R[1][1] = v_y;
            R[2][1] = n_y;

            R[0][2] = u_z;
            R[1][2] = v_z;

            // calculation of R(inverse)*T(inverse)
            M = calc.MatrixTimes(T, R);
        }
        // calculation of R*T
        if (mark == "mwc")
            M = calc.MatrixTimes(R, T);
        return M;
    }

    public static double[][] Mwc(
      double VRP_x, double VRP_y, double VRP_z,
      double VPN_x, double VPN_y, double VPN_z,
      double VUP_x, double VUP_y, double VUP_z) {
        double M[][] = new double[4][4];
        M = get_matrix(VRP_x, VRP_y, VRP_z,
          VPN_x, VPN_y, VPN_z,
          VUP_x, VUP_y, VUP_z, "mwc");
        return M;
    }

    public static double[][] Mcw(
      double VRP_x, double VRP_y,
      double VRP_z, double VPN_x,
      double VPN_y, double VPN_z,
        double VUP_x, double VUP_y, double VUP_z) {
        double M[][] = new double[4][4];
        M = get_matrix(VRP_x, VRP_y, VRP_z,
          VPN_x, VPN_y, VPN_z,
          VUP_x, VUP_y, VUP_z, "mcw");
        return M;
    }

}

MyModel

// Initialize the global data structures;
public class MyModel {
    /* definition of the image buffer */
    public static final int ROWS = 512;
    public static final int COLS = 512;
    public static int image[][] = new int[ROWS][COLS];
    /* definition of window on the image plane in the camera coordinates */
    /* They are used in mapping (j, i) in the screen coordinates into */
    /* (x, y) on the image plane in the camera coordinates */
    /* The window size used here simulates the 35 mm film. */
    public static double xmin = 0.0175;
    public static double ymin = -0.0175;
    public static double xmax = -0.0175;
    public static double ymax = 0.0175;
    /* definition of the camera parameters */
    public static double VRP[] = new double[] {
        1.0,
        2.0,
        3.5
    };
    public static double VPN[] = new double[] {
        0.0,
        -1.0,
        -2.5
    };
    public static double VUP[] = new double[] {
        0.0,
        1.0,
        0.0
    };
    /* focal length simulating 50 mm lens */
    public static double focal = 0.05;
    /* definition of light source */
    public static double LPR[] = new double[] {
        -10.0, 10.0, 2.0
    };
    /* intensity of the point light source */
    public static double IP = 200.0;
    public static double Mwc[][] = new double[4][4];
    public static double Mcw[][] = new double[4][4];
    public static double[] P0 = new double[4];
    public static double[] V0 = new double[4];
    /* create a spherical object */
    public static SPHERE obj1 = new SPHERE(1.0, 1.0, 1.0, 1.0, 0.75);
    /* create a polygon object */
    public static POLY4 obj2 = new POLY4();
}

Poly4

/* Definition of Polygon with 4 edges */
public class POLY4 {
    double[][] v = new double[4][3];
    double[] N = new double[3];
    double kd;
    public POLY4() {
        /* v0 */
        v[0][0] = 0.0;
        v[0][1] = 0.0;
        v[0][2] = 0.0;

        /* v1 */
        v[1][0] = 0.0;
        v[1][1] = 0.0;
        v[1][2] = 2.0;

        /* v2 */
        v[2][0] = 2.0;
        v[2][1] = 0.0;
        v[2][2] = 2.0;

        /* v3 */
        v[3][0] = 2.0;
        v[3][1] = 0.0;
        v[3][2] = 0.0;

        /* normal of the polygon */
        N[0] = 0.0;
        N[1] = 1.0;
        N[2] = 0.0;

        /* diffuse reflection coefficient */
        kd = 0.8;
    }
}

Sphere

/* Definition of the structure for Sphere */
public class SPHERE {
    // define
    /* x y z as center of the circle */
    /* radius as radius of the circle */
    /* kd as diffuse reflection coefficient */
    double x, y, z;
    double radius;
    double kd;
    public SPHERE(double x, double y, double z, double radius, double kd) {
        super();
        this.x = x;
        this.y = y;
        this.z = z;
        this.radius = radius;
        this.kd = kd;
    }
}

Ray Construction

public class ray_construction {

    static int i;
    static int j;
    static double[] P0 = new double[4];
    static double[] V0 = new double[4];

    // Construction of ray
    // Input: pixel index (i, j) in the screen coordinates
    // Output: P0, V0 (for parametric ray equation P = P0 + V0*t)
    // in the world coordinates.
    public static void generate(int j, int i) {

        // Step 1:
        // Map (j, i) in the screen coordinates to (xc, yc) in the
        // camera coordinates.

        double xc, yc;

        xc = j * (MyModel.xmax - MyModel.xmin) / (MyModel.COLS - 1) + MyModel.xmin;
        yc = i * (MyModel.ymax - MyModel.ymin) / (MyModel.ROWS - 1) + MyModel.ymin;

        // Step 2:
        // Transform the origin (0.0, 0.0, 0.0) of the camera
        // coordinates to P0 in the world coordinates using the
        // transformation matrix Mcw. Note that the transformed result
        // should be VRP.

        double[] origin_camera = {
            0.0,
            0.0,
            0.0,
            1.0
        };
        P0 = calc.transform(MyModel.Mcw, origin_camera);

        // Step 3:
        // Transform the point (xc, yc, f) on the image plane in
        // the camera coordinates to P1 in the world coordinates using
        // the transformation matrix Mcw.

        double[] data = new double[4];
        double[] P1 = new double[4];

        data[0] = xc;
        data[1] = yc;
        data[2] = MyModel.focal;
        data[3] = 1;
        P1 = calc.transform(MyModel.Mcw, data);

        // V0 = P1 – P0;
        V0[0] = P1[0] - P0[0];
        V0[1] = P1[1] - P0[1];
        V0[2] = P1[2] - P0[2];

        // normalize V0 into unit length;
        V0 = calc.normalize(V0);
        MyModel.P0 = P0;
        MyModel.V0 = V0;
    }
}

Ray Object Intersection

public class ray_object_intersection {

    static double C;
    static double[] P0 = new double[4];
    static double[] V0 = new double[4];
    static double[] P = new double[4];

    static double[] N = new double[3];
    static double[] N1 = new double[3];
    static double[] N2 = new double[3];

    static double kd;
    static double kd1;
    static double kd2;

    public static boolean main(double[] P0, double[] V0) {

        double t1 = 0;
        double t2 = 0;

        kd1 = MyModel.obj1.kd;
        kd2 = MyModel.obj2.kd;

        t1 = ray_sphere_intersection(P0, V0);
        t2 = ray_polygon_intersection(P0, V0);

        if (t1 == 0 && t2 == 0)
            return false;
        else if (t2 == 0) {
            shading.P = calc.vector_add(P0, calc.vector_times(V0, t1));
            shading.N = N1;
            shading.kd = kd1;
            return true;
        } else if (t1 == 0) {
            shading.P = calc.vector_add(P0, calc.vector_times(V0, t2));
            shading.N = N2;
            shading.kd = kd2;
            return true;
        } else if (t1 < t2) {
            shading.P = calc.vector_add(P0, calc.vector_times(V0, t1));
            shading.N = N1;
            shading.kd = kd1;
            return true;
        } else {
            shading.P = calc.vector_add(P0, calc.vector_times(V0, t2));
            shading.N = N2;
            shading.kd = kd2;
            return true;
        }
    }

    public static double ray_sphere_intersection(double[] P0, double[] V0) {

        double t, A, B, C, R, delta;
        double t1, t2;

        // using method 2 from notes
        // solving A^2+B^2+C^2=R^2 by PO+t*V0

        R = MyModel.obj1.radius;
        A = V0[0] * V0[0] + V0[1] * V0[1] + V0[2] * V0[2];
        B = (P0[0] * V0[0] + P0[1] * V0[1] + P0[2] * V0[2]) * 2;
        C = P0[0] * P0[0] + P0[1] * P0[1] + P0[2] * P0[2] - R * R;

        delta = B * B - 4 * A * C;

        // determine if the ray has a intersection with the sphere
        if (delta < 0)
            return 0;
        else {
            t1 = (Math.abs(Math.sqrt(delta)) - B) / (2 * A);
            t2 = (-Math.abs(Math.sqrt(delta)) - B) / (2 * A);
            if (t1 < t2)
                t = t1;
            else
                t = t2;
            N1[0] = (P0[0] + V0[0] * t - MyModel.obj1.x);
            N1[1] = (P0[1] + V0[1] * t - MyModel.obj1.y);
            N1[2] = (P0[2] + V0[2] * t - MyModel.obj1.z);
            return t;
        }
    }

    public static double ray_polygon_intersection(double[] P0, double[] V0) {

        double N_value;
        double D;
        double t;

        double[] V1 = new double[3];
        double[] V2 = new double[3];
        double[] P = new double[3];

        V1[0] = MyModel.obj2.v[1][0] - MyModel.obj2.v[0][0];
        V1[1] = MyModel.obj2.v[1][1] - MyModel.obj2.v[0][1];
        V1[2] = MyModel.obj2.v[1][2] - MyModel.obj2.v[0][2];

        V2[0] = MyModel.obj2.v[2][0] - MyModel.obj2.v[0][0];
        V2[1] = MyModel.obj2.v[2][1] - MyModel.obj2.v[0][1];
        V2[2] = MyModel.obj2.v[2][2] - MyModel.obj2.v[0][2];

        N_value = Math.sqrt(Math.pow((V1[1] * V2[2] - V2[1] * V1[2]), 2) +
                  Math.pow((V2[0] * V1[2] - V1[0] * V2[2]), 2) +
                  Math.pow((V1[0] * V2[1] - V2[0] * V1[1]), 2));
        N[0] = (V1[1] * V2[2] - V2[1] * V1[2]) / N_value;
        N[1] = (V2[0] * V1[2] - V1[0] * V2[2]) / N_value;
        N[2] = (V1[0] * V2[1] - V2[0] * V1[1]) / N_value;


        // compute D

        D = (N[0] * MyModel.obj2.v[0][0] +
              N[1] * MyModel.obj2.v[0][1] +
              N[2] * MyModel.obj2.v[0][2]) * (-1);

        t = ((N[0] * P0[0] + N[1] * P0[1] + N[2] * P0[2]) + D) /
        (N[0] * V0[0] + N[1] * V0[1] + N[2] * V0[2]) * (-1);

        P[0] = P0[0] + V0[0] * t;
        P[1] = P0[1] + V0[1] * t;
        P[2] = P0[2] + V0[2] * t;

        if (is_inside(P, N)) {
            N2 = N;
            return t;
        } else
            return 0;
    }

    public static boolean is_inside(double[] P, double[] N) {

        int number = 0;
        int i;
        int x, y;
        double k, b;
        double[][] V = new double[5][2];
        int[] remain = new int[2];
        remain = drop(N);
        x = remain[0];
        y = remain[1];

        // drop one dimension to make the scene into 2D
        V[0][0] = MyModel.obj2.v[0][x];
        V[0][1] = MyModel.obj2.v[0][y];
        V[1][0] = MyModel.obj2.v[1][x];
        V[1][1] = MyModel.obj2.v[1][y];
        V[2][0] = MyModel.obj2.v[2][x];
        V[2][1] = MyModel.obj2.v[2][y];
        V[3][0] = MyModel.obj2.v[3][x];
        V[3][1] = MyModel.obj2.v[3][y];

        V[0][0] = V[0][0] - P[x];
        V[0][1] = V[0][1] - P[y];
        V[1][0] = V[1][0] - P[x];
        V[1][1] = V[1][1] - P[y];
        V[2][0] = V[2][0] - P[x];
        V[2][1] = V[2][1] - P[y];
        V[3][0] = V[3][0] - P[x];
        V[3][1] = V[3][1] - P[y];
        V[4][0] = V[0][0];
        V[4][1] = V[0][1];

        //calculate the y value of the point intersected with x axis
        for (i = 0; i <= 3; i++) {
            k = (V[i][1] - V[i + 1][1]) / (V[i][0] - V[i + 1][0]);
            b = V[i][1] - V[i][0] * k;
            // y = kx +b
            if ((-b / k) >= 0)
                number++;
        }
        if (number % 2 == 1)
            return true;
        else
            return false;
    }

    public static int[] drop(double[] N) {
        int[] r = new int[2];
        double max;
        int k = 0;
        max = calc.max(N[0], N[1], N[2]);
        for (int i = 0; i < 3; i++) {
            if (N[i] != max) {
                r[k] = i;
                k++;
            }
        }
        return r;
    }
}

Handle Ray Tracing

public class ray_tracing {
    static double C;
    static double[] P0 = new double[4];
    static double[] V0 = new double[4];
    static double kd;
    public static double main(double[] P0, double[] V0) {
        boolean found;
        found = ray_object_intersection.main(P0, V0);
        if (found) {
            C = shading.get();
            return C;
        } else {
          return 0;
        }
    }
}

Shading

// Shading:
// Input: P[3] – point position
// N[3] – surface normal at that point
// kd – diffuse reflection coefficient of the surface
// Output: C – shading value
public class shading {
    public static double[] P = new double[3];
    public static double[] N = new double[3];
    public static double kd;
    public static double C;
    public static double[] L = new double[4]; // LPR is the light position
    public static double get() {
        // L = LPR - P;
        L[0] = MyModel.LPR[0] - P[0];
        L[1] = MyModel.LPR[1] - P[1];
        L[2] = MyModel.LPR[2] - P[2];
        // normalize L to unit length;
        L = calc.normalize(L);
        C = MyModel.IP * kd * (N[0] * L[0] + N[1] * L[1] + N[2] * L[2]);
        return C;
    }
}

Utils

public class calc {
    public static double[][] MatrixTimes(double[][] a, double[][] b) {
        double[][] c = new double[4][4];
        int i, j, k;
        double s;
        for (j = 0; j <= 3; j++) {
            for (i = 0; i <= 3; i++) {
                s = 0;
                for (k = 0; k <= 3; k++) {
                    s += a[k][j] * b[i][k];
                }
                c[i][j] = s;
            }
        }
        return c;
    }

    public static double[] transform(double[][] M, double[] data) {
        int i, j;
        double s;
        double[] newdata = new double[4];
        for (j = 0; j <= 3; j++) {
            s = 0;
            for (i = 0; i <= 3; i++) {
                s += M[i][j] * data[i];
            }
            newdata[j] = s;
        }
        return newdata;
    }

    public static double[] vector_minus(double[] a, double[] b) {
        double[] c = new double[4];
        c[0] = a[0] - b[0];
        c[1] = a[1] - b[1];
        c[2] = a[2] - b[2];
        c[3] = a[3] - b[3];
        return c;
    }

    public static double[] vector_add(double[] a, double[] b) {
        double[] c = new double[4];
        c[0] = a[0] + b[0];
        c[1] = a[1] + b[1];
        c[2] = a[2] + b[2];
        c[3] = a[3] + b[3];
        return c;
    }

    public static double[] normalize(double[] c) {
        double d;
        d = Math.sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]);
        c[0] = c[0] / d;
        c[1] = c[1] / d;
        c[2] = c[2] / d;
        return c;
    }

    public static double[] vector_times(double[] d, double t) {
        d[0] *= t;
        d[1] *= t;
        d[2] *= t;
        return d;
    }

    public static double dot_product(double[] a, double[] b) {
        double c;
        c = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
        return c;
    }

    public static double max(double a, double b, double c) {
        double d = 0;
        if (a > d)
            d = a;
        if (b > d)
            d = b;
        if (c > d)
            d = c;
        return d;
    }
}

Volume Rendering

Additional Files:

Ray Box Intersection

//Ray-Box Intersection
//Input: ray – P0, V0
//Output: n – the number of intersections found
// n = 0, no intersection
// n = 1, one intersection
// n = 2, two intersections
// It will be very rare to find more two intersections.
// In this case, you can set it to 0.
// ts[2] stores the found intersections.
// if n = 2, you should have ts[0] < ts[1].
// kd, the diffuse reflection coefficient of the surface.

public class ray_box_intersection {
    public static int main() {
        int n = 0;
        double t;
        double t0 = 0, t1 = 0;
        double x, y, z;
        double[] intersection = new double[4];

        // for side x = 0
        t = (0 - global.P0[0]) / global.V0[0];
        y = global.P0[1] + global.V0[1] * t;
        z = global.P0[2] + global.V0[2] * t;
        if (y >= 0 && y <= global.ROWS && z >= 0 && z <= global.LAYS) {
            intersection[n] = t;
            n++;
        }

        // for side x = 127
        t = (127 - global.P0[0]) / global.V0[0];
        y = global.P0[1] + global.V0[1] * t;
        z = global.P0[2] + global.V0[2] * t;
        if (y >= 0 && y <= global.ROWS && z >= 0 && z <= global.LAYS) {
            intersection[n] = t;
            n++;
        }

        // for side y = 0
        t = (0 - global.P0[1]) / global.V0[1];
        x = global.P0[0] + global.V0[0] * t;
        z = global.P0[2] + global.V0[2] * t;
        if (x >= 0 && x <= global.COLS && z >= 0 && z <= global.LAYS) {
            intersection[n] = t;
            n++;
        }

        // for side y = 127
        t = (127 - global.P0[1]) / global.V0[1];
        x = global.P0[0] + global.V0[0] * t;
        z = global.P0[2] + global.V0[2] * t;
        if (x >= 0 && x <= global.COLS && z >= 0 && z <= global.LAYS) {
            intersection[n] = t;
            n++;
        }

        // for side z = 0
        t = (0 - global.P0[2]) / global.V0[2];
        x = global.P0[0] + global.V0[0] * t;
        y = global.P0[1] + global.V0[1] * t;
        if (x >= 0 && x <= global.COLS && y >= 0 && y <= global.ROWS) {
            intersection[n] = t;
            n++;
        }

        // for side z = 127
        t = (127 - global.P0[2]) / global.V0[2];
        x = global.P0[0] + global.V0[0] * t;
        y = global.P0[1] + global.V0[1] * t;
        if (x >= 0 && x <= global.COLS && y >= 0 && y <= global.ROWS) {
            intersection[n] = t;
            n++;
        }

        // find more than two intersections
        if (n > 2) {
            n = 0;
        }

        // intersections found
        if (n != 0) {
            if (intersection[0] < intersection[1]) {
                t0 = intersection[0];
                t1 = intersection[1];
            } else {
                t1 = intersection[0];
                t0 = intersection[1];
            }
            global.ts[0] = t0;
            global.ts[1] = t1;
        }
        return n;
    }
}

Trilinear Interpolation

public class trilinear_interpolation {
    public static int x0, x1, y0, y1, z0, z1;
    public static double xd, yd, zd;
    public static double c000, c100, c001, c101, c010, c110, c011, c111;
    public static double c00, c01, c10, c11;
    public static double c0, c1;
    public static double c;
    public static double s, t;
    public static double main(int[][][] data, double x, double y, double z, String mark) {

        x0 = (int) x;
        x1 = x0 + 1;
        y0 = (int) y;
        y1 = y0 + 1;
        z0 = (int) z;
        z1 = z0 + 1;

        // return 0 if the point is outside the boundary
        if (x1 > 127 || x0 < 0 || y1 > 127 || y0 < 0 || z1 > 127 || z0 < 0)
            return 0;

        c000 = data[z1][y0][x0];
        c100 = data[z1][y0][x1];

        c001 = data[z1][y1][x0];
        c101 = data[z1][y1][x1];

        c010 = data[z0][y0][x0];
        c110 = data[z0][y0][x1];

        c011 = data[z0][y1][x0];
        c111 = data[z0][y1][x1];

        s = x - x0;
        t = 1.0 - s;

        c00 = c000 * t + c100 * s;
        c01 = c001 * t + c101 * s;
        c10 = c010 * t + c110 * s;
        c11 = c011 * t + c111 * s;

        s = z - z0;
        t = 1 - s;

        c0 = c10 * t + c00 * s;
        c1 = c11 * t + c01 * s;

        s = y - y0;
        t = 1 - s;
        c = c0 * t + c1 * s;

        if (mark == "opacity")
            return c / 255; // opacity being normalized in the range [0.0, 1.0]
        else
            return c;
    }
}

Volumn Ray Tracing

//Main Volume Ray-Tracing Function:
//Input:
// O – starting point of the ray
// V – unit-length vector pointing in the direction of the ray
// ts[0] and ts[1] are two points on the ray. Assuming
// ts[0] < ts[1]
//Output: the integrated shading value along the ray between
// ts[0] and ts[1]

public class volume_ray_tracing {
    public static int main() {

        double t, t0, t1;
        double x, y, z;
        double a, c;
        double dt = 1.0; // the interval for sampling along the ray
        double C = 0.0; // for accumulating the shading value
        double T = 1.0; // for accumulating the transparency

        t0 = global.ts[0];
        t1 = global.ts[1];

        /* Marching through the CT volume from t0 to t1 by step size dt. */
        /* Compute the 3D coordinates of the current sample position in the volume */

        for (t = t0; t <= t1; t += dt) {
            x = global.P0[0] + t * global.V0[0];
            y = global.P0[1] + t * global.V0[1];
            z = global.P0[2] + t * global.V0[2];
            /*
             * Obtain the shading value C and opacity value A from the shading volume and CT
             * volume, respectively, by using tri-linear interpolation.
             */
            // obtain opacity(density) value
            a = trilinear_interpolation.main(global.CT, x, y, z, "opacity");
            // obtain shading value c
            c = trilinear_interpolation.main(global.SHADING, x, y, z, "shading");

            /* Accumulate the shading values in the front-to-back order. */
            C += T * a * c;
            T *= (1.0 - a);
        }
        return (int) C;
    }
}

Profile picture

Personal blog by Chao Zhang.
The accumulation of technologies.

© 2022, Chao Zhang