#include #include #include struct Point3D { float x, y, z; }; struct Triangle { Point3D v0, v1, v2; }; __device__ Point3D cross(const Point3D& v1, const Point3D& v2) { Point3D result; result.x = v1.y * v2.z - v1.z * v2.y; result.y = v1.z * v2.x - v1.x * v2.z; result.z = v1.x * v2.y - v1.y * v2.x; return result; } // Compute the dot product of two vectors __device__ float dot(const Point3D& v1, const Point3D& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } // Subtract two 3D points (vector subtraction) __device__ Point3D subtract(const Point3D& p1, const Point3D& p2) { Point3D result = {p1.x - p2.x, p1.y - p2.y, p1.z - p2.z}; return result; } __device__ float magnitude(const Point3D &v) { return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); } __device__ bool is_identical(const Point3D & p1, const Point3D & p2){ Point3D check = subtract(p1, p2); if(check.x==0 && check.y == 0 && check.z == 0) return true; return false; } // Compute the squared distance between two points __device__ float squaredDistance(const Point3D& p1, const Point3D& p2) { return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) + (p1.z - p2.z) * (p1.z - p2.z); } __device__ Point3D normalize(Point3D v){ float len = sqrtf(dot(v, v)); if (len ==0) return v; float scale = 1 / len; Point3D result = {v.x * scale, v.y * scale, v.z * scale}; return result; } __device__ float point_to_line_distance(const Point3D &p, const Point3D &v0, const Point3D &v1) { // Direction vector of the line Point3D d = subtract(v1, v0); // Vector from v0 to point p Point3D v0_to_p = subtract(p, v0); // Scalar projection of v0_to_p onto the direction vector d float t = dot(v0_to_p, d) / dot(d, d); Point3D closest_point; // Check where the projection falls if (t < 0) { // Projection falls before v0, so the closest point is v0 closest_point = v0; } else if (t > 1) { // Projection falls beyond v1, so the closest point is v1 closest_point = v1; } else { // Projection falls within the segment, compute the projection point closest_point.x = v0.x + t * d.x; closest_point.y = v0.y + t * d.y; closest_point.z = v0.z + t * d.z; } // Calculate the distance between p and the closest point Point3D closest_to_p = subtract(p, closest_point); return magnitude(closest_to_p); } // Compute the distance between a point and a triangle face __device__ float pointToTriangleDistance(const Point3D& queryPoint, const Point3D& v0, const Point3D& v1, const Point3D& v2, bool inverse=false) { // Edge vectors Point3D edge0 = subtract(v1, v0); Point3D edge1 = subtract(v2, v0); if (is_identical(v0, v1) && is_identical(v0, v2)) return sqrtf(squaredDistance(queryPoint, v0)); if (is_identical(v0, v1)) return point_to_line_distance(queryPoint, v0, v2); if (is_identical(v0, v2)) return point_to_line_distance(queryPoint, v0, v1); if (is_identical(v1, v2)) return point_to_line_distance(queryPoint, v0, v1); // Normal vector to the triangle plane Point3D normal = cross(edge0, edge1); if (inverse) normal = cross(edge1, edge0); // Vector from v0 to queryPoint Point3D queryVec = subtract(queryPoint, v0); if (dot(normal, normal)==0) return sqrtf(dot(queryVec, queryVec)); normal = normalize(normal); //return 1.0; // Project the query point onto the triangle's plane float distanceToPlane = dot(normal, queryVec); // / sqrtf(dot(normal, normal)); // return fabsf(distanceToPlane); Point3D projectionPoint = { queryPoint.x - distanceToPlane * normal.x, queryPoint.y - distanceToPlane * normal.y, queryPoint.z - distanceToPlane * normal.z }; // Check if the projection point is inside the triangle using barycentric coordinates edge0 = subtract(v0, v1); edge1 = subtract(v1, v2); Point3D edge2 = subtract(v2, v0); Point3D projVec0 = subtract(v0, projectionPoint); Point3D projVec1 = subtract(v1, projectionPoint); Point3D projVec2 = subtract(v2, projectionPoint); Point3D c0 = cross(edge0, projVec0); Point3D c1 = cross(edge1, projVec1); Point3D c2 = cross(edge2, projVec2); if (dot(c0, c1) > 0 && dot(c1, c2) > 0 && dot(c0, c2) > 0) return fabsf(distanceToPlane); // Otherwise, return the minimum distance to the triangle's edges float minEdgeDistance = 1e6f; minEdgeDistance = fmin(minEdgeDistance, point_to_line_distance(queryPoint, v0, v1)); minEdgeDistance = fmin(minEdgeDistance, point_to_line_distance(queryPoint, v0, v2)); minEdgeDistance = fmin(minEdgeDistance, point_to_line_distance(queryPoint, v1, v2)); return minEdgeDistance; } __device__ void updateUDF(Triangle t, int* udf, const int DIM, const float threshold) { // Compute the bounding box of the triangle float minX = fminf(fminf(t.v0.x, t.v1.x), t.v2.x); float minY = fminf(fminf(t.v0.y, t.v1.y), t.v2.y); float minZ = fminf(fminf(t.v0.z, t.v1.z), t.v2.z); float maxX = fmaxf(fmaxf(t.v0.x, t.v1.x), t.v2.x); float maxY = fmaxf(fmaxf(t.v0.y, t.v1.y), t.v2.y); float maxZ = fmaxf(fmaxf(t.v0.z, t.v1.z), t.v2.z); // Convert bounding box to grid coordinates int iMin = max(0, (int)floorf((minX + 0.5) * (DIM-1))); int jMin = max(0, (int)floorf((minY + 0.5) * (DIM-1))); int kMin = max(0, (int)floorf((minZ + 0.5) * (DIM-1))); int iMax = min(DIM - 1, (int)floorf((maxX + 0.5) * (DIM-1))); int jMax = min(DIM - 1, (int)floorf((maxY + 0.5) * (DIM-1))); int kMax = min(DIM - 1, (int)floorf((maxZ + 0.5) * (DIM-1))); int range = (int)(threshold + 1); // Make the bounding box larger than the original iMax = min(DIM - 1, iMax + range); iMin = max(0, iMin - range); jMax = min(DIM - 1, jMax + range); jMin = max(0, jMin - range); kMax = min(DIM - 1, kMax + range); kMin = max(0, kMin - range); // Update the valid grids within the bounding box for (int i = iMin; i <= iMax; ++i) { for (int j = jMin; j <= jMax; ++j) { for (int k = kMin; k <= kMax; ++k) { int idx = i * DIM * DIM + j * DIM + k; // Compute the distance from the query point to the triangle Point3D queryPoint = {(float)i/(DIM-1) - 0.5, (float)j/(DIM-1) - 0.5, (float)k/(DIM-1) -0.5}; float distance = pointToTriangleDistance(queryPoint, t.v0, t.v1, t.v2); float distance2 = pointToTriangleDistance(queryPoint, t.v0, t.v1, t.v2, true); if (distance < threshold / DIM or distance2 < threshold / DIM){ //distance = distance2; int int_dist = (int)(distance * 10000000); atomicMin(&udf[idx], int_dist); } } } } } __global__ void compute_udf_kernel(float* vertices, int* faces, int * udf, int numTriangles, const int DIM, const float threshold) { int t = blockIdx.x * blockDim.x + threadIdx.x; if (t < numTriangles) { int f0 = faces[t * 3 + 0]; int f1 = faces[t * 3 + 1]; int f2 = faces[t * 3 + 2]; Point3D v0 = {vertices[f0 * 3 + 0], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2]}; Point3D v1 = {vertices[f1 * 3 + 0], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2]}; Point3D v2 = {vertices[f2 * 3 + 0], vertices[f2 * 3 + 1], vertices[f2 * 3 + 2]}; Triangle triangle = {v0, v1, v2}; updateUDF(triangle, udf, DIM, threshold); } } void compute_valid_udf_cuda(float* vertices, int* faces, int* udf, int numTriangles, const int DIM=512, const float threshold=8) { int blockSize = 256; int gridSize = (numTriangles + blockSize - 1) / blockSize; // Launch the kernel compute_udf_kernel<<>>(vertices, faces, udf, numTriangles, DIM, threshold); }