FOrcaSlicer v2.3.2-fos.8.4
Fix: Support, Tree Support and the Prime Tower Were All Sized for Nozzle 1
This release is a single theme. Under mixed nozzle sizes, three features computed
their geometry from nozzle 1 no matter which tool actually printed them. Everything here
is a no-op on a uniform-nozzle machine.
Problem
Assign support to filament 2 on a 0.2 / 0.4 / 0.6 / 0.8 machine and the slicer picks the
right nozzle - then tells it to lay a 0.22 mm line, which is nozzle 1's width. The
0.4 mm tip is asked for a bead thinner than itself.
The prime tower was worse. Every tool wiped at 1.0 mm and rammed at 2.0 mm - the
0.2 mm nozzle included, at 5x and 10x its own diameter.
None of this is a rounding error. These are extrusions a nozzle physically cannot lay.
Root Cause
The rule already existed. Nothing outside walls and infill was using it.
Absolute line widths in a process preset are authored against nozzle 1, the reference
nozzle the preset was resolved with. Any feature printed by a different tool must have
that width re-derived by ratio. PrintRegion::flow() has done exactly this for
frExternalPerimeter / frPerimeter / frInfill / frSolidInfill / frTopSolidInfill
all along:
// config_width may have been resolved against nozzle 1 already;
// recompute using actual extruder's nozzle
float ref_nozzle = float(print_config.nozzle_diameter.get_at(0));
config_width.value = (config_width.value / ref_nozzle) * nozzle_diameter;Support roles are not in that list, and support never passes through PrintRegion::flow()
at all - it goes through free functions in Flow.cpp that pick the right nozzle and then
hand it an unadjusted width.
Tree support was wrong in a second way. support_extrusion_width - which sizes the
tree base - was read from support_interface_filament's nozzle, not the base's. Two
further sites hardcoded nozzle_diameter.get_at(0), pinning branch spacing and collision
resolution to nozzle 1 outright.
The prime tower kept a single scalar and overwrote it. WipeTower2::m_perimeter_width
is assigned inside set_extruder(), which is called once per filament - so the last
filament configured won, by accident of iteration order. On 0.2/0.4/0.6/0.8 that is
0.8 x 1.25 = 1.0 mm, for everyone. The code states the assumption out loud:
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio;
// all extruders are now assumed to have the same diameterMeanwhile m_filpar[idx].nozzle_diameter had been populated all along and never read -
its comment says "to be used in future with (non-single) multiextruder MM".
Changes
src/libslic3r/Flow.hpp / Flow.cpp
- New
fos_width_for_nozzle()- the nozzle-1 -> printing-nozzle ratio rule, exported so
support,SupportParametersandTreeSupportall derive widths identically rather
than three different ways. Percent widths are passed through untouched;
get_abs_value()already ratios over the nozzle it is given. support_material_flow,support_material_1st_layer_flowand
support_material_interface_flownow route through it.
src/libslic3r/Support/SupportParameters.hpp
support_extrusion_widthnow comes fromsupport_filament(was
support_interface_filament) and is ratio-derived. It sizes the support base, so it was
taking its dimensions from the wrong tool.
src/libslic3r/Support/TreeSupport.cpp
- Two hardcoded
nozzle_diameter.get_at(0)reads replaced with the support filament's
nozzle, ratio-derived. These drive tree collision resolution and branch spacing - a tree
printed by a 0.6 mm tool was being built to 0.2 mm dimensions.
src/libslic3r/GCode/WipeTower2.cpp / .hpp
The scalar was doing two jobs. They are now separate:
- Structure width - footprint, box margins, brim spacing, and the tower's perimeter
and sparse fill - is bound towipe_tower_filament, the tool that genuinely prints
them. (set_extruder()marks that filament as the only non-soluble one, so
first_toolchange_to_nonsoluble()landsfinish_layeron it.) Previously this value was
whicheverset_extruder()call happened to run last. - Wipe and ramming now extrude at each tool's own width and flow, from
m_filpar[tool].nozzle_diameter. - Depth planning follows.
plan_toolchange()andsave_on_last_wipe()reserve depth
using the same per-tool widths. Width and spacing have to move together - fix the width
alone and the purge block over- or under-fills, and the reserved depth stops matching
the lines emitted.
Ramming's E is volumetric (ramming_speed * time / filament_area), so only the line
length changes. Purged volume is unaffected.
src/slic3r/GUI/*, src/libslic3r/Print.cpp - "Default" is gated
Support/raft base, Support/raft interface and Wipe tower offer a
Default option meaning whichever filament is already loaded prints this. Under mixed
nozzles that is not a valid choice, and it cannot be made one:
Support paths are generated once, at slicing time, with a single flow. The tool is not
chosen until G-code export - whereToolOrderingreassigns the tool on
already-generated extrusions and nothing re-renders them. A path built for a 0.2 mm tip
can be handed to a 0.8 mm tip.
So when nozzle diameters differ:
- Those three dropdowns show "Empty" instead of "Default".
- The slicer refuses to slice until you choose a filament, and names which dropdown is
blank.
The unset value is deliberately not auto-filled with filament 1 - silently landing on
nozzle 1 is precisely the bug being fixed. On a uniform-nozzle machine, "Default" behaves
exactly as before.
Version
FOS_VERSION->2.3.2-fos.8.4; installerVIProductVersion2.3.2.8->2.3.2.9.
Result
Verified in G-code on a 0.2 / 0.4 / 0.6 / 0.8 machine, support base on filament 3,
interface on filament 2, wipe tower on filament 2:
| before | after | |
|---|---|---|
| Support (0.6 mm tool) | 0.22 mm | 0.66 mm ✓ |
| Support interface (0.4 mm tool) | 0.22 mm | 0.44 mm ✓ |
| Tower wipe, tools 0-3 | 1.0 / 1.0 / 1.0 / 1.0 | 0.25 / 0.5 / 0.75 / 1.0 ✓ |
| Tower ramming, tools 0-3 | 2.0 / 2.0 / 2.0 / 2.0 | 0.5 / 1.0 / 1.5 / 2.0 ✓ |
- Purge block stays inside the tower wall - depth planning tracks the new widths ✓
- Tree support branch spacing now scales with the support nozzle ✓
- Uniform-nozzle slices are unchanged. A 0.6 / 0.6 / 0.6 / 0.6 job produces the same
support width (0.62 mm), the same tower widths (0.75 / 1.5 mm) and the same extrusion
counts as before ✓
Upgrade Note
If you use mixed nozzles and support or a prime tower, you will be asked to pick a
filament for Support/raft base, Support/raft interface and Wipe tower the
first time you slice. Projects saved before 8.4 may open with these blank; the slicer will
tell you which one it needs. This is intentional - previously those settings silently
resolved to nozzle 1.
Uniform-nozzle users are unaffected and need do nothing.
Known Issues
Support layer height still follows nozzle 1. Consistent with the 8.x rule that all
nozzles follow nozzle 1's process settings, but it means a 0.8 mm nozzle can be asked to
print 0.1 mm support layers. A layer-height clamp would be a new feature, not a fix, and
is deferred.
Ramming-to-wipe alignment. The Y offsets that align the ramming block to the first
wipe line still use the tower's structure width, so with per-tool widths they can be off
by up to ~0.4 mm. Cosmetic; it does not affect purge volume or tower geometry.
Thick internal bridges (carried from 8.2/8.3, not a regression). An internal bridge
extrudes at nozzle_diameter * sqrt(bridge_flow) with no clamp against layer height. This
is upstream OrcaSlicer behavior - stock Orca with uniform 0.8 mm nozzles at 0.24 mm layers
produces the same effect. Mixed nozzles change the magnitude, not the mechanism. Workaround:
disable Thick internal bridges when the solid-infill nozzle is much larger than the
layer height.