5050041d8 Paint texture mapping regions automatically when using image projection mode. Work on UV map auto-generation
This commit is contained in:
@@ -6789,6 +6789,60 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
|
||||
samples.push_back({ x_mm, y_mm, rgba, sample_weight });
|
||||
};
|
||||
|
||||
auto accumulate_constant_surface_triangle_samples = [&](const Vec3d &p0,
|
||||
const Vec3d &p1,
|
||||
const Vec3d &p2,
|
||||
const std::array<float, 4> &rgba) {
|
||||
const float max_world_edge_mm = std::max({
|
||||
float((p1 - p0).norm()),
|
||||
float((p2 - p1).norm()),
|
||||
float((p0 - p2).norm())
|
||||
});
|
||||
if (!std::isfinite(max_world_edge_mm))
|
||||
return;
|
||||
|
||||
const double tri_area_mm2 = 0.5 * ((p1 - p0).cross(p2 - p0)).norm();
|
||||
if (!std::isfinite(tri_area_mm2))
|
||||
return;
|
||||
|
||||
const float world_sample_pitch_mm = high_resolution_texture_sampling ? 0.08f : 0.16f;
|
||||
const int max_bary_steps = high_resolution_texture_sampling ? 80 : 40;
|
||||
const int bary_steps = std::clamp(int(std::ceil(max_world_edge_mm / world_sample_pitch_mm)), 1, max_bary_steps);
|
||||
const int sample_count = bary_steps * (bary_steps + 1) / 2;
|
||||
if (sample_count <= 0)
|
||||
return;
|
||||
|
||||
const float area_weight = std::max(0.05f, float(tri_area_mm2)) / float(sample_count);
|
||||
if (!std::isfinite(area_weight))
|
||||
return;
|
||||
|
||||
const float inv_steps = 1.f / float(bary_steps);
|
||||
for (int i = 0; i < bary_steps; ++i) {
|
||||
for (int j = 0; j < (bary_steps - i); ++j) {
|
||||
const float b1 = (float(i) + 0.33333334f) * inv_steps;
|
||||
const float b2 = (float(j) + 0.33333334f) * inv_steps;
|
||||
const float b0 = 1.f - b1 - b2;
|
||||
if (b0 < 0.f)
|
||||
continue;
|
||||
|
||||
const Vec3d world_pos = p0 * double(b0) + p1 * double(b1) + p2 * double(b2);
|
||||
float sample_weight = area_weight;
|
||||
if (use_layer_weighting) {
|
||||
const float dz = std::abs(float(world_pos.z()) - layer_z_mm);
|
||||
const float z_norm = dz / safe_layer_z_falloff_mm;
|
||||
const float z_weight = std::exp(-0.5f * z_norm * z_norm);
|
||||
if (!std::isfinite(z_weight))
|
||||
continue;
|
||||
sample_weight *= z_weight;
|
||||
}
|
||||
if (sample_weight <= EPSILON)
|
||||
continue;
|
||||
|
||||
accumulate_sample(float(world_pos.x()), float(world_pos.y()), rgba, sample_weight);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const Transform3d object_trafo = print_object.trafo_centered();
|
||||
for (const ModelVolume *volume : model_object->volumes) {
|
||||
if (volume == nullptr)
|
||||
@@ -6811,26 +6865,10 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
|
||||
if (!p0.allFinite() || !p1.allFinite() || !p2.allFinite())
|
||||
continue;
|
||||
|
||||
const Vec3d world_pos = (p0 + p1 + p2) / 3.0;
|
||||
std::array<float, 4> rgba = unpack_rgba_u32(facet.rgba);
|
||||
rgba[3] = 1.f;
|
||||
|
||||
const double tri_area_mm2 = 0.5 * ((p1 - p0).cross(p2 - p0)).norm();
|
||||
if (!std::isfinite(tri_area_mm2))
|
||||
continue;
|
||||
float sample_weight = std::max(0.05f, float(tri_area_mm2));
|
||||
if (use_layer_weighting) {
|
||||
const float dz = std::abs(float(world_pos.z()) - layer_z_mm);
|
||||
const float z_norm = dz / safe_layer_z_falloff_mm;
|
||||
const float z_weight = std::exp(-0.5f * z_norm * z_norm);
|
||||
if (!std::isfinite(z_weight))
|
||||
continue;
|
||||
sample_weight *= z_weight;
|
||||
}
|
||||
if (sample_weight <= EPSILON)
|
||||
continue;
|
||||
|
||||
accumulate_sample(float(world_pos.x()), float(world_pos.y()), rgba, sample_weight);
|
||||
accumulate_constant_surface_triangle_samples(p0, p1, p2, rgba);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -123,6 +123,24 @@ bool model_volume_has_any_texture_preview_data(const ModelVolume &model_volume)
|
||||
model_volume.imported_texture_height > 0);
|
||||
}
|
||||
|
||||
bool texture_preview_has_surface_gradient_state(size_t states_count,
|
||||
unsigned int base_filament_id,
|
||||
size_t num_physical,
|
||||
const TextureMappingManager *texture_mgr)
|
||||
{
|
||||
if (texture_mgr == nullptr)
|
||||
return false;
|
||||
|
||||
for (size_t state_id = 0; state_id < states_count; ++state_id) {
|
||||
const unsigned int filament_id = state_id == 0 ? base_filament_id : unsigned(state_id);
|
||||
const TextureMappingZone *zone = texture_mgr->zone_from_id(filament_id);
|
||||
if (zone != nullptr && zone->enabled && !zone->deleted && zone->is_2d_gradient())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -628,6 +646,8 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj
|
||||
const unsigned int base_filament_id = model_volume->extruder_id() > 0 ? unsigned(model_volume->extruder_id()) : 0u;
|
||||
const TextureMappingZone *base_zone = texture_mgr != nullptr ? texture_mgr->zone_from_id(base_filament_id) : nullptr;
|
||||
const bool has_mmu_segmentation = !model_volume->mmu_segmentation_facets.empty();
|
||||
const bool has_texture_mapping_color_preview_data = model_volume_has_texture_mapping_color_preview_data(*model_volume);
|
||||
const bool has_texture_preview_data = model_volume_has_texture_preview_data(*model_volume);
|
||||
const bool has_texture_preview =
|
||||
base_zone != nullptr &&
|
||||
base_zone->enabled &&
|
||||
@@ -682,25 +702,31 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj
|
||||
fallback_color);
|
||||
state_colors.insert(state_colors.end(), extruder_colors.begin(), extruder_colors.end());
|
||||
|
||||
build_mmu_texture_preview_models(*model_volume,
|
||||
triangles_per_type,
|
||||
state_colors,
|
||||
base_filament_id,
|
||||
num_physical,
|
||||
texture_mgr,
|
||||
mmuseg_texture_preview_models,
|
||||
mmuseg_texture_preview_colors,
|
||||
mmuseg_texture_preview_filament_ids);
|
||||
build_mmu_vertex_color_preview_models(*model_volume,
|
||||
triangles_per_type,
|
||||
state_colors,
|
||||
base_filament_id,
|
||||
num_physical,
|
||||
texture_mgr,
|
||||
this->world_matrix(),
|
||||
mmuseg_vertex_color_preview_models,
|
||||
mmuseg_vertex_color_preview_colors,
|
||||
mmuseg_vertex_color_preview_filament_ids);
|
||||
if (!has_texture_mapping_color_preview_data && has_texture_preview_data) {
|
||||
build_mmu_texture_preview_models(*model_volume,
|
||||
triangles_per_type,
|
||||
state_colors,
|
||||
base_filament_id,
|
||||
num_physical,
|
||||
texture_mgr,
|
||||
mmuseg_texture_preview_models,
|
||||
mmuseg_texture_preview_colors,
|
||||
mmuseg_texture_preview_filament_ids);
|
||||
}
|
||||
if (has_texture_mapping_color_preview_data ||
|
||||
!has_texture_preview_data ||
|
||||
texture_preview_has_surface_gradient_state(triangles_per_type.size(), base_filament_id, num_physical, texture_mgr)) {
|
||||
build_mmu_vertex_color_preview_models(*model_volume,
|
||||
triangles_per_type,
|
||||
state_colors,
|
||||
base_filament_id,
|
||||
num_physical,
|
||||
texture_mgr,
|
||||
this->world_matrix(),
|
||||
mmuseg_vertex_color_preview_models,
|
||||
mmuseg_vertex_color_preview_colors,
|
||||
mmuseg_vertex_color_preview_filament_ids);
|
||||
}
|
||||
mmuseg_ts = model_volume->mmu_segmentation_facets.timestamp();
|
||||
mmuseg_texture_preview_visual_signature = preview_visual_signature;
|
||||
}
|
||||
@@ -814,6 +840,21 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj
|
||||
glFrontFace(GL_CCW);
|
||||
}
|
||||
|
||||
void GLVolume::invalidate_texture_mapping_preview()
|
||||
{
|
||||
mmuseg_models.clear();
|
||||
mmuseg_texture_preview_models.clear();
|
||||
mmuseg_texture_preview_colors.clear();
|
||||
mmuseg_texture_preview_filament_ids.clear();
|
||||
mmuseg_vertex_color_preview_models.clear();
|
||||
mmuseg_vertex_color_preview_colors.clear();
|
||||
mmuseg_vertex_color_preview_filament_ids.clear();
|
||||
mmuseg_texture_preview.reset();
|
||||
mmuseg_texture_preview_signature = 0;
|
||||
mmuseg_texture_preview_visual_signature = 0;
|
||||
mmuseg_ts = 0;
|
||||
}
|
||||
|
||||
bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -int(slaposSupportTree); }
|
||||
bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposPad); }
|
||||
|
||||
@@ -1261,6 +1302,19 @@ bool GLWipeTowerVolume::IsTransparent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLVolumeCollection::invalidate_texture_mapping_preview_for_object(int object_idx)
|
||||
{
|
||||
bool changed = false;
|
||||
for (GLVolume *volume : volumes) {
|
||||
if (volume == nullptr || volume->object_idx() != object_idx)
|
||||
continue;
|
||||
volume->invalidate_texture_mapping_preview();
|
||||
changed = true;
|
||||
}
|
||||
if (changed)
|
||||
clear_texture_preview_simulation_cache();
|
||||
}
|
||||
|
||||
std::vector<int> GLVolumeCollection::load_object(
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
|
||||
@@ -359,6 +359,7 @@ public:
|
||||
|
||||
//BBS: add simple render function for thumbnail
|
||||
void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector<ColorRGBA>& extruder_colors, bool ban_light =false);
|
||||
void invalidate_texture_mapping_preview();
|
||||
|
||||
void set_bounding_boxes_as_dirty() {
|
||||
m_transformed_bounding_box.reset();
|
||||
@@ -553,6 +554,7 @@ public:
|
||||
|
||||
// Clear the geometry
|
||||
void clear() { clear_texture_preview_simulation_cache(); for (auto *v : volumes) delete v; volumes.clear(); }
|
||||
void invalidate_texture_mapping_preview_for_object(int object_idx);
|
||||
|
||||
bool empty() const { return volumes.empty(); }
|
||||
void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); }
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
#include <float.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
@@ -1352,6 +1353,12 @@ void GLCanvas3D::reset_volumes()
|
||||
_set_warning_notification(EWarning::ObjectOutside, false);
|
||||
}
|
||||
|
||||
void GLCanvas3D::invalidate_texture_mapping_preview_for_object(size_t object_idx)
|
||||
{
|
||||
if (object_idx <= size_t(std::numeric_limits<int>::max()))
|
||||
m_volumes.invalidate_texture_mapping_preview_for_object(int(object_idx));
|
||||
}
|
||||
|
||||
//BBS: get current plater's bounding box
|
||||
BoundingBoxf3 GLCanvas3D::_get_current_partplate_print_volume()
|
||||
{
|
||||
|
||||
@@ -768,6 +768,7 @@ public:
|
||||
unsigned int get_volumes_count() const { return (unsigned int)m_volumes.volumes.size(); }
|
||||
const GLVolumeCollection& get_volumes() const { return m_volumes; }
|
||||
void reset_volumes();
|
||||
void invalidate_texture_mapping_preview_for_object(size_t object_idx);
|
||||
ModelInstanceEPrintVolumeState check_volumes_outside_state(ObjectFilamentResults* object_results = nullptr) const;
|
||||
void check_volumes_outside_state(GLVolumeCollection& volumes) const { check_volumes_outside_state(volumes, nullptr, false); }
|
||||
bool is_all_plates_selected() { return m_sel_plate_toolbar.m_all_plates_stats_item && m_sel_plate_toolbar.m_all_plates_stats_item->selected; }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1559,6 +1559,63 @@ std::optional<ColorRGBA> sample_texture_mapping_color_preview(
|
||||
return unpack_vertex_color(color_facets[found->second.front()].rgba);
|
||||
}
|
||||
|
||||
std::vector<Vec3f> clip_preview_triangle_to_triangle(const std::array<Vec3f, 3> &subject, const std::array<Vec3f, 3> &clip)
|
||||
{
|
||||
std::vector<Vec3f> polygon(subject.begin(), subject.end());
|
||||
const float tolerance = -1e-5f;
|
||||
|
||||
for (size_t side = 0; side < 3 && !polygon.empty(); ++side) {
|
||||
std::vector<Vec3f> clipped;
|
||||
clipped.reserve(polygon.size() + 1);
|
||||
|
||||
auto weight_for_side = [&clip, side](const Vec3f &point) {
|
||||
Vec3f weights = Vec3f::Zero();
|
||||
if (!barycentric_weights(point, clip[0], clip[1], clip[2], weights))
|
||||
return -std::numeric_limits<float>::max();
|
||||
return weights[side];
|
||||
};
|
||||
|
||||
Vec3f previous = polygon.back();
|
||||
float previous_weight = weight_for_side(previous);
|
||||
bool previous_inside = previous_weight >= tolerance;
|
||||
|
||||
for (const Vec3f ¤t : polygon) {
|
||||
const float current_weight = weight_for_side(current);
|
||||
const bool current_inside = current_weight >= tolerance;
|
||||
|
||||
if (current_inside != previous_inside) {
|
||||
const float denom = previous_weight - current_weight;
|
||||
if (std::abs(denom) > k_epsilon) {
|
||||
const float t = std::clamp(previous_weight / denom, 0.f, 1.f);
|
||||
clipped.emplace_back(previous + (current - previous) * t);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_inside)
|
||||
clipped.emplace_back(current);
|
||||
|
||||
previous = current;
|
||||
previous_weight = current_weight;
|
||||
previous_inside = current_inside;
|
||||
}
|
||||
|
||||
polygon = std::move(clipped);
|
||||
}
|
||||
|
||||
return polygon;
|
||||
}
|
||||
|
||||
bool preview_polygon_has_area(const std::vector<Vec3f> &polygon, const Vec3f &normal)
|
||||
{
|
||||
if (polygon.size() < 3)
|
||||
return false;
|
||||
|
||||
float area = 0.f;
|
||||
for (size_t idx = 1; idx + 1 < polygon.size(); ++idx)
|
||||
area += std::abs((polygon[idx] - polygon[0]).cross(polygon[idx + 1] - polygon[0]).dot(normal));
|
||||
return area > k_epsilon;
|
||||
}
|
||||
|
||||
bool build_texture_mapping_color_preview_model_for_state(
|
||||
const ModelVolume &model_volume,
|
||||
const std::vector<TriangleSelector::FacetStateTriangle> &state_triangles,
|
||||
@@ -1624,25 +1681,23 @@ bool build_texture_mapping_color_preview_model_for_state(
|
||||
bool emitted_color_facets = false;
|
||||
auto color_facets_for_triangle = facets_by_source_triangle.find(triangle.source_triangle);
|
||||
if (color_facets_for_triangle != facets_by_source_triangle.end()) {
|
||||
const float tolerance = -1e-4f;
|
||||
for (const size_t facet_idx : color_facets_for_triangle->second) {
|
||||
if (facet_idx >= color_facets.size())
|
||||
continue;
|
||||
|
||||
const ColorFacetTriangle &facet = color_facets[facet_idx];
|
||||
const Vec3f centroid = (facet.vertices[0] + facet.vertices[1] + facet.vertices[2]) / 3.f;
|
||||
Vec3f weights = Vec3f::Zero();
|
||||
if (!barycentric_weights(centroid, triangle.vertices[0], triangle.vertices[1], triangle.vertices[2], weights))
|
||||
continue;
|
||||
if (weights.x() < tolerance || weights.y() < tolerance || weights.z() < tolerance)
|
||||
const std::vector<Vec3f> clipped = clip_preview_triangle_to_triangle(facet.vertices, triangle.vertices);
|
||||
if (!preview_polygon_has_area(clipped, normal))
|
||||
continue;
|
||||
|
||||
const ColorRGBA color = preview_color(unpack_vertex_color(facet.rgba));
|
||||
geometry.add_vertex(facet.vertices[0] + offset, normal, color);
|
||||
geometry.add_vertex(facet.vertices[1] + offset, normal, color);
|
||||
geometry.add_vertex(facet.vertices[2] + offset, normal, color);
|
||||
geometry.add_triangle(vertex_index, vertex_index + 1, vertex_index + 2);
|
||||
vertex_index += 3;
|
||||
for (size_t poly_idx = 1; poly_idx + 1 < clipped.size(); ++poly_idx) {
|
||||
geometry.add_vertex(clipped[0] + offset, normal, color);
|
||||
geometry.add_vertex(clipped[poly_idx] + offset, normal, color);
|
||||
geometry.add_vertex(clipped[poly_idx + 1] + offset, normal, color);
|
||||
geometry.add_triangle(vertex_index, vertex_index + 1, vertex_index + 2);
|
||||
vertex_index += 3;
|
||||
}
|
||||
emitted_color_facets = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ bool build_mmu_vertex_color_preview_models(
|
||||
|
||||
size_t model_volume_texture_preview_signature(const ModelVolume &model_volume);
|
||||
size_t model_volume_texture_mapping_color_preview_signature(const ModelVolume &model_volume);
|
||||
bool model_volume_has_texture_preview_data(const ModelVolume &model_volume);
|
||||
bool model_volume_has_vertex_color_preview_data(const ModelVolume &model_volume);
|
||||
bool model_volume_has_texture_mapping_color_preview_data(const ModelVolume &model_volume);
|
||||
|
||||
bool ensure_model_volume_texture_preview(const ModelVolume &model_volume,
|
||||
GUI::GLTexture &texture,
|
||||
|
||||
Reference in New Issue
Block a user