mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 13:05:57 +08:00
fixed QEC decimation problem with ugly triangles
improved seam placer subdivision factor to get smaller models (less triangles) changed aligned behavior - now should align according to the enforcers little tweaking of parameters
This commit is contained in:
parent
39ed3b9cea
commit
18c4fc69e3
@ -178,24 +178,22 @@ std::vector<FaceVisibilityInfo> raycast_visibility(const AABBTreeIndirect::Tree<
|
||||
bool some_hit = AABBTreeIndirect::intersect_ray_all_hits(triangles.vertices,
|
||||
triangles.indices, raycasting_tree,
|
||||
ray_origin_d, final_ray_dir_d, hits);
|
||||
if (some_hit && its_face_normal(triangles, hits[0].id).dot(final_ray_dir) <= 0) {
|
||||
int in_negative = 0;
|
||||
int in_positive = 0;
|
||||
if (some_hit) {
|
||||
int counter = 0;
|
||||
// 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
|
||||
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
|
||||
in_negative += sgn(face_normal.dot(final_ray_dir)); // if volume face aligns with ray dir, we are leaving negative space
|
||||
counter -= sgn(face_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
|
||||
} else {
|
||||
in_positive += sgn(face_normal.dot(final_ray_dir));
|
||||
}
|
||||
if (in_positive > 0 && in_negative <= 0) {
|
||||
dest.visibility -= decrease;
|
||||
break;
|
||||
counter += sgn(face_normal.dot(final_ray_dir));
|
||||
}
|
||||
}
|
||||
if (counter == 0) {
|
||||
dest.visibility -= decrease;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -321,12 +319,10 @@ struct GlobalModelInfo {
|
||||
|
||||
for (size_t i = 0; i < divided_mesh.vertices.size(); ++i) {
|
||||
float visibility = calculate_point_visibility(divided_mesh.vertices[i]);
|
||||
Vec3f color = value_to_rgbf(0.0f, 1.0f,
|
||||
visibility);
|
||||
Vec3f color = value_to_rgbf(0.0f, 1.0f, visibility);
|
||||
fprintf(fp, "v %f %f %f %f %f %f\n",
|
||||
divided_mesh.vertices[i](0), divided_mesh.vertices[i](1), divided_mesh.vertices[i](2),
|
||||
color(0), color(1), color(2)
|
||||
);
|
||||
color(0), color(1), color(2));
|
||||
}
|
||||
for (size_t i = 0; i < divided_mesh.indices.size(); ++i)
|
||||
fprintf(fp, "f %d %d %d\n", divided_mesh.indices[i][0] + 1, divided_mesh.indices[i][1] + 1,
|
||||
@ -557,15 +553,55 @@ void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po) {
|
||||
<< "SeamPlacer: simplify occlusion meshes: start";
|
||||
|
||||
//simplify raycasting mesh
|
||||
its_quadric_edge_collapse(triangle_set, SeamPlacer::raycasting_decimation_target_triangle_count, nullptr, nullptr,
|
||||
nullptr);
|
||||
triangle_set = its_subdivide(triangle_set, SeamPlacer::raycasting_subdivision_target_length);
|
||||
{
|
||||
its_quadric_edge_collapse(triangle_set, SeamPlacer::raycasting_decimation_target_triangle_count, nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
float triangle_set_area = tbb::parallel_reduce(tbb::blocked_range<size_t>(0, triangle_set.indices.size()), 0,
|
||||
[&triangle_set](
|
||||
tbb::blocked_range<size_t> r, float sum) {
|
||||
for (size_t t_idx = r.begin(); t_idx < r.end(); ++t_idx) {
|
||||
const Vec3f &a = triangle_set.vertices[triangle_set.indices[t_idx].x()];
|
||||
const Vec3f &b = triangle_set.vertices[triangle_set.indices[t_idx].y()];
|
||||
const Vec3f &c = triangle_set.vertices[triangle_set.indices[t_idx].z()];
|
||||
sum += 0.5f * (b - a).cross(c - a).norm();
|
||||
}
|
||||
return sum;
|
||||
}, std::plus<float>());
|
||||
|
||||
float target_triangle_area = triangle_set_area / SeamPlacer::raycasting_subdivision_target_triangle_count;
|
||||
float target_triangle_length = 2 * 1.316 * sqrtf(target_triangle_area); //assuming 30-30-120 triangle
|
||||
float subdivision_length = std::max(SeamPlacer::raycasting_subdivision_target_length, target_triangle_length);
|
||||
triangle_set = its_subdivide(triangle_set, subdivision_length);
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< "SeamPlacer: triangle set after subdivision: " << triangle_set.indices.size();
|
||||
}
|
||||
|
||||
//simplify negative volumes
|
||||
its_quadric_edge_collapse(negative_volumes_set, SeamPlacer::raycasting_decimation_target_triangle_count, nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
negative_volumes_set = its_subdivide(negative_volumes_set, SeamPlacer::raycasting_subdivision_target_length);
|
||||
{
|
||||
its_quadric_edge_collapse(negative_volumes_set, SeamPlacer::raycasting_decimation_target_triangle_count,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
float negative_volumes_set_area = tbb::parallel_reduce(
|
||||
tbb::blocked_range<size_t>(0, negative_volumes_set.indices.size()), 0,
|
||||
[&negative_volumes_set](
|
||||
tbb::blocked_range<size_t> r, float sum) {
|
||||
for (size_t t_idx = r.begin(); t_idx < r.end(); ++t_idx) {
|
||||
const Vec3f &a = negative_volumes_set.vertices[negative_volumes_set.indices[t_idx].x()];
|
||||
const Vec3f &b = negative_volumes_set.vertices[negative_volumes_set.indices[t_idx].y()];
|
||||
const Vec3f &c = negative_volumes_set.vertices[negative_volumes_set.indices[t_idx].z()];
|
||||
sum += 0.5f * (b - a).cross(c - a).norm();
|
||||
}
|
||||
return sum;
|
||||
}, std::plus<float>());
|
||||
|
||||
float target_triangle_area = negative_volumes_set_area
|
||||
/ SeamPlacer::raycasting_subdivision_target_triangle_count;
|
||||
float target_triangle_length = 2 * 1.316 * sqrtf(target_triangle_area); //assuming 30-30-120 triangle
|
||||
float subdivision_length = std::max(SeamPlacer::raycasting_subdivision_target_length, target_triangle_length);
|
||||
negative_volumes_set = its_subdivide(negative_volumes_set, subdivision_length);
|
||||
}
|
||||
|
||||
size_t negative_volumes_start_index = triangle_set.indices.size();
|
||||
its_merge(triangle_set, negative_volumes_set);
|
||||
@ -1077,15 +1113,12 @@ std::optional<std::pair<size_t, size_t>> SeamPlacer::find_next_seam_in_layer(
|
||||
}
|
||||
|
||||
// Next compare nearest and nearby point. If they are similar pick nearest, Otherwise expect curvy lines on smooth surfaces like chimney of benchy model
|
||||
// We also compare it to the last point, to detect sharp changes in the scoring - that points to change in the model geometry and string should be ended.
|
||||
if (comparator.are_similar(nearest_point, best_nearby_point)
|
||||
&& comparator.is_first_not_much_worse(nearest_point, next_layer_seam)
|
||||
&& comparator.are_similar(last_point, nearest_point)) {
|
||||
&& comparator.is_first_not_much_worse(nearest_point, next_layer_seam)) {
|
||||
return {std::pair<size_t, size_t> {layer_idx, nearest_point_index}};
|
||||
}
|
||||
// If nearest point is not good enough, try it with the best nearby point.
|
||||
if (comparator.is_first_not_much_worse(best_nearby_point, next_layer_seam)
|
||||
&& comparator.are_similar(last_point, nearest_point)) {
|
||||
if (comparator.is_first_not_much_worse(best_nearby_point, next_layer_seam)) {
|
||||
return {std::pair<size_t, size_t> {layer_idx, best_nearby_point_index}};
|
||||
}
|
||||
|
||||
@ -1204,11 +1237,13 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::
|
||||
}
|
||||
}
|
||||
|
||||
Vec2f back_attractor = 2.0f * unscaled(po->bounding_box().max).cast<float>();
|
||||
//sort them before alignment. Alignment is sensitive to initializaion, this gives it better chance to choose something nice
|
||||
std::sort(seams.begin(), seams.end(),
|
||||
[&comparator, &layers](const std::pair<size_t, size_t> &left, const std::pair<size_t, size_t> &right) {
|
||||
[&comparator, &layers, &back_attractor](const std::pair<size_t, size_t> &left,
|
||||
const std::pair<size_t, size_t> &right) {
|
||||
return comparator.is_first_better(layers[left.first].points[left.second],
|
||||
layers[right.first].points[right.second]);
|
||||
layers[right.first].points[right.second], back_attractor);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -112,6 +112,8 @@ struct PrintObjectSeamData
|
||||
class SeamPlacer {
|
||||
public:
|
||||
static constexpr size_t raycasting_decimation_target_triangle_count = 10000;
|
||||
// for subdivision, both following criteria are considered, and the one with less resulting triangles is used
|
||||
static constexpr size_t raycasting_subdivision_target_triangle_count = 15000;
|
||||
static constexpr float raycasting_subdivision_target_length = 2.0f;
|
||||
//square of number of rays per triangle
|
||||
static constexpr size_t sqr_rays_per_triangle = 7;
|
||||
@ -120,7 +122,7 @@ public:
|
||||
static constexpr float polygon_local_angles_arm_distance = 0.5f;
|
||||
|
||||
// increases angle importance at the cost of deacreasing visibility info importance. must be > 0
|
||||
static constexpr float additional_angle_importance = 0.4f;
|
||||
static constexpr float additional_angle_importance = 0.3f;
|
||||
|
||||
// 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;
|
||||
@ -129,7 +131,7 @@ public:
|
||||
|
||||
// When searching for seam clusters for alignment:
|
||||
// following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer
|
||||
static constexpr float seam_align_score_tolerance = 0.3f;
|
||||
static constexpr float seam_align_score_tolerance = 0.2f;
|
||||
// seam_align_tolerable_dist - if next layer closes point is too far away, break string
|
||||
static constexpr float seam_align_tolerable_dist = 1.0f;
|
||||
// if the seam of the current layer is too far away, and the closest seam candidate is not very good, layer is skipped.
|
||||
|
@ -595,8 +595,7 @@ bool QuadricEdgeCollapse::is_flipped(const Vec3f & new_vertex,
|
||||
const EdgeInfos & e_infos,
|
||||
const indexed_triangle_set &its)
|
||||
{
|
||||
static const float thr_pos = 1.0f - std::numeric_limits<float>::epsilon();
|
||||
static const float thr_neg = -thr_pos;
|
||||
static const float triangle_beauty_threshold = 1.0f - std::numeric_limits<float>::epsilon();
|
||||
static const float dot_thr = 0.2f; // Value from simplify mesh cca 80 DEG
|
||||
|
||||
// for each vertex triangles
|
||||
@ -615,7 +614,16 @@ bool QuadricEdgeCollapse::is_flipped(const Vec3f & new_vertex,
|
||||
d2.normalize();
|
||||
|
||||
float dot = d1.dot(d2);
|
||||
if (dot > thr_pos || dot < thr_neg) return true;
|
||||
if (std::abs(dot) > triangle_beauty_threshold) { // OK, the new triangle is suspiciously ugly, but it can still be better than the original
|
||||
const Vec3f &v_orig = its.vertices[t[(e_info.edge) % 3]];
|
||||
Vec3f d1_orig = vf - v_orig;
|
||||
d1_orig.normalize();
|
||||
Vec3f d2_orig = vs - v_orig;
|
||||
d2_orig.normalize();
|
||||
if (std::abs(d1_orig.dot(d2_orig)) < std::abs(dot)) { // original was not that ugly, so return flipped
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// IMPROVE: propagate new normal
|
||||
Vec3f n = d1.cross(d2);
|
||||
n.normalize();
|
||||
|
Loading…
x
Reference in New Issue
Block a user