Skip to content

Commit

Permalink
Implement new 'fuzzy skin' type: displacement mapping
Browse files Browse the repository at this point in the history
Add new fuzzy skin type: displacement map. This feature uses an 8-bit grayscale PNG to displace the object's surface based on pixel values.

The displacement map is applied by mapping the surface points of the 3D model to the corresponding points on the 2D displacement map.

The UV mapping in this implementation is simple: it treats the object's as a cube.
It determines which face of the cube the current line is on based on the direction of the bump (which is just perpendicular to the line).
The U coordinate is calculated based on the x, y coordinates of the point on the line relative to the bounding box and the determined face.
The V coordinate is based on the current layer's height.
This method works surpsingly well for many objects but may fail for more complex shapes like ramps.

This feature is based on work by the PrusaSlicer community member Poikilos, who initially implemented displacement and cube mapping.
  • Loading branch information
undingen committed Jan 30, 2025
1 parent 4d762c4 commit e506d73
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 27 deletions.
1 change: 1 addition & 0 deletions src/libslic3r/LayerRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, const LayerRe
&region_config,
&this->layer()->object()->config(),
&print_config,
this->layer()->object(),
spiral_mode,

// output:
Expand Down
214 changes: 193 additions & 21 deletions src/libslic3r/PerimeterGenerator.cpp

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion src/libslic3r/PerimeterGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct FuzzySkinConfig
double noise_scale;
int noise_octaves;
double noise_persistence;
std::string displacement_map_path;

bool operator==(const FuzzySkinConfig& r) const
{
Expand All @@ -30,7 +31,8 @@ struct FuzzySkinConfig
&& noise_type == r.noise_type
&& noise_scale == r.noise_scale
&& noise_octaves == r.noise_octaves
&& noise_persistence == r.noise_persistence;
&& noise_persistence == r.noise_persistence
&& displacement_map_path == r.displacement_map_path;
}

bool operator!=(const FuzzySkinConfig& r) const { return !(*this == r); }
Expand All @@ -50,6 +52,7 @@ template<> struct hash<Slic3r::FuzzySkinConfig>
boost::hash_combine(seed, std::hash<double>{}(c.noise_scale));
boost::hash_combine(seed, std::hash<int>{}(c.noise_octaves));
boost::hash_combine(seed, std::hash<double>{}(c.noise_persistence));
boost::hash_combine(seed, std::hash<std::string>{}(c.displacement_map_path));
return seed;
}
};
Expand All @@ -74,6 +77,7 @@ class PerimeterGenerator {
const PrintRegionConfig *config;
const PrintObjectConfig *object_config;
const PrintConfig *print_config;
const PrintObject *print_object;
// Outputs:
ExtrusionEntityCollection *loops;
ExtrusionEntityCollection *gap_fill;
Expand Down Expand Up @@ -104,6 +108,7 @@ class PerimeterGenerator {
const PrintRegionConfig* config,
const PrintObjectConfig* object_config,
const PrintConfig* print_config,
const PrintObject* print_object,
const bool spiral_mode,
// Output:
// Loops with the external thin walls
Expand All @@ -118,6 +123,7 @@ class PerimeterGenerator {
slice_z(slice_z), layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config),
print_object(print_object),
m_spiral_vase(spiral_mode),
m_scaled_resolution(scaled<double>(print_config->resolution.value > EPSILON ? print_config->resolution.value : EPSILON)),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces), fill_no_overlap(fill_no_overlap),
Expand All @@ -136,6 +142,8 @@ class PerimeterGenerator {
double smaller_width_ext_mm3_per_mm() const { return m_ext_mm3_per_mm_smaller_width; }
Polygons lower_slices_polygons() const { return m_lower_slices_polygons; }

const PrintObject* object() const { return print_object; }

private:
std::vector<Polygons> generate_lower_polygons_series(float width);
void split_top_surfaces(const ExPolygons &orig_polygons, ExPolygons &top_fills, ExPolygons &non_top_polygons, ExPolygons &fill_clip) const;
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ static std::vector<std::string> s_Preset_print_options {
"minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target",
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_inset",
"max_travel_detour_distance",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence", "fuzzy_skin_displacement_map",
"max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only",
"inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed",
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_interface_speed",
Expand Down
15 changes: 13 additions & 2 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ static t_config_enum_values s_keys_map_NoiseType {
{ "perlin", int(NoiseType::Perlin) },
{ "billow", int(NoiseType::Billow) },
{ "ridgedmulti", int(NoiseType::RidgedMulti) },
{ "voronoi", int(NoiseType::Voronoi) }
{ "voronoi", int(NoiseType::Voronoi) },
{ "displacementmap",int(NoiseType::DisplacementMap) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NoiseType)

Expand Down Expand Up @@ -2649,18 +2650,21 @@ void PrintConfigDef::init_fff_params()
"Perlin: Perlin noise, which gives a more consistent texture.\n"
"Billow: Similar to perlin noise, but clumpier.\n"
"Ridged Multifractal: Ridged noise with sharp, jagged features. Creates marble-like textures.\n"
"Voronoi: Divides the surface into voronoi cells, and displaces each one by a random amount. Creates a patchwork texture.");
"Voronoi: Divides the surface into voronoi cells, and displaces each one by a random amount. Creates a patchwork texture.\n"
"Displacement Map: Deforms the perimeter with an image-based displacement map.");
def->enum_keys_map = &ConfigOptionEnum<NoiseType>::get_enum_values();
def->enum_values.push_back("classic");
def->enum_values.push_back("perlin");
def->enum_values.push_back("billow");
def->enum_values.push_back("ridgedmulti");
def->enum_values.push_back("voronoi");
def->enum_values.push_back("displacementmap");
def->enum_labels.push_back(L("Classic"));
def->enum_labels.push_back(L("Perlin"));
def->enum_labels.push_back(L("Billow"));
def->enum_labels.push_back(L("Ridged Multifractal"));
def->enum_labels.push_back(L("Voronoi"));
def->enum_labels.push_back(L("Displacement Map"));
def->mode = comSimple;
def->set_default_value(new ConfigOptionEnum<NoiseType>(NoiseType::Classic));

Expand Down Expand Up @@ -2692,6 +2696,13 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.5));

def = this->add("fuzzy_skin_displacement_map", coString);
def->label = L("Fuzzy skin displacement map filepath");
def->tooltip = L("Specifies the path to an 8-bit grayscale PNG file used for displacement mapping.");
def->category = L("Others");
def->mode = comSimple;
def->set_default_value(new ConfigOptionString());

def = this->add("filter_out_gap_fill", coFloat);
def->label = L("Filter out tiny gaps");
def->category = L("Layers and Perimeters");
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ enum class NoiseType {
Billow,
RidgedMulti,
Voronoi,
DisplacementMap,
};

enum PrintHostType {
Expand Down Expand Up @@ -930,6 +931,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, fuzzy_skin_scale))
((ConfigOptionInt, fuzzy_skin_octaves))
((ConfigOptionFloat, fuzzy_skin_persistence))
((ConfigOptionString, fuzzy_skin_displacement_map))
((ConfigOptionFloat, gap_infill_speed))
((ConfigOptionInt, sparse_infill_filament))
((ConfigOptionFloatOrPercent, sparse_infill_line_width))
Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "fuzzy_skin_scale"
|| opt_key == "fuzzy_skin_octaves"
|| opt_key == "fuzzy_skin_persistence"
|| opt_key == "fuzzy_skin_displacement_map"
|| opt_key == "detect_overhang_wall"
|| opt_key == "overhang_reverse"
|| opt_key == "overhang_reverse_internal_only"
Expand Down
5 changes: 3 additions & 2 deletions src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line(el, has_fuzzy_skin);

NoiseType fuzzy_skin_noise_type = config->opt_enum<NoiseType>("fuzzy_skin_noise_type");
toggle_line("fuzzy_skin_scale", has_fuzzy_skin && fuzzy_skin_noise_type != NoiseType::Classic);
toggle_line("fuzzy_skin_octaves", has_fuzzy_skin && fuzzy_skin_noise_type != NoiseType::Classic && fuzzy_skin_noise_type != NoiseType::Voronoi);
toggle_line("fuzzy_skin_scale", has_fuzzy_skin && (fuzzy_skin_noise_type != NoiseType::Classic && fuzzy_skin_noise_type != NoiseType::DisplacementMap));
toggle_line("fuzzy_skin_octaves", has_fuzzy_skin && fuzzy_skin_noise_type != NoiseType::Classic && fuzzy_skin_noise_type != NoiseType::Voronoi && fuzzy_skin_noise_type != NoiseType::DisplacementMap);
toggle_line("fuzzy_skin_persistence", has_fuzzy_skin && (fuzzy_skin_noise_type == NoiseType::Perlin || fuzzy_skin_noise_type == NoiseType::Billow));
toggle_line("fuzzy_skin_displacement", has_fuzzy_skin && fuzzy_skin_noise_type == NoiseType::DisplacementMap);

bool have_arachne = config->opt_enum<PerimeterGeneratorType>("wall_generator") == PerimeterGeneratorType::Arachne;
for (auto el : { "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
Expand Down
1 change: 1 addition & 0 deletions src/slic3r/GUI/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2353,6 +2353,7 @@ page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only v

optgroup->append_single_option_line("fuzzy_skin");
optgroup->append_single_option_line("fuzzy_skin_noise_type");
optgroup->append_single_option_line("fuzzy_skin_displacement_map");
optgroup->append_single_option_line("fuzzy_skin_point_distance");
optgroup->append_single_option_line("fuzzy_skin_thickness");
optgroup->append_single_option_line("fuzzy_skin_scale");
Expand Down

0 comments on commit e506d73

Please sign in to comment.