@Override
    public void run() {
      // Always tracing from the origin here.
      Double3D origin = new Double3D(0.0, 0.0, 0.0);

      black.ka = new DoubleColor(0, 0, 0, 1);
      black.kd = new DoubleColor(0, 0, 0, 1);
      black.ks = new DoubleColor(0, 0, 0, 1);
      black.shiny = 0;
      black.refractiveIndex = 1;
      black.reflectivity = new DoubleColor(0, 0, 0, 1);
      black.refractivity = new DoubleColor(0, 0, 0, 1);

      white.ka = new DoubleColor(1, 1, 1, 1);
      white.kd = new DoubleColor(0, 0, 0, 1);
      white.ks = new DoubleColor(0, 0, 0, 1);
      white.shiny = 0;
      white.refractiveIndex = 1;
      white.reflectivity = new DoubleColor(0, 0, 0, 1);
      white.refractivity = new DoubleColor(0, 0, 0, 1);

      // Work though viewport (pixel) coordinates
      // Start in the middle of pixel 0
      double worldY = scene.camera.windowBottom + (yMin + startLine) * heightRatio;
      for (curY = (int) yMin + startLine; curY < yMax; curY = curY + THREADS) {
        worldY += THREADS * heightRatio;
        // Start in the middle of pixel 0
        double worldX = scene.camera.windowLeft + (xMin) * widthRatio;

        for (curX = (int) xMin; curX < xMax; curX++) {
          worldX += widthRatio;
          Double3D dir = new Double3D(worldX, worldY, -scene.camera.near);
          Ray ray = new Ray(origin, dir.getUnit());

          viewPort[curX][curY] = trace(ray);

          // We haven't sampled this pixel yet.
          if (!scene.antiAliasing) sampled = false;
        } // for y
      } // for x

      System.out.println("Thread " + startLine + " finished.");
    }