cv::Vec4f traceRayToGetColor()

in source/rig/RigSimulator.cpp [195:261]


cv::Vec4f traceRayToGetColor(
    const Ray& ray,
    const std::vector<Triangle>& triangles,
    const BoundingVolumeHierarchy& bvh,
    const cv::Mat_<cv::Vec3b>& skybox) {
  // intersect with geometry in bvh
  RayIntersectionResult intersectionResult = raytraceBVH(ray, bvh);

  // intersect with a textured rectangle above the rig
  if (!FLAGS_ceiling_path.empty()) {
    // solve r(depth).z = ceiling_position <=>
    const float depth = (FLAGS_ceiling_position - ray.origin[2]) / ray.dir[2];
    if (0 < depth && depth < intersectionResult.dist) {
      cv::Vec3f p = ray.origin + depth * ray.dir;
      float s = p[0] / FLAGS_ceiling_width + 0.5;
      float t = p[1] / FLAGS_ceiling_depth + 0.5;
      if (0 <= s && s < 1 && 0 <= t && t < 1) {
        // ceiling is hit, return the color
        static cv::Mat_<cv::Vec3b> ceiling =
            cv_util::imreadExceptionOnFail(FLAGS_ceiling_path, cv::IMREAD_COLOR);
        cv::Vec3f color = ceiling(t * ceiling.rows, s * ceiling.cols);
        return cv::Vec4f(color[0] / 255, color[1] / 255, color[2] / 255, depth);
      }
    }
  }

  // if nothing else was hit, intersect with sky equirect
  if (!intersectionResult.hit) {
    const float phi = acos(math_util::clamp(
        ray.dir[2], -1.0f, 1.0f)); // the min here is to avoid a nan.. other numerics can result in
                                   // a value that is epsilon > 1.0 being passed here
    const float theta = M_PI + atan2(ray.dir[1], ray.dir[0]);
    const float sampleX = (theta / (2.0 * M_PI)) * skybox.cols;
    const float sampleY = (phi / M_PI) * skybox.rows;
    const cv::Vec3b skyColor =
        skybox(std::min(int(sampleY), skybox.rows - 1), int(sampleX) % skybox.cols);
    return cv::Vec4f(
        skyColor[0] / 255.0f,
        skyColor[1] / 255.0f,
        skyColor[2] / 255.0f,
        std::numeric_limits<float>::max());
  }

  assert(
      intersectionResult.hitObjectIdx >=
      0); // if this fails, we probably forgot to bind the triangle indices in Triangle::selfIdx
  cv::Vec3f baseColor = triangles[intersectionResult.hitObjectIdx].color;
  const cv::Vec3f& normal = triangles[intersectionResult.hitObjectIdx].normal;
  const cv::Vec3f intersectionPoint = ray.origin + intersectionResult.dist * ray.dir;

  if (FLAGS_marble) {
    baseColor *= 0.7f +
        0.3f *
            std::fabs(perlin_noise::pnoise(
                FLAGS_marble_scale * intersectionPoint[0],
                FLAGS_marble_scale * intersectionPoint[1],
                FLAGS_marble_scale * intersectionPoint[2]));
  }

  const static cv::Vec3f kLightPos(2.0f, 1.0f, 5.2f);
  cv::Vec3f lightDir = kLightPos - intersectionPoint;
  lightDir /= norm(lightDir);
  const float lightCoef = .25f + .75f * std::max(0.0f, normal.dot(lightDir));

  const cv::Vec3f shadedColor = baseColor * lightCoef;
  return cv::Vec4f(shadedColor[0], shadedColor[1], shadedColor[2], intersectionResult.dist);
}