boolean shadowTrace(Ray ray) {
      for (int i = 0; i < numObjects; i++)
        // Spheres only for now
        if (spheres[i].shadowHit(ray, 0.00001, 10000000, 0))
          if (scene.spheresOnly) {
            for (PMesh.SurfCell s = shapes[i].surfHead; s != null; s = s.next)
              for (PMesh.PolyCell poly = s.polyHead; poly != null; poly = poly.next)
                if (poly.numVerts == 3) {
                  Double3D v[] = new Double3D[3];
                  int j = 0;
                  for (PMesh.VertListCell vert = poly.vert; vert != null; vert = vert.next)
                    v[j++] = shapes[i].vertArray.get(vert.vert).viewPos;
                  // Increment j in the line post access

                  if (Triangle.shadowHit(v[0], v[1], v[2], ray, 0.00001, 10000000, 0)) return false;
                } else
                  System.out.println(
                      "Need to intersect polygon with " + poly.numVerts + " vertices.");
          } else return false;

      return true;
    }
    // All rays we deal with here are in world coordinates.
    // Should take the refractive index of the material it is currently in.
    DoubleColor trace(Ray ray) {
      DoubleColor color = new DoubleColor(0.0, 0.0, 0.0, 1.0);
      HitRecord hit = new HitRecord();

      if (depth > Math.max(DEBUG_recursion, scene.maxRecursiveDepth)) return color;

      double tMin = 0.0001;
      double tMax = 10000000;

      // Spheres only for now
      for (int i = 0; i < numObjects; i++)
        // Did I hit the bounding sphere for an object?
        if (spheres[i].hit(ray, tMin, tMax, 0, hit))
          if (scene.spheresOnly) {
            for (PMesh.SurfCell s = shapes[i].surfHead; s != null; s = s.next)
              for (PMesh.PolyCell poly = s.polyHead; poly != null; poly = poly.next)
                // Triangles only for now
                if (poly.numVerts == 3) {
                  Double3D v[] = new Double3D[3];
                  int j = 0;
                  for (PMesh.VertListCell vert = poly.vert; vert != null; vert = vert.next)
                    v[j++] = shapes[i].vertArray.get(vert.vert).viewPos;
                  // Increment j in the line post access

                  // Check for a hit on this polygon
                  if (Triangle.hit(v[0], v[1], v[2], ray, tMin, tMax, 0, hit)) {
                    tMax = hit.t;

                    hit.normal = poly.viewNorm;
                    hit.matIndex = s.material;
                    hit.index = i;
                  }
                } else
                  System.out.println(
                      "Need to intersect polygon with " + poly.numVerts + " vertices.");
          } else {
            tMax = hit.t;
            hit.matIndex = i; // May cause an error if object 10 and it only has 3 materials.
            hit.index = i;
          }

      if (hit.index >= 0) // If it intersects then multi-sample
      {
        if (!sampled && depth == 0) {
          // Only sample once per ray from the main loop
          sampled = true;

          Double3D dir = ray.dir;
          DoubleColor antiAlias = trace(ray);

          for (int i = 0; i < samples; i++) {
            // Double3D sample = new Double3D(dir.x + imageSamples[i].x, dir.y + imageSamples[i].y,
            // dir.z).getUnit();
            // ray.dir = sample;
            ray.dir.x = dir.x + imageSamples[i].x;
            ray.dir.y = dir.y + imageSamples[i].y;

            antiAlias.plus(trace(ray));
          }
          antiAlias.scale(1.0 / (samples + 1.0));

          color.plus(antiAlias);
        } else if (hit.matIndex < shapes[hit.index].materials.length)
          color = shade(ray, hit, shapes[hit.index].materials[hit.matIndex], false);
        else
          color =
              shade(
                  ray,
                  hit,
                  shapes[hit.index].materials[shapes[hit.index].materials.length - 1],
                  false);
      } else // We hit nothing check for intersection with the far clip plane for checker board
      // pattern.
      if (scene.checkerBackground) color = shade(ray, hit, checkerBackgroundHit(ray, hit), true);

      return color;
    }