| #pragma once |
|
|
| #include <gpu/common.h> |
|
|
| namespace cubvh { |
|
|
| |
| struct Triangle { |
|
|
| __host__ __device__ Eigen::Vector3f sample_uniform_position(const Eigen::Vector2f& sample) const { |
| float sqrt_x = std::sqrt(sample.x()); |
| float factor0 = 1.0f - sqrt_x; |
| float factor1 = sqrt_x * (1.0f - sample.y()); |
| float factor2 = sqrt_x * sample.y(); |
|
|
| return factor0 * a + factor1 * b + factor2 * c; |
| } |
|
|
| __host__ __device__ float surface_area() const { |
| return 0.5f * Eigen::Vector3f((b - a).cross(c - a)).norm(); |
| } |
|
|
| __host__ __device__ Eigen::Vector3f normal() const { |
| Eigen::Vector3f n = (b - a).cross(c - a); |
| float norm = n.norm(); |
| if (norm > 1e-12f) { |
| return n / norm; |
| } |
| return Eigen::Vector3f::Zero(); |
| } |
|
|
| __host__ __device__ float ray_intersect(const Eigen::Vector3f &ro, const Eigen::Vector3f &rd, Eigen::Vector3f& n) const { |
| Eigen::Vector3f v1v0 = b - a; |
| Eigen::Vector3f v2v0 = c - a; |
| Eigen::Vector3f rov0 = ro - a; |
| n = v1v0.cross( v2v0 ); |
| Eigen::Vector3f q = rov0.cross( rd ); |
| float d = safe_divide(1.0f, rd.dot(n)); |
| float u = d*-q.dot( v2v0 ); |
| float v = d* q.dot( v1v0 ); |
| float t = d*-n.dot( rov0 ); |
| if( u<0.0f || u>1.0f || v<0.0f || (u+v)>1.0f || t<0.0f) t = 1e6f; |
| return t; |
| } |
|
|
| __host__ __device__ float ray_intersect(const Eigen::Vector3f &ro, const Eigen::Vector3f &rd) const { |
| Eigen::Vector3f n; |
| return ray_intersect(ro, rd, n); |
| } |
|
|
| __host__ __device__ float distance_sq(const Eigen::Vector3f& pos) const { |
| |
| Eigen::Vector3f v21 = b - a; Eigen::Vector3f p1 = pos - a; |
| Eigen::Vector3f v32 = c - b; Eigen::Vector3f p2 = pos - b; |
| Eigen::Vector3f v13 = a - c; Eigen::Vector3f p3 = pos - c; |
| Eigen::Vector3f nor = v21.cross(v13); |
|
|
| return |
| |
| (sign(v21.cross(nor).dot(p1)) + sign(v32.cross(nor).dot(p2)) + sign(v13.cross(nor).dot(p3)) < 2.0f) |
| ? |
| |
| std::min( |
| std::min( |
| (v21 * clamp(v21.dot(p1) / v21.squaredNorm(), 0.0f, 1.0f)-p1).squaredNorm(), |
| (v32 * clamp(v32.dot(p2) / v32.squaredNorm(), 0.0f, 1.0f)-p2).squaredNorm() |
| ), |
| (v13 * clamp(v13.dot(p3) / v13.squaredNorm(), 0.0f, 1.0f)-p3).squaredNorm() |
| ) |
| : |
| |
| nor.dot(p1)*nor.dot(p1)/nor.squaredNorm(); |
| } |
|
|
| __host__ __device__ float distance(const Eigen::Vector3f& pos) const { |
| return std::sqrt(distance_sq(pos)); |
| } |
|
|
| __host__ __device__ bool point_in_triangle(const Eigen::Vector3f& p) const { |
| |
| |
| Eigen::Vector3f local_a = a - p; |
| Eigen::Vector3f local_b = b - p; |
| Eigen::Vector3f local_c = c - p; |
|
|
| |
| |
| |
| |
|
|
| |
| |
| |
| |
|
|
| Eigen::Vector3f u = local_b.cross(local_c); |
| Eigen::Vector3f v = local_c.cross(local_a); |
| Eigen::Vector3f w = local_a.cross(local_b); |
|
|
| |
| |
| if (u.dot(v) < 0.0f) { |
| return false; |
| } |
| if (u.dot(w) < 0.0f) { |
| return false; |
| } |
|
|
| |
| return true; |
| } |
|
|
| __host__ __device__ Eigen::Vector3f closest_point_to_line(const Eigen::Vector3f& a, const Eigen::Vector3f& b, const Eigen::Vector3f& c) const { |
| Eigen::Vector3f ab = b - a; |
| float denom = ab.squaredNorm(); |
| if (denom <= 1e-12f) { |
| return a; |
| } |
| float t = (c - a).dot(ab) / denom; |
| t = clamp(t, 0.0f, 1.0f); |
| return a + t * ab; |
| } |
|
|
| __host__ __device__ Eigen::Vector3f closest_point(Eigen::Vector3f point) const { |
| Eigen::Vector3f ab = b - a; |
| Eigen::Vector3f ac = c - a; |
| Eigen::Vector3f n = ab.cross(ac); |
| float norm_sq = n.squaredNorm(); |
| if (norm_sq > 1e-12f) { |
| float dist = n.dot(point - a) / norm_sq; |
| point -= dist * n; |
| } |
|
|
| if (point_in_triangle(point)) { |
| return point; |
| } |
|
|
| Eigen::Vector3f c1 = closest_point_to_line(a, b, point); |
| Eigen::Vector3f c2 = closest_point_to_line(b, c, point); |
| Eigen::Vector3f c3 = closest_point_to_line(c, a, point); |
|
|
| float mag1 = (point - c1).squaredNorm(); |
| float mag2 = (point - c2).squaredNorm(); |
| float mag3 = (point - c3).squaredNorm(); |
|
|
| float min = std::min(mag1, mag2); |
| min = std::min(min, mag3); |
|
|
| if (min == mag1) { |
| return c1; |
| } |
| else if (min == mag2) { |
| return c2; |
| } |
| return c3; |
| } |
|
|
| __host__ __device__ Eigen::Vector3f barycentric(const Eigen::Vector3f& p) const { |
| Eigen::Vector3f v0 = b - a; |
| Eigen::Vector3f v1 = c - a; |
| Eigen::Vector3f v2 = p - a; |
|
|
| float d00 = v0.dot(v0); |
| float d01 = v0.dot(v1); |
| float d11 = v1.dot(v1); |
| float d20 = v2.dot(v0); |
| float d21 = v2.dot(v1); |
|
|
| float denom = d00 * d11 - d01 * d01; |
| if (fabsf(denom) < 1e-12f) { |
| float ab = (b - a).squaredNorm(); |
| float bc = (c - b).squaredNorm(); |
| float ca = (a - c).squaredNorm(); |
| const float eps = 1e-12f; |
|
|
| if (ab >= bc && ab >= ca && ab > eps) { |
| float t = clamp((p - a).dot(b - a) / ab, 0.0f, 1.0f); |
| return Eigen::Vector3f(1.0f - t, t, 0.0f); |
| } |
| if (bc >= ca && bc > eps) { |
| float t = clamp((p - b).dot(c - b) / bc, 0.0f, 1.0f); |
| return Eigen::Vector3f(0.0f, 1.0f - t, t); |
| } |
| if (ca > eps) { |
| float t = clamp((p - c).dot(a - c) / ca, 0.0f, 1.0f); |
| return Eigen::Vector3f(t, 0.0f, 1.0f - t); |
| } |
| return Eigen::Vector3f(1.0f, 0.0f, 0.0f); |
| } |
|
|
| float v = (d11 * d20 - d01 * d21) / denom; |
| float w = (d00 * d21 - d01 * d20) / denom; |
| float u = 1.0f - v - w; |
|
|
| return Eigen::Vector3f(u, v, w); |
| } |
|
|
| __host__ __device__ Eigen::Vector3f centroid() const { |
| return (a + b + c) / 3.0f; |
| } |
|
|
| __host__ __device__ float centroid(int axis) const { |
| return (a[axis] + b[axis] + c[axis]) / 3; |
| } |
|
|
| __host__ __device__ void get_vertices(Eigen::Vector3f v[3]) const { |
| v[0] = a; |
| v[1] = b; |
| v[2] = c; |
| } |
|
|
| Eigen::Vector3f a, b, c; |
| int64_t id; |
| }; |
|
|
|
|
| inline std::ostream& operator<<(std::ostream& os, const Triangle& triangle) { |
| os << "["; |
| os << "a=[" << triangle.a.x() << "," << triangle.a.y() << "," << triangle.a.z() << "], "; |
| os << "b=[" << triangle.b.x() << "," << triangle.b.y() << "," << triangle.b.z() << "], "; |
| os << "c=[" << triangle.c.x() << "," << triangle.c.y() << "," << triangle.c.z() << "]"; |
| os << "]"; |
| return os; |
| } |
|
|
|
|
| } |