Multi nozzle printing with per Extruder Layerheight#580
Open
LixNix wants to merge 7 commits into
Open
Conversation
Port of the mainline OrcaSlicer feature chain to this fork (based on Orca ~2.3.4): - Fix Filament for Features (OrcaSlicer#13607) - Fix + Support 'Default' filament option, index 0 (OrcaSlicer#13887) - Filament for features for SEMM (OrcaSlicer#13937) - Divided filament for features (OrcaSlicer#14042) The coarse per-feature filament selectors are split into six independent ones: outer_wall_filament_id, inner_wall_filament_id, sparse_infill_filament_id, internal_solid_filament_id, top_surface_filament_id and bottom_surface_filament_id. All default to 0 ("Default" = use the active object/part filament) instead of the old 1-based scheme where "1" doubled as the default. Backward compatibility: PrintConfigDef::handle_legacy() renames the old keys (wall_filament, sparse_infill_filament, solid_infill_filament and their pre-Orca aliases) on any config load - presets, 3mf project files and imported G-code alike - and maps the legacy default value 1 to 0. Fork-specific integrations kept working: the mixed-filament manager's per-layer filament resolution (LayerTools resolve_mixed, pointillism and grouped-manual-pattern splitting in GCode::process_layer, effective filament remapping in LayerRegion/Fill), Local-Z clipped collections, SSWCP/Flutter filament slot collection, and the object settings tab resolver all route the new six selectors through the same paths the three old ones used. Mixed perimeter collections are now split into outer/inner sub-collections when the two wall filaments differ.
Port of LixNix/OrcaSlicer-multi-nozzle-size-printing commit 944da13 "Add per extruder layer height" onto this fork. New printer option extruder_layer_height (per extruder): the preferred layer height of each extruder, for printers whose extruders carry different nozzle sizes. Object parts whose walls are assigned to an extruder preferring an integer multiple N of the object layer height print only on every Nth layer with N-times-thicker extrusions wherever geometry allows (region slices are combined at the slicing step); sparse infill assigned to such an extruder is combined up to that height instead. New print options extruder_layer_height_mode (consistent/adaptive) and extruder_layer_height_tolerance control the run combining, and support_nozzle_diameter restricts support, raft and interface printing to filaments of one nozzle diameter. Includes: per-tool line widths on the wipe tower (WipeTower2), tool ordering that skips combined-away layers and prefers nozzle-matching filaments for flushing, per-feature-filament flow resolution (bottom surfaces / external bridges / gap fill print with their own filament's nozzle width), support flow and layer height limits honoring the support nozzle restriction, and extensive Print::validate() checks. Adaptations to this fork: no BBL filament-map rerouting (a filament index is the extruder index on classic multi-tool printers), the single-StringObjectException warning channel of this fork's Print::validate(), mixed-filament (Local-Z / pointillism / grouped patterns) integration kept working - resolved effective filaments feed the new flow lookups and the wipe tower's Local-Z planning gained the same per-tool widths. All new behavior is inert while the new options stay at their defaults (0). Tests: tests/fff_print/test_multi_nozzle_layer_height.cpp (ported to Catch2 v2 and this fork's APIs).
…ment logic Follow-up fixes from an adversarial review of the two ports: - GCode::process_layer's fork-local dispatch lambdas (configured_filament_id_1based / configured_extruder_id) now mirror ToolOrdering's classification: the role of a fill collection is derived from its first non-gap-fill entity, pure gap fill dispatches to the outer wall filament, and external bridges print with the bottom surface filament. Without this, gap fill and external bridges were grouped under a different extruder than ToolOrdering scheduled and than their flow widths were computed for (inert at default settings, wrong once the per-feature filaments diverge). - combine_infill() and its Print::validate() mirror pick the combining filament at 100% sparse density from the sparse infill filament, matching this fork's print-time dispatch (internal_solid_infill_uses_sparse_filament), instead of mainline's internal solid filament. - Per-extruder layer height combining ignores Snapmaker mixed (virtual) filament ids: mixed rows resolve to a different physical extruder per layer, so regions whose walls use them never combine and no preferred height is derived from an out-of-range id. - ToolOrdering::collect_extruders expands grouped manual-pattern mixed filaments for the inner wall exactly like the outer wall, so the wipe tower planner sees every extruder the grouped perimeter split will emit when the two wall filaments differ.
…d per-nozzle sidebar
Make the per-extruder preferred layer heights ("extruder_layer_height")
actually take effect on mixed-nozzle printers and give them a first-class
UI, so each feature of a part prints with the layer height of the
extruder assigned to it wherever physics allows.
Engine (libslic3r):
- A part follows one layer pitch, defined by its wall filaments'
explicit preferences, or by the agreement of its other pitch-bound
feature filaments (top/bottom/internal solid) when no wall filament
carries one. Runs of N base layers combine and extrude once at N
times the object layer height; region tops/bottoms, overhangs and the
first layer keep the finer base layers.
- When the rest of the part vetoes the walls' pitch, the walls still
combine on their own (walls-only pitch); disagreeing explicit wall
preferences meet at the lower height instead of falling back.
- Full-density top surfaces absorb the internal solid layers below them
and extrude once at their filament's preferred height.
- Sparse infill combines separately as before; at 100% density the
combined solid interior is internal solid infill printed with the
internal solid filament (PrintRegion::extruder()).
- Only a nozzle that physically cannot extrude a pitch vetoes it;
min/max layer heights are soft profile limits that warn instead.
- Mixed (virtual) filaments rotate physical extruders per layer and
never combine.
- Tool ordering and G-code dispatch classify wall extrusions per
entity, so overhang-first inner loops, split mixed perimeters and
wipe overrides route to the correct filament.
Validation (Print::validate()):
- Strict errors for wall preferences the printer cannot honor
(below the object layer height, not an integer multiple, above the
nozzle bore) and for line widths below the combined heights.
- Warnings when preferences are ignored, unhonorable, below an
extruder's minimum or above its maximum, when disagreeing wall
preferences meet at the lower height, and when a fine nozzle forces a
part back to the object layer height.
- Per-extruder layer heights are rejected with spiral vase, interface
shells and variable layer height.
GUI:
- The Prepare sidebar shows one tab per nozzle with a Diameter combo
(sets only that nozzle's diameter instead of switching the whole
printer preset) and a Preferred layer height combo listing the valid
multiples of the object layer height for that extruder.
- Changing a nozzle's diameter adopts the layer height limits of the
printer's profile for the new size when one exists and notifies the
user; otherwise it warns to review the limits manually. The tabs
follow the extruder count and refresh on config changes.
- The preview attributes extrusions to the per-feature filaments.
Tests: fff_print [MultiNozzleLayerHeight] scenarios cover region
combining, walls-only pitch, top-surface absorption, bore vetoes,
disagreeing wall preferences and validation errors.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EniRUwSktuaiWwd11GH7FP
Closed
Author
|
Works would appreciate feedback. |
Let the outer and inner walls print at their own layer heights when
they are assigned to filaments with different preferred layer heights
("Filament for Features" wall selectors + per-extruder layer heights).
Splitting is automatic whenever both wall filaments carry explicit
conforming preferred heights and one is a whole multiple of the other
(e.g. inner walls 0.24 mm, outer wall 0.48 mm over a 0.12 mm object
layer height): the finer class prints every time its height is reached
and the coarser class extrudes once per multiple at the full height, so
the two classes' tops stay flush. Either wall class may be the coarse
one, and the finer pitch may equal the object layer height itself.
Where geometry prevents a coarse run (shape drift, caps, first layer),
both classes fall back to printing together at the lower height.
When the two preferred heights do NOT divide evenly, the new "Adjust
wall layer height" option (split_wall_adjust, default off, in the
Filament for Features group) adjusts the wall-only layer height of one
wall filament to the nearest divisor or multiple of the other so the
walls can still split; landing on the other filament's height merges
the walls there instead. Two selections appear while the toggle is on:
which wall filament is adjusted (split_wall_adjust_filament) and
whether its height may only decrease or increase
(split_wall_adjust_direction). Unlike the preferred heights themselves,
adjusted heights are hard-bounded by the adjusted filament's min/max
layer heights and nozzle bore; without a legal candidate in the chosen
direction the walls keep merging at the lower height with the existing
conflict warning. The adjustment applies only to that filament's walls,
its other features keep the preferred height, and validation reports
the adjusted height once as an info message.
Implementation. The decision logic lives in one place,
PrintObject::wall_effective_multipliers() - the raw conforming
multipliers of the two wall classes plus the optional adjustment -
consumed by wall_layer_height_multiplier() (min-merge = the fine
cadence), wall_split_pitches() (unequal + divisible = split) and
Print::validate(). The fine cadence is the existing walls-only run
machinery unchanged. A second marking pass in
apply_extruder_layer_heights() groups whole fine runs into coarse runs
(same shape tolerance and rest-on-object tests, applied across the
whole span) and marks them on the LayerRegions
(wall_split_count/height). LayerRegion::make_perimeters() drops the
coarse class from the fine pass inside committed coarse runs -
classified with perimeter_entity_uses_outer_wall_filament(), the same
predicate the G-code dispatch uses, so cadence and filament routing
agree by construction - and on a coarse-run top regenerates the coarse
class once at the full height with the layer below the run as overhang
reference; both generator passes share one parameterized routine. Thin
/ gap fills and the fill boundaries stay with the fine pass. validate()
detects adjusted classes by comparing effective against raw
multipliers, keeps the min-merge conflict warning silent when a split
or adjustment resolved the disagreement, checks per-class heights
against line widths and max layer heights, and does not count an
adjusted class's own preference as unhonored. Mixed (virtual)
filament ids never combine and never split; the engine code stays
textually aligned with the mainline-Orca fork except for the mixed
guards and the direct filament-to-extruder mapping.
Tests: scenarios for the automatic divisible split (including the
fine-pitch-equals-object-layer-height case), the non-divisible fallback,
and the three adjustment outcomes (decrease to a divisor -> split,
increase onto the other wall's height -> merge there, no legal
candidate -> unchanged fallback with the conflict warning).
Author
|
Something that i forgot to mention in explicitly in the support tap a user can select which nozzle sizes should print the support, so in case multiple things, for example, are printed with .2 nozzles, you can restrict support to just .2 nozzle sizes instead of just being able to select one filament to so support in that case, which would have increased print time. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR makes mixed-nozzle printing practical on multi-tool printers like the Snapmaker U1: each extruder can carry a preferred layer height (
extruder_layer_height, allows selecting layer height via UI on a per extruder basis), and together with the existing Filament for Features selectors, each feature of a part prints with the layer height of the extruder assigned to it wherever physics allows — instead of everything being forced to the finest nozzle's layer height. The added filaments for features were ported from mainline Orcaslicer together with their requirements.Slicing engine
Validation & user feedback
GUI
Profiles
Compatibility / breaking changes
extruder_layer_heightdefaults to 0 (= use the object layer height) on every extruder, so existing profiles and projects slice exactly as before until a preference is set. Existing 3MF projects load unchanged.Screenshots/Recordings/Graphs
Tests
New Catch2 suite
tests/fff_print/test_multi_nozzle_layer_height.cpp([MultiNozzleLayerHeight], 14 cases / 159 assertions) on a four-nozzle 0.2/0.4/0.6/0.8 printer config: whole-region combining, walls-only pitch, top-surface absorption, 100%-density interior ownership, nozzle-bore vetoes, disagreeing wall preferences meeting at the lower height, per-extruder minimum handling, and the validation errors.End-to-end G-code verification with the real Snapmaker U1 profiles: walls assigned to the 0.8 mm extruder print in 0.48 mm runs (tool changes on a test cube drop from ~474 to ~45), combining top surfaces produce a single thick top pass, and the 100%-density interior prints with the Internal solid infill filament.
GUI changes exercised manually: per-nozzle tab rebuild on extruder count changes, live refresh of the valid layer height lists when the base layer height or limits change, notifications on nozzle size changes, and the wall-conflict warning popup.
Full
fff_printsuite: the feature-related cases all pass; the pre-existing failures in unrelated suites fail identically on the base commit.Old PR (removed to to changes and issue in pr and branch): Multi nozzle printing #575
How to Download Pull Requests Artifacts for Testing