File size: 7,566 Bytes
6b92ff7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | #pragma once
#include <gpu/common.h>
namespace cubvh {
// Triangle data structure
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 { // based on https://www.iquilezles.org/www/articles/intersectors/intersectors.htm
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; // Eigen::Vector3f( t, u, v );
}
__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 {
// prepare data
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
// inside/outside test
(sign(v21.cross(nor).dot(p1)) + sign(v32.cross(nor).dot(p2)) + sign(v13.cross(nor).dot(p3)) < 2.0f)
?
// 3 edges
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()
)
:
// 1 face
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 {
// Move the triangle so that the point becomes the
// triangles origin
Eigen::Vector3f local_a = a - p;
Eigen::Vector3f local_b = b - p;
Eigen::Vector3f local_c = c - p;
// The point should be moved too, so they are both
// relative, but because we don't use p in the
// equation anymore, we don't need it!
// p -= p;
// Compute the normal vectors for triangles:
// u = normal of PBC
// v = normal of PCA
// w = normal of PAB
Eigen::Vector3f u = local_b.cross(local_c);
Eigen::Vector3f v = local_c.cross(local_a);
Eigen::Vector3f w = local_a.cross(local_b);
// Test to see if the normals are facing
// the same direction, return false if not
if (u.dot(v) < 0.0f) {
return false;
}
if (u.dot(w) < 0.0f) {
return false;
}
// All normals facing the same way, return true
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;
}
} |