23int ray_box_intersection(
const ray<T, 3>& ray, fvec<T, 3> extent, fvec<T, 2>& out_ts, fvec<T, 3>* out_normal = 
nullptr) {
 
   25    fvec<T, 3> m = fvec<T, 3>(T(1)) / ray.direction; 
 
   26    fvec<T, 3> n = m * ray.origin;   
 
   27    fvec<T, 3> k = abs(m) * extent;
 
   28    fvec<T, 3> t1 = -n - k;
 
   29    fvec<T, 3> t2 = -n + k;
 
   30    T t_near = std::max(std::max(t1.x(), t1.y()), t1.z());
 
   31    T t_far = std::min(std::min(t2.x(), t2.y()), t2.z());
 
   33    if(t_near > t_far || t_far < T(0))
 
   40        *out_normal = -sign(ray.direction)
 
   41        * step(fvec<T, 3>(t1.y(), t1.z(), t1.x()), fvec<T, 3>(t1.x(), t1.y(), t1.z()))
 
   42        * step(fvec<T, 3>(t1.z(), t1.x(), t1.y()), fvec<T, 3>(t1.x(), t1.y(), t1.z()));
 
   57int ray_box_intersection(
const ray<T, 3> &ray, 
const fvec<T, 3> &min, 
const fvec<T, 3> &max, fvec<T, 2>& out_ts) {
 
   59    fvec<T, 3> t0 = (min - ray.origin) / ray.direction;
 
   60    fvec<T, 3> t1 = (max - ray.origin) / ray.direction;
 
   63        std::swap(t0.x(), t1.x());
 
   66        std::swap(t0.y(), t1.y());
 
   69        std::swap(t0.z(), t1.z());
 
   71    if(t0.x() > t1.y() || t0.y() > t1.x() ||
 
   72        t0.x() > t1.z() || t0.z() > t1.x() ||
 
   73        t0.z() > t1.y() || t0.y() > t1.z())
 
   76    T t_near = std::max(std::max(t0.x(), t0.y()), t0.z());
 
   77    T t_far = std::min(std::min(t1.x(), t1.y()), t1.z());
 
   80        std::swap(t_near, t_far);
 
  100int ray_cylinder_intersection(
const ray<T, 3>& ray, 
const fvec<T, 3>& position, 
const fvec<T, 3>& axis, T radius, T& out_t, fvec<T, 3>* out_normal = 
nullptr) {
 
  102    fvec<T, 3> oc = ray.origin - position;
 
  103    T caca = dot(axis, axis);
 
  104    T card = dot(axis, ray.direction);
 
  105    T caoc = dot(axis, oc);
 
  106    T a = caca - card * card;
 
  107    T b = caca * dot(oc, ray.direction) - caoc * card;
 
  108    T c = caca * dot(oc, oc) - caoc * caoc - radius * radius * caca;
 
  115    out_t = (-b - h) / a;
 
  118    T y = caoc + out_t * card;
 
  119    if(y > T(0) && y < caca) {
 
  121            *out_normal = (oc + out_t * ray.direction - axis * y / caca) / radius;
 
  126    out_t = ((y < T(0) ? T(0) : caca) - caoc) / card;
 
  127    if(std::abs(b + a * out_t) < h) {
 
  129            *out_normal = axis * sign(y) / caca;
 
  148int ray_cylinder_intersection2(
const ray<T, 3>& ray, 
const fvec<T, 3>& start_position, 
const fvec<T, 3>& end_position, T radius, T& out_t, fvec<T, 3>* out_normal = 
nullptr) {
 
  150    return ray_cylinder_intersection(ray, start_position, end_position - start_position, radius, out_t, out_normal);
 
  163int ray_plane_intersection(
const ray<T, 3>& ray, 
const fvec<T, 3>& origin, 
const fvec<T, 3>& normal, T& out_t) {
 
  165    T denom = dot(normal, ray.direction);
 
  166    if(std::abs(denom) < std::numeric_limits<T>::epsilon())
 
  169    out_t = dot(origin - ray.origin, normal) / denom;
 
  185int ray_axis_aligned_rectangle_intersection(
const ray<T, 3>& ray, 
const fvec<T, 3>& position, 
const fvec<T, 2>& extent, 
int axis_index, T& out_t, fvec<T, 2>* out_uv = 
nullptr) {
 
  187    assert(axis_index >= 0 && axis_index < 3);
 
  189    fvec<T, 3> normal = { T(0) };
 
  190    normal[axis_index] = T(1);
 
  192    T t = std::numeric_limits<T>::max();
 
  193    if(cgv::math::ray_plane_intersection(ray, position, normal, t)) {
 
  194        fvec<T, 3> intersection_position = ray.position(t);
 
  195        intersection_position -= position;
 
  200            uv[0] = intersection_position[1];
 
  201            uv[1] = intersection_position[2];
 
  204            uv[0] = intersection_position[0];
 
  205            uv[1] = intersection_position[2];
 
  208            uv[0] = intersection_position[0];
 
  209            uv[1] = intersection_position[1];
 
  215        uv += T(0.5) * extent;
 
  217        if(uv[0] >= T(0) && uv[0] <= extent.x() && uv[1] >= T(0) && uv[1] <= extent.y()) {
 
  220                *out_uv = uv / extent;
 
  241int ray_parallelogram_intersection(
const ray<T, 3>& ray, 
const fvec<T, 3>& origin, 
const fvec<T, 3> edge_u, 
const fvec<T, 3>& edge_v, T& out_t, fvec<T, 3>* out_normal = 
nullptr, fvec<T, 2>* out_uv = 
nullptr) {
 
  243    fvec<T, 3> normal = normalize(cross(edge_u, edge_v));
 
  251    T axy = edge_u.x() * edge_u.x() + edge_u.y() * edge_u.y();
 
  252    axy *= edge_v.x() * edge_v.x() + edge_v.y() * edge_v.y();
 
  255    T axz = edge_u.x() * edge_u.x() + edge_u.z() * edge_u.z();
 
  256    axz *= edge_v.x() * edge_v.x() + edge_v.z() * edge_v.z();
 
  259    T ayz = edge_u.y() * edge_u.y() + edge_u.z() * edge_u.z();
 
  260    ayz *= edge_v.y() * edge_v.y() + edge_v.z() * edge_v.z();
 
  267            sf = normal.z() < T(0) ? T(1) : -T(1);
 
  272            sf = normal.x() < T(0) ? T(1) : -T(1);
 
  279            sf = normal.y() < T(0) ? -T(1) : T(1);
 
  284            sf = normal.x() < T(0) ? T(1) : -T(1);
 
  288    T ndd = dot(normal, ray.direction);
 
  289    if(std::abs(ndd) < std::numeric_limits<T>::epsilon())
 
  292    T t = dot(normal, origin - ray.origin) / ndd;
 
  296    fvec<T, 3> x = ray.position(t);
 
  297    fvec<T, 2> x2d(x[ku] - origin[ku], x[kv] - origin[kv]);
 
  299    fvec<T, 2> e1(edge_u[ku], edge_u[kv]);
 
  300    fvec<T, 2> e2(edge_v[ku], edge_v[kv]);
 
  302    T s = e1.x() * x2d.y() - e1.y() * x2d.x();
 
  303    if(sf * s > -std::numeric_limits<T>::epsilon())
 
  306    s = e2.x() * x2d.y() - e2.y() * x2d.x();
 
  307    if(sf * s < std::numeric_limits<T>::epsilon())
 
  312    s = e1.y() * x2d.x() - e1.x() * x2d.y();
 
  313    if(sf * s > -std::numeric_limits<T>::epsilon())
 
  316    s = e2.y() * x2d.x() - e2.x() * x2d.y();
 
  317    if(sf * s < std::numeric_limits<T>::epsilon())
 
  323        *out_normal = normal;
 
  327        uv.x() /= length(e1);
 
  328        uv.y() /= length(e2);
 
  348int ray_rectangle_intersection(
const ray<T, 3>& ray, 
const fvec<T, 3>& position, 
const fvec<T, 2> extent, 
const quaternion<T>& rotation, T& out_t, fvec<T, 3>* out_normal = 
nullptr, fvec<T, 2>* out_uv = 
nullptr) {
 
  351    fvec<T, 3> tangent = { T(1), T(0), T(0) };
 
  352    fvec<T, 3> bitangent = { T(0), T(1), T(0) };
 
  354    tangent = rotation.apply(tangent);
 
  355    bitangent = rotation.apply(bitangent);
 
  357    fvec<T, 3> corner = position - T(0.5) * extent.x() * tangent - T(0.5) * extent.y() * bitangent;
 
  359    fvec<T, 3> edge_u = extent.x() * tangent;
 
  360    fvec<T, 3> edge_v = extent.y() * bitangent;
 
  362    return ray_parallelogram_intersection(ray, corner, edge_u, edge_v, out_t, out_normal, out_uv);
 
  375int ray_sphere_intersection(
const ray<T, 3>& ray, 
const fvec<T, 3>& center, T radius, fvec<T, 2>& out_ts) {
 
  377    fvec<T, 3> d = ray.origin - center;
 
  378    T il = T(1) / dot(ray.direction, ray.direction);
 
  379    T b = il * dot(d, ray.direction);
 
  380    T c = il * (dot(d, d) - radius * radius);
 
  386    if(D < std::numeric_limits<T>::epsilon()) {
 
  409int first_ray_sphere_intersection(
const ray<T, 3>& ray, 
const fvec<T, 3>& center, T radius, T& out_t, fvec<T, 3>* out_normal = 
nullptr) {
 
  412    int k = ray_sphere_intersection(ray, center, radius, ts);
 
  414    if(k == 1 || (k == 2 && ts[0] > T(0)))
 
  416    else if(k == 2 && ts[1] > T(0))
 
  422        *out_normal = normalize(ray.position(out_t) - center);
 
  438int ray_torus_intersection(
const ray<T, 3>& ray, T large_radius, T small_radius, T& out_t, fvec<T, 3>* out_normal = 
nullptr) {
 
  441    T Ra2 = large_radius * large_radius;
 
  442    T ra2 = small_radius * small_radius;
 
  443    T m = dot(ray.origin, ray.origin);
 
  444    T n = dot(ray.origin, ray.direction);
 
  445    T k = (m + Ra2 - ra2) / T(2);
 
  447    const fvec<T, 2>& ro_xy = 
reinterpret_cast<const fvec<T, 2>&
>(ray.origin);
 
  448    const fvec<T, 2>& rd_xy = 
reinterpret_cast<const fvec<T, 2>&
>(ray.direction);
 
  449    T k2 = n * n - Ra2 * dot(rd_xy, rd_xy) + k;
 
  450    T k1 = n * k - Ra2 * dot(rd_xy, ro_xy);
 
  451    T k0 = k * k - Ra2 * dot(ro_xy, ro_xy);
 
  453    if(std::abs(k3 * (k3 * k3 - k2) + k1) < T(0.01)) {
 
  455        T tmp = k1; k1 = k3; k3 = tmp;
 
  462    T c2 = k2 * T(2) - T(3) * k3 * k3;
 
  463    T c1 = k3 * (k3 * k3 - k2) + k1;
 
  464    T c0 = k3 * (k3 * (c2 + T(2) * k2) - T(8) * k1) + T(4) * k0;
 
  469    T R = c2 * c2 * c2 - T(3) * c2 * c0 + c1 * c1;
 
  470    T h = R * R - Q * Q * Q;
 
  474        T v = sign(R + h) * std::pow(std::abs(R + h), T(1) / T(3)); 
 
  475        T u = sign(R - h) * std::pow(std::abs(R - h), T(1) / T(3)); 
 
  476        fvec<T, 2> s = fvec<T, 2>((v + u) + T(4) * c2, (v - u) * std::sqrt(T(3)));
 
  477        T y = std::sqrt(T(0.5) * (length(s) + s.x()));
 
  478        T x = T(0.5) * s.y() / y;
 
  479        T r = T(2) * c1 / (x * x + y * y);
 
  480        T t1 = x - r - k3; t1 = (po < T(0)) ? T(2) / t1 : t1;
 
  481        T t2 = -x - r - k3; t2 = (po < T(0)) ? T(2) / t2 : t2;
 
  483        if(t1 > T(0)) out_t = t1;
 
  484        if(t2 > T(0)) out_t = std::min(out_t, t2);
 
  487            fvec<T, 3> pos = ray.position(out_t);
 
  488            *out_normal = normalize(pos * ((dot(pos, pos) - ra2) * fvec<T, 3>(T(1)) - Ra2 * fvec<T, 3>(T(1), T(1), T(-1))));
 
  495    T w = sQ * cos(acos(-R / (sQ * Q)) / T(3));
 
  501    T d1 = std::sqrt(d2);
 
  502    T h1 = std::sqrt(w - T(2) * c2 + c1 / d1);
 
  503    T h2 = std::sqrt(w - T(2) * c2 - c1 / d1);
 
  504    T t1 = -d1 - h1 - k3; t1 = (po < T(0)) ? T(2) / t1 : t1;
 
  505    T t2 = -d1 + h1 - k3; t2 = (po < T(0)) ? T(2) / t2 : t2;
 
  506    T t3 = d1 - h2 - k3;  t3 = (po < T(0)) ? T(2) / t3 : t3;
 
  507    T t4 = d1 + h2 - k3;  t4 = (po < T(0)) ? T(2) / t4 : t4;
 
  509    if (t1 > T(0)) out_t = t1;
 
  510    if (t2 > T(0)) out_t = std::min(out_t, t2);
 
  511    if (t3 > T(0)) out_t = std::min(out_t, t3);
 
  512    if (t4 > T(0)) out_t = std::min(out_t, t4);
 
  515        fvec<T, 3> pos = ray.position(out_t);
 
  516        *out_normal = normalize(pos * ((dot(pos, pos) - ra2) * fvec<T, 3>(T(1)) - Ra2 * fvec<T, 3>(T(1), T(1), T(-1))));
 
  535int ray_torus_intersection(
const ray<T, 3>& ray, 
const fvec<T, 3>& center, 
const fvec<T, 3>& normal, T large_radius, T small_radius, T& out_t, fvec<T, 3>* out_normal = 
nullptr) {
 
  540    fvec<T, 3>& x = 
reinterpret_cast<fvec<T, 3>&
>(pose[0]);
 
  541    fvec<T, 3>& y = 
reinterpret_cast<fvec<T, 3>&
>(pose[3]);
 
  542    fvec<T, 3>& z = 
reinterpret_cast<fvec<T, 3>&
>(pose[6]);
 
  545    int i = std::abs(normal[0]) < std::abs(normal[1]) ? 0 : 1;
 
  546    i = std::abs(normal[i]) < std::abs(normal[2]) ? i : 2;
 
  548    y = normalize(cross(normal, x));
 
  549    x = cross(y, normal);
 
  556    int res = ray_torus_intersection(transformed_ray, large_radius, small_radius, out_t, out_normal);
 
This class defines a template for n-dimensional rays with arbitrary data type defined by origin and d...
cgv::math::fvec< float, 2 > vec2
declare type of 2d single precision floating point vectors
helper functions to work with poses that can be represented with 3x4 matrix or quaternion plus vector
fvec< T, 3 > pose_transform_vector(const fmat< T, 3, 4 > &pose, const fvec< T, 3 > &v)
transform vector with pose matrix
fvec< T, 3 > & pose_position(fmat< T, 3, 4 > &pose)
extract position vector from pose matrix
fvec< T, 3 > inverse_pose_transform_vector(const fmat< T, 3, 4 > &pose, const fvec< T, 3 > &v)
transform vector with inverse of pose matrix
fvec< T, 3 > inverse_pose_transform_point(const fmat< T, 3, 4 > &pose, const fvec< T, 3 > &p)
transform point with inverse of pose matrix