Negative volumes raycasting fix - normal was flipped between iterations, incorrect algorithm for hit detection

Debug files export fix after refactoring
This commit is contained in:
PavelMikus 2022-04-06 09:57:36 +02:00
parent 8ce36e9137
commit fb2621c03c
2 changed files with 26 additions and 21 deletions

View File

@ -146,13 +146,15 @@ std::vector<FaceVisibilityInfo> raycast_visibility(const AABBTreeIndirect::Tree<
std::vector<FaceVisibilityInfo> result(triangles.indices.size()); std::vector<FaceVisibilityInfo> result(triangles.indices.size());
tbb::parallel_for(tbb::blocked_range<size_t>(0, result.size()), tbb::parallel_for(tbb::blocked_range<size_t>(0, result.size()),
[&triangles, &precomputed_sample_directions, model_contains_negative_parts, negative_volumes_start_index, &raycasting_tree, &result](tbb::blocked_range<size_t> r) { [&triangles, &precomputed_sample_directions, model_contains_negative_parts, negative_volumes_start_index,
&raycasting_tree, &result](tbb::blocked_range<size_t> r) {
// Maintaining hits memory outside of the loop, so it does not have to be reallocated for each query. // Maintaining hits memory outside of the loop, so it does not have to be reallocated for each query.
std::vector<igl::Hit> hits; std::vector<igl::Hit> hits;
for (size_t face_index = r.begin(); face_index < r.end(); ++face_index) { for (size_t face_index = r.begin(); face_index < r.end(); ++face_index) {
FaceVisibilityInfo &dest = result[face_index]; FaceVisibilityInfo &dest = result[face_index];
dest.visibility = 1.0f; dest.visibility = 1.0f;
constexpr float decrease = 1.0f / (SeamPlacer::sqr_rays_per_triangle * SeamPlacer::sqr_rays_per_triangle); constexpr float decrease = 1.0f
/ (SeamPlacer::sqr_rays_per_triangle * SeamPlacer::sqr_rays_per_triangle);
Vec3i face = triangles.indices[face_index]; Vec3i face = triangles.indices[face_index];
Vec3f A = triangles.vertices[face.x()]; Vec3f A = triangles.vertices[face.x()];
@ -177,32 +179,35 @@ std::vector<FaceVisibilityInfo> raycast_visibility(const AABBTreeIndirect::Tree<
if (hit) { if (hit) {
dest.visibility -= decrease; dest.visibility -= decrease;
} }
} else { } else { //TODO improve logic for order based boolean operations - consider order of volumes
int in_negative = 0; Vec3d ray_origin_d = (center + normal * 0.1).cast<double>(); // start above surface.
if (face_index >= negative_volumes_start_index) { // if casting from negative volume face, invert direction if (face_index >= negative_volumes_start_index) { // if casting from negative volume face, invert direction, change start pos
final_ray_dir = -1.0 * final_ray_dir; final_ray_dir = -1.0 * final_ray_dir;
normal = -normal; ray_origin_d = (center - normal * 0.1).cast<double>();
} }
Vec3d final_ray_dir_d = final_ray_dir.cast<double>(); Vec3d final_ray_dir_d = final_ray_dir.cast<double>();
Vec3d ray_origin_d = (center + normal * 0.1).cast<double>(); // start above surface.
bool some_hit = AABBTreeIndirect::intersect_ray_all_hits(triangles.vertices, bool some_hit = AABBTreeIndirect::intersect_ray_all_hits(triangles.vertices,
triangles.indices, raycasting_tree, triangles.indices, raycasting_tree,
ray_origin_d, final_ray_dir_d, hits); ray_origin_d, final_ray_dir_d, hits);
if (some_hit) { if (some_hit) {
int in_negative = 0;
int in_positive = 0;
// NOTE: iterating in reverse, from the last hit for one simple reason: We know the state of the ray at that point; // NOTE: iterating in reverse, from the last hit for one simple reason: We know the state of the ray at that point;
// It cannot be inside model, and it cannot be inside negative volume // It cannot be inside model, and it cannot be inside negative volume
for (int hit_index = int(hits.size()) - 1; hit_index >= 0; --hit_index) { for (int hit_index = int(hits.size()) - 1; hit_index >= 0; --hit_index) {
Vec3f face_normal = its_face_normal(triangles, hits[hit_index].id);
if (hits[hit_index].id >= int(negative_volumes_start_index)) { //negative volume hit if (hits[hit_index].id >= int(negative_volumes_start_index)) { //negative volume hit
Vec3f normal = its_face_normal(triangles, hits[hit_index].id); in_negative += sgn(face_normal.dot(final_ray_dir)); // if volume face aligns with ray dir, we are leaving negative space
in_negative += sgn(normal.dot(final_ray_dir)); // if volume face aligns with ray dir, we are leaving negative space
// which in reverse hit analysis means, that we are entering negative space :) and vice versa // which in reverse hit analysis means, that we are entering negative space :) and vice versa
} else if (in_negative <= 0) { //object hit and we are not in negative space } else {
in_positive += sgn(face_normal.dot(final_ray_dir));
}
if (in_positive > 0 && in_negative <= 0) {
dest.visibility -= decrease; dest.visibility -= decrease;
break; break;
} }
} }
} }
} }
} }
} }
@ -747,9 +752,9 @@ struct SeamComparator {
; ;
#ifdef DEBUG_FILES #ifdef DEBUG_FILES
void debug_export_points(const std::vector<std::vector<SeamPlacerImpl::SeamCandidate>> &object_perimter_points, void debug_export_points(const std::vector<PrintObjectSeamData::LayerSeams> &layers,
const BoundingBox &bounding_box, std::string object_name, const SeamComparator &comparator) { const BoundingBox &bounding_box, std::string object_name, const SeamComparator &comparator) {
for (size_t layer_idx = 0; layer_idx < object_perimter_points.size(); ++layer_idx) { for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) {
std::string angles_file_name = debug_out_path( std::string angles_file_name = debug_out_path(
(object_name + "_angles_" + std::to_string(layer_idx) + ".svg").c_str()); (object_name + "_angles_" + std::to_string(layer_idx) + ".svg").c_str());
SVG angles_svg {angles_file_name, bounding_box}; SVG angles_svg {angles_file_name, bounding_box};
@ -759,7 +764,7 @@ void debug_export_points(const std::vector<std::vector<SeamPlacerImpl::SeamCandi
float min_weight = std::numeric_limits<float>::min(); float min_weight = std::numeric_limits<float>::min();
float max_weight = min_weight; float max_weight = min_weight;
for (const SeamCandidate &point : object_perimter_points[layer_idx]) { for (const SeamCandidate &point : layers[layer_idx].points) {
Vec3i color = value_rgbi(-PI, PI, point.local_ccw_angle); Vec3i color = value_rgbi(-PI, PI, point.local_ccw_angle);
std::string fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + "," std::string fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + ","
+ std::to_string(color.z()) + ")"; + std::to_string(color.z()) + ")";
@ -782,7 +787,7 @@ void debug_export_points(const std::vector<std::vector<SeamPlacerImpl::SeamCandi
(object_name + "_overhang_" + std::to_string(layer_idx) + ".svg").c_str()); (object_name + "_overhang_" + std::to_string(layer_idx) + ".svg").c_str());
SVG overhangs_svg {overhangs_file_name, bounding_box}; SVG overhangs_svg {overhangs_file_name, bounding_box};
for (const SeamCandidate &point : object_perimter_points[layer_idx]) { for (const SeamCandidate &point : layers[layer_idx].points) {
Vec3i color = value_rgbi(min_vis, max_vis, point.visibility); Vec3i color = value_rgbi(min_vis, max_vis, point.visibility);
std::string visibility_fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + "," std::string visibility_fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + ","
+ std::to_string(color.z()) + ")"; + std::to_string(color.z()) + ")";
@ -1166,7 +1171,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::
continue; continue;
} }
// String is long engouh, all string seams and potential string seams gathered, now do the alignment // String is long enough, all string seams and potential string seams gathered, now do the alignment
//sort by layer index //sort by layer index
std::sort(seam_string.begin(), seam_string.end(), std::sort(seam_string.begin(), seam_string.end(),
[](const std::pair<size_t, size_t> &left, const std::pair<size_t, size_t> &right) { [](const std::pair<size_t, size_t> &left, const std::pair<size_t, size_t> &right) {
@ -1219,7 +1224,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::
}; };
Vec3f color { randf(), randf(), randf() }; Vec3f color { randf(), randf(), randf() };
for (size_t i = 0; i < seam_string.size(); ++i) { for (size_t i = 0; i < seam_string.size(); ++i) {
auto orig_seam = perimeter_points[seam_string[i].first][seam_string[i].second]; auto orig_seam = layers[seam_string[i].first].points[seam_string[i].second];
fprintf(clusters, "v %f %f %f %f %f %f \n", orig_seam.position[0], fprintf(clusters, "v %f %f %f %f %f %f \n", orig_seam.position[0],
orig_seam.position[1], orig_seam.position[1],
orig_seam.position[2], color[0], color[1], orig_seam.position[2], color[0], color[1],
@ -1228,7 +1233,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::
color = Vec3f { randf(), randf(), randf() }; color = Vec3f { randf(), randf(), randf() };
for (size_t i = 0; i < seam_string.size(); ++i) { for (size_t i = 0; i < seam_string.size(); ++i) {
Perimeter &perimeter = perimeter_points[seam_string[i].first][seam_string[i].second].perimeter; const Perimeter &perimeter = layers[seam_string[i].first].points[seam_string[i].second].perimeter;
fprintf(aligns, "v %f %f %f %f %f %f \n", perimeter.final_seam_position[0], fprintf(aligns, "v %f %f %f %f %f %f \n", perimeter.final_seam_position[0],
perimeter.final_seam_position[1], perimeter.final_seam_position[1],
perimeter.final_seam_position[2], color[0], color[1], perimeter.final_seam_position[2], color[0], color[1],
@ -1308,7 +1313,7 @@ void SeamPlacer::init(const Print &print) {
} }
#ifdef DEBUG_FILES #ifdef DEBUG_FILES
debug_export_points(perimeter_points, po->bounding_box(), std::to_string(po->id().id), debug_export_points(layers, po->bounding_box(), std::to_string(po->id().id),
comparator); comparator);
#endif #endif
} }

View File

@ -119,7 +119,7 @@ public:
static constexpr float polygon_local_angles_arm_distance = 0.5f; static constexpr float polygon_local_angles_arm_distance = 0.5f;
// increases angle importance at the cost of deacreasing visibility info importance. must be > 0 // increases angle importance at the cost of deacreasing visibility info importance. must be > 0
static constexpr float additional_angle_importance = 0.3f; static constexpr float additional_angle_importance = 0.6f;
// If enforcer or blocker is closer to the seam candidate than this limit, the seam candidate is set to Blocker or Enforcer // If enforcer or blocker is closer to the seam candidate than this limit, the seam candidate is set to Blocker or Enforcer
static constexpr float enforcer_blocker_distance_tolerance = 0.35f; static constexpr float enforcer_blocker_distance_tolerance = 0.35f;
@ -134,7 +134,7 @@ public:
// if the seam of the current layer is too far away, and the closest seam candidate is not very good, layer is skipped. // if the seam of the current layer is too far away, and the closest seam candidate is not very good, layer is skipped.
// this param limits the number of allowed skips // this param limits the number of allowed skips
static constexpr size_t seam_align_tolerable_skips = 4; static constexpr size_t seam_align_tolerable_skips = 4;
// minimum number of seams needed in cluster to make alignemnt happen // minimum number of seams needed in cluster to make alignment happen
static constexpr size_t seam_align_minimum_string_seams = 6; static constexpr size_t seam_align_minimum_string_seams = 6;
// points covered by spline; determines number of splines for the given string // points covered by spline; determines number of splines for the given string
static constexpr size_t seam_align_seams_per_segment = 8; static constexpr size_t seam_align_seams_per_segment = 8;