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);
}