Integrations up to commit b3c41fda4180a2946812726218d0a849be0aedb6.
- libslic3r: vendor FilamentMixer; MixedFilamentManager (auto-gen, resolve,
serialize; manual-pattern / gradient / pointillism); 19 new PrintConfig
keys; PresetBundle owns the canonical manager with 3MF + AppConfig
roundtrip and AMS-safe strip+restore; Print owns the slicing-time copy
with PrintApply auto-regen on color change; TriangleSelector::
shift_states_above + filament-id remap; inset_idx propagation through
ExtrusionPath/Loop/MultiPath copy/assign.
- Slicing: virtual filament IDs in painted regions (same-physical channels
collapse when mixed_filament_region_collapse is on); ByObject
collect_filament_data expands mixed slots; pair-cadence + whole-object +
3+component Local-Z plan generators; LocalZOrderOptimizer utility.
- GCode + ToolOrdering: LayerTools resolves virtual IDs through wall /
infill / sparse / solid queries; SameLayerPointillisme in process_layer
(uniform-segment + grouped per-perimeter-index splitters); WipeTower2
Local-Z reservation + sub-layer G-code emission; per-layer infill
filament override.
- PartPlate: get_extruders* expand virtual slots into physical components;
CLI path rebuilds a local manager from full_config.
- GUI: five widget files extracted from FS Plater.cpp (~5000 LOC) —
MixedMixPreview, MixedGradientSelector + WeightsDialog,
MixedFilamentColorMapPanel, MixedFilamentColorMatchDialog (ΔE₀₀ recipe
search), MixedFilamentConfigPanel; Sidebar Mixed Filaments panel
(drag-reorder, enable/delete, Add Gradient/Pattern/Color); Tab exposure
of mixed-filament / dithering / per-layer infill-override settings +
ConfigManipulation visibility and slot-validation rules;
BBLMixedFilamentBroken / BBLSingleExtruderMixedFilamentRisk
notifications + slice gate; WipeTowerDialog edits physical P×P
sub-matrix; bounds-safe extruder_id guards in 3DScene / GLCanvas3D /
GLGizmoMmuSegmentation; change_filament merge guard and
on_filaments_delete is_mixed_before_delete propagation.
- Tests: 4 Catch2 tests for 3MF roundtrip (auto/custom persistence,
PresetBundle string path, total_filaments stability); full-pipeline
slice E2E deferred — TODO in file.
Co-authored-by: Rad <radugheorghiu96@gmail.com>
Co-authored-by: Justin Hayes <justinh@rahb.ca>
Co-authored-by: Calogero Guagenti <calogeroguagenti@gmail.com>
Co-authored-by: xSil3nt <ahmedshazin21@gmail.com>
Co-authored-by: ratdoux <62392831+ratdoux@users.noreply.github.com>
Co-authored-by: Rad <radugheorghiu96@gmail.com>
Co-authored-by: Justin Hayes <justinh@rahb.ca>
Co-authored-by: Calogero Guagenti <calogeroguagenti@gmail.com>
Co-authored-by: xSil3nt <ahmedshazin21@gmail.com>
Co-authored-by: ratdoux <62392831+ratdoux@users.noreply.github.com>
7.7 KiB
Mixed Filament
Ported from OrcaSlicer-FullSpectrum with contributions from Rad, Justin Hayes, Calogero Guagenti, xSil3nt, and ratdoux.
User Guide
What It Does
Mixed Filament lets a single virtual filament slot alternate between two physical filaments across layers (or within a layer in Pointillisme mode), producing blended or gradient-like colours on single-extruder printers.
Enabling
- Load a multi-colour (multi-extruder) profile with at least 2 filaments.
- The Mixed Filaments panel appears automatically in the right-hand sidebar when 2 or more filaments are configured.
- Each auto-generated row represents one pair of physical filaments. Toggle a row to enable it; the total filament count grows to include the virtual slot.
Sidebar Workflow
- Add — creates a custom row for the same pair or a different ratio.
- Edit — opens
MixedFilamentConfigPanelto adjust ratio, pattern, surface offset (bias), and distribution mode. - Delete — marks the row deleted; existing painted geometry retains its virtual filament ID until you re-slice or repaint.
Painting with a virtual filament ID behaves the same as painting with a physical one — use the Multi-Material Painting gizmo and select the virtual slot from the colour palette.
Color Match Dialog
Open via the colour swatch on a mixed row. The dialog (MixedFilamentColorMatchDialog)
shows a live preview strip of the blended result and lets you adjust ratio
until the preview matches your target colour. The preview accounts for
surface-offset bias when enabled.
Anti-Banding Options
| Setting | What it does |
|---|---|
mixed_filament_advanced_dithering |
Uses an ordered dither pattern instead of simple A-then-B runs. Reduces stripe visibility on some hue pairs. More experimental than the default. |
dithering_local_z_mode |
Splits each blended layer into two sub-layers whose heights are proportional to the mix ratio (e.g. 66/33 at 0.12 mm → 0.08 mm + 0.04 mm). Produces the smoothest colour gradients. |
dithering_local_z_whole_objects |
Extends Local-Z splitting beyond painted masks to cover the entire object cross-section. Useful when mixed walls surround a painted zone. |
dithering_local_z_direct_multicolor |
For rows with 3 or more physical components, allocates Local-Z sub-layers directly across all components with carry-over error correction instead of collapsing to pair cadence. More toolchanges; less banding. |
Gotchas
- Single-extruder warning — Mixed Filament requires a physical toolchange
between the two components. On a true single-nozzle printer this means a
manual filament swap. Verify your printer profile supports
T0/T1before using mixed slots in a production print. - Variable-layer interaction — If Variable Layer Height is enabled, Local-Z sub-layer heights are recomputed per interval. The mix ratio is preserved but the absolute sub-layer heights change with the variable height. Review the layer preview after applying variable layers.
- Custom sequence disabled — OrcaSlicer's "custom toolchange sequence" is
suppressed when mixed filaments are active (
PlateSettingsDialog). The virtual-to-physical resolution must control toolchange order; a user-defined sequence would break it. - Stable IDs — each mixed row carries a
stable_id(64-bit). If you reorder or delete rows and then load an older project, the ID remap inPresetBundle::update_mixed_filament_id_remaptranslates painted geometry to the correct new virtual slot. Do not rely on the 1-based filament index as a stable identifier.
Developer Guide
Core Data Structures
src/libslic3r/MixedFilament.hpp — MixedFilament struct, MixedFilamentManager
src/libslic3r/MixedFilament.cpp — serialization, resolve(), auto_generate()
src/libslic3r/LocalZOrderOptimizer.hpp — bucket-ordering helpers for Local-Z
The key scalar fields on MixedFilament:
component_a,component_b— 1-based physical filament indices.ratio_a,ratio_b— layer-alternation cadence numerators.mix_b_percent— nominal colour mix (used for Local-Z height computation and the Color Match preview; does not change the cadence).stable_id— monotonically increasing 64-bit ID assigned at construction. Never reused. Survives serialization round-trips.distribution_mode— selects betweenSimple,SameLayerPointillisme, andGroupedManual.
Seam: Adding New Distribution Modes
MixedFilamentManager::resolve() in MixedFilament.cpp is the single
dispatch point that maps (virtual_filament_id, num_physical, layer_index)
to a physical extruder. The current switch covers Simple and
SameLayerPointillisme. A new mode is added by:
- Adding a value to the
MixedFilament::DistributionModeenum inMixedFilament.hpp. - Adding a
casetoMixedFilamentManager::resolve()inMixedFilament.cpp. - Serializing the new mode token in
serialize_custom_entries/load_custom_entries(format is a semicolon-delimited row string; see existing tokens for the convention).
G-code emission (src/libslic3r/GCode/) reads only the physical ID returned
by resolve(), so new modes are automatically emitted without further changes.
Seam: New Toolchange-Cost Heuristics
LocalZOrderOptimizer (src/libslic3r/LocalZOrderOptimizer.hpp) exposes:
order_bucket_extruders(bucket, current, preferred_last)— reorders a single-layer bucket to minimise toolchanges given the current active extruder.order_pass_group(group, current_extruder)— greedy walk across a set of buckets (one per Local-Z sub-layer) to minimise total transitions.
To add a new heuristic (e.g. cost-based look-ahead), replace or wrap
order_pass_group. The caller in PrintObjectSlice.cpp passes the result
directly into the sub-layer plan, so the heuristic is fully decoupled from
the plan builder.
Seam: New Picker Shapes in the Color Map Panel
MixedFilamentColorMapPanel (src/slic3r/GUI/MixedFilamentColorMapPanel.hpp)
renders a 2-D colour map using a set of geometry "types" (currently strip and
gradient). Each type is a small self-contained rendering path keyed by an enum
value. New shapes are added by:
- Adding an enum value to
MixedFilamentColorMapPanel::GeometryType. - Implementing the corresponding
Paint*helper (followPaintStripas a template). - Wiring the new type into the
switchinOnPaint.
Persistence (3MF)
The entire mixed-filament state is stored as a single string key
mixed_filament_definitions in the project config block (section [presets]
in the 3MF metadata).
Round-trip path:
MixedFilamentManager::serialize_custom_entries()
called by PresetBundle::sync_mixed_filaments_to_config()
written by bbs_3mf: store_bbs_3mf → config.set("presets", "mixed_filament_definitions", ...)
load_bbs_3mf → config.get("presets", "mixed_filament_definitions")
stored in project_config["mixed_filament_definitions"]
read by PresetBundle::sync_mixed_filaments_from_config()
→ mixed_filaments.auto_generate(colours)
→ mixed_filaments.load_custom_entries(defs, colours)
Auto-generated rows are not written to the definitions string; they are
rebuilt from the filament colour list. Only custom == true rows are stored.
See tests/fff_print/test_mixed_filament_e2e.cpp for regression tests
covering this path.
ID Remap
When filaments are added, removed, or reordered, virtual IDs shift.
PresetBundle::update_mixed_filament_id_remap(old_mixed, old_count, new_count)
produces a remap vector where remap[old_virtual_id] = new_virtual_id.
Painted triangle mesh face data uses these IDs; the remap is applied in
TriangleSelectorMixed after any filament list change.