When projecting images, prefer using texture zones that are already used on the target object

This commit is contained in:
sentientstardust
2026-05-08 05:16:20 +01:00
parent d115824d6a
commit de81550309
3 changed files with 97 additions and 25 deletions

View File

@@ -7331,6 +7331,7 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
struct TextureSampleData {
std::array<float, 4> rgba { { 0.f, 0.f, 0.f, 1.f } };
std::vector<float> raw_component_weights;
bool raw_component_weights_from_texture { false };
};
struct WeightedTextureSample {
@@ -7338,16 +7339,18 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
float y_mm { 0.f };
std::array<float, 4> rgba { { 0.f, 0.f, 0.f, 1.f } };
std::vector<float> raw_component_weights;
bool raw_component_weights_from_texture { false };
float weight { 0.f };
};
std::vector<WeightedTextureSample> samples;
samples.reserve(8192);
auto accumulate_sample = [&samples](float x_mm,
float y_mm,
const std::array<float, 4> &rgba,
float sample_weight,
std::vector<float> raw_component_weights = {}) {
auto accumulate_sample = [&samples, component_count](float x_mm,
float y_mm,
const std::array<float, 4> &rgba,
float sample_weight,
std::vector<float> raw_component_weights = {},
bool raw_component_weights_from_texture = false) {
if (!std::isfinite(x_mm) || !std::isfinite(y_mm) || sample_weight <= EPSILON)
return;
if (!std::isfinite(sample_weight) ||
@@ -7356,8 +7359,10 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
!std::isfinite(rgba[2]) ||
!std::isfinite(rgba[3]))
return;
if (raw_component_weights.size() != component_count)
raw_component_weights_from_texture = false;
samples.push_back({ x_mm, y_mm, rgba, std::move(raw_component_weights), sample_weight });
samples.push_back({ x_mm, y_mm, rgba, std::move(raw_component_weights), raw_component_weights_from_texture, sample_weight });
};
struct LayerPlaneSamplePoint {
@@ -7473,7 +7478,8 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
float(world_pos.y()),
sample_data.rgba,
sample_weight,
std::move(sample_data.raw_component_weights));
std::move(sample_data.raw_component_weights),
sample_data.raw_component_weights_from_texture);
}
return true;
@@ -7483,7 +7489,7 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
const Vec3d &p1,
const Vec3d &p2,
const std::array<float, 4> &rgba) {
if (accumulate_layer_plane_triangle_samples(p0, p1, p2, [&rgba](const Vec3f &) { return TextureSampleData{ rgba, {} }; }))
if (accumulate_layer_plane_triangle_samples(p0, p1, p2, [&rgba](const Vec3f &) { return TextureSampleData{ rgba, {}, false }; }))
return;
const float max_world_edge_mm = std::max({
@@ -7640,7 +7646,7 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
}
if (raw_component_weights.size() != component_count)
rgba = composite_rgba_over_background_for_gcode(rgba, background_color);
return TextureSampleData{ rgba, std::move(raw_component_weights) };
return TextureSampleData{ rgba, std::move(raw_component_weights), use_raw_uv_texture };
};
auto sample_data_for_barycentric = [&](const Vec3f &barycentric) {
@@ -7711,7 +7717,8 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
float(world_pos.y()),
sample_data.rgba,
sample_weight,
std::move(sample_data.raw_component_weights));
std::move(sample_data.raw_component_weights),
sample_data.raw_component_weights_from_texture);
sampled_from_uv_texture = true;
}
}
@@ -7789,6 +7796,7 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
weight_field.sample_y_mm.resize(sample_count);
weight_field.sample_weight.resize(sample_count);
weight_field.sample_component_weights.assign(sample_count * component_count, 0.f);
weight_field.raw_component_weights_from_texture = false;
std::vector<float> fallback_acc(component_count, 0.f);
float fallback_weight = 0.f;
@@ -7796,6 +7804,8 @@ static VertexColorOverhangWeightField build_vertex_color_weight_field_for_gcode(
const WeightedTextureSample &sample = samples[sample_idx];
if (sample.weight <= EPSILON)
continue;
if (sample.raw_component_weights_from_texture)
weight_field.raw_component_weights_from_texture = true;
weight_field.sample_x_mm[sample_idx] = sample.x_mm;
weight_field.sample_y_mm[sample_idx] = sample.y_mm;
@@ -7911,7 +7921,8 @@ static float sample_vertex_color_weight_field_for_gcode(const VertexColorOverhan
bool high_resolution_texture_sampling,
bool compact_offset_mode = false)
{
if (compact_offset_mode && !weight_field.empty() && component_idx < weight_field.component_count) {
if (compact_offset_mode && !weight_field.raw_component_weights_from_texture && !weight_field.empty() &&
component_idx < weight_field.component_count) {
std::vector<float> values(weight_field.component_count, 0.f);
float max_value = 0.f;
for (size_t idx = 0; idx < weight_field.component_count; ++idx) {

View File

@@ -66,6 +66,7 @@ struct VertexColorOverhangWeightField {
std::vector<float> sample_component_weights;
std::vector<std::vector<uint32_t>> buckets;
std::vector<float> fallback_weights;
bool raw_component_weights_from_texture { false };
bool empty() const
{

View File

@@ -4343,6 +4343,74 @@ static void assign_texture_mapping_zone_preserving_painted_regions(ModelObject &
}
}
static bool image_texture_zone_is_usable_for_projection(const TextureMappingManager &texture_mgr, unsigned int zone_id)
{
const TextureMappingZone *zone = texture_mgr.zone_from_id(zone_id);
return zone != nullptr && zone->enabled && !zone->deleted && zone->is_image_texture();
}
static unsigned int painted_image_texture_zone_id_for_projection(const ModelObject &object)
{
if (wxGetApp().preset_bundle == nullptr)
return 0;
const TextureMappingManager &texture_mgr = wxGetApp().preset_bundle->texture_mapping_zones;
std::vector<unsigned int> painted_ids;
for (const ModelVolume *volume : object.volumes) {
if (volume == nullptr || !volume->is_model_part() || volume->mmu_segmentation_facets.empty())
continue;
const auto &used_states = volume->mmu_segmentation_facets.get_data().used_states;
for (size_t state_idx = static_cast<size_t>(EnforcerBlockerType::Extruder1); state_idx < used_states.size(); ++state_idx) {
if (used_states[state_idx] && image_texture_zone_is_usable_for_projection(texture_mgr, unsigned(state_idx)))
painted_ids.emplace_back(unsigned(state_idx));
}
}
for (const TextureMappingZone &zone : texture_mgr.zones())
if (image_texture_zone_is_usable_for_projection(texture_mgr, zone.zone_id) &&
std::find(painted_ids.begin(), painted_ids.end(), zone.zone_id) != painted_ids.end())
return zone.zone_id;
return 0;
}
static unsigned int base_image_texture_zone_id_for_projection(const ModelObject &object)
{
if (wxGetApp().preset_bundle == nullptr)
return 0;
const TextureMappingManager &texture_mgr = wxGetApp().preset_bundle->texture_mapping_zones;
std::vector<unsigned int> base_ids;
if (const ConfigOption *opt = object.config.option("extruder"); opt != nullptr) {
const int extruder_id = opt->getInt();
if (extruder_id > 0 && image_texture_zone_is_usable_for_projection(texture_mgr, unsigned(extruder_id)))
base_ids.emplace_back(unsigned(extruder_id));
}
for (const ModelVolume *volume : object.volumes) {
if (volume == nullptr || !volume->is_model_part())
continue;
const int extruder_id = volume->extruder_id();
if (extruder_id > 0 && image_texture_zone_is_usable_for_projection(texture_mgr, unsigned(extruder_id)))
base_ids.emplace_back(unsigned(extruder_id));
}
for (const TextureMappingZone &zone : texture_mgr.zones())
if (image_texture_zone_is_usable_for_projection(texture_mgr, zone.zone_id) &&
std::find(base_ids.begin(), base_ids.end(), zone.zone_id) != base_ids.end())
return zone.zone_id;
return 0;
}
static unsigned int texture_mapping_zone_id_for_image_projection(ModelObject &object)
{
if (const unsigned int painted_id = painted_image_texture_zone_id_for_projection(object); painted_id != 0)
return painted_id;
if (const unsigned int base_id = base_image_texture_zone_id_for_projection(object); base_id != 0)
return base_id;
return ensure_texture_mapping_zone();
}
struct ManagedRegionColorSource
{
std::vector<std::vector<TriangleSelector::FacetStateTriangle>> triangles_per_type;
@@ -8742,21 +8810,13 @@ bool GLGizmoImageProjection::project_image_to_selected_object()
if (!changed)
return false;
unsigned int raw_texture_mapping_filament_id = 0;
if (m_raw_atlas.valid()) {
raw_texture_mapping_filament_id = ensure_texture_mapping_zone();
if (raw_texture_mapping_filament_id != 0) {
object->config.set("extruder", int(raw_texture_mapping_filament_id));
for (ModelVolume *volume : object->volumes)
if (volume != nullptr && volume->is_model_part())
volume->config.set("extruder", int(raw_texture_mapping_filament_id));
enable_texture_mapping_zone_simulated_preview(raw_texture_mapping_filament_id);
}
}
const bool whole_image_texture_mapped_without_regions = object_is_whole_image_texture_mapped_without_regions(*object);
const unsigned int texture_mapping_filament_id =
(!whole_image_texture_mapped_without_regions || m_raw_atlas.valid()) ? texture_mapping_zone_id_for_image_projection(*object) : 0;
if (m_raw_atlas.valid() && texture_mapping_filament_id != 0)
enable_texture_mapping_zone_simulated_preview(texture_mapping_filament_id);
if (!object_is_whole_image_texture_mapped_without_regions(*object)) {
const unsigned int texture_mapping_filament_id =
raw_texture_mapping_filament_id != 0 ? raw_texture_mapping_filament_id : ensure_texture_mapping_zone();
if (!whole_image_texture_mapped_without_regions) {
if (texture_mapping_filament_id != 0) {
const Selection &selection = m_parent.get_selection();
const int instance_idx = selection.get_instance_idx();