Belt Printer Slicing #113

Open
opened 2026-04-05 16:18:30 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @HarrierPigeon on 3/28/2026

Add belt printer support to OrcaSlicer

...and:

  • generic shear transforms
  • axis swapping
  • axis mirroring
  • configurable slicing planes for normal printers too

Description

This PR adds nearly comprehensive belt printer (conveyor belt / infinite-Z) support to OrcaSlicer. Belt printers use a tilted conveyor belt as the build surface instead of a flat horizontal bed, which fundamentally changes the geometry of slicing, support generation, and G-code output.

The problem belt printers pose for a slicer

OrcaSlicer (and most other slicers) assume that the bed is on the XY plane, and that layers are horizontal cross-sections.

IMG_0261

On belt printers, the motor that advances the belt is usually the Z axis, meaning that the bed is now on the XZ plane.
IMG_0262

Note

This means that most belt printers are intentionally violating the right-hand rule. That definitely didn't hurt my head at all. :/

To make things more complicated, we also need to deal with the fact that the slicer still wants to make g-code frames in the XY plane, and it wants to do so in a normal cartesian space, which means we have to modify the inputs to keep the slicing relatively untouched.

Thankfully, most belt printers still have normal XY gantries, so all we have to do is swap the axes of the mesh around. (Usually this is a Y-Z swap.) This is done as a local transform.

Unfortunately, we're still not out of the woods yet, because we need to deal with the belt printer's angle.

This is done by adding height to the Z-coordinates of the object mesh depending on the Y position of the part.

        
Z = Z' + Y \cdot \cot(\alpha)

Now that objects are sheared and in the right coordinate space, the part can be sliced like normal and it should just work. Nice!

However, because we sliced in a funky coordinate system (local coordinate swaps on a global non-swapped coordinate system) we need to snap the lower coordinates of the bounding boxes back to the axis origin in order to keep the Y-coordinates from growing.

Important

If you're reading this and you think you know where the pipeline broke down to require axis origin snapping, I'm all ears. This feels like a bit of a kludge, but it works in all tested cases so ummmmmm....

This is what the basic slicing workflow looks like without any axis swapping.
IMG_0265

note: back-transforms are only required if going back to a fully cartesian printer (aka what 99% of printers are,) and not when using a belt printer

Supports

Supports are handled after slicing the part. These are handled by essentially putting in a fake surface on the shear transform base plane, and letting supports generate to that. This means that there aren't brims on these supports, but it was also the least invasive way to get the feature working.

Changes by commit

Part 1: Belt printer transform pipeline

  • Implement core belt slicing pipeline: R(-alpha, X) mesh rotation in PrintObjectSlice with corrected object height calculation for proper layer count
  • Add to_machine_coords() in GCodeWriter to convert slicing-frame coordinates back to machine-frame, propagated through GCode, GCodeProcessor, and GCodeViewer
  • Add belt-mode UI: tilted bed visualization, slicing-direction arrow, and raw G-code toggle to switch between machine-frame and slicing-frame views

Part 2: Per-axis shear transforms and G-code axis remap

  • Replace monolithic belt rotation transform with independent per-axis shear controls (mode/angle/source-axis for X, Y, Z) and G-code axis remapping, giving full flexibility to match any belt printer's coordinate system
  • Remove all rotation mode logic, simplifying the pipeline to pure shear matrices while preserving the default behavior (Y += Z*cot(45deg) with identity remap)
  • Clean up GCodeWriter, GCodeProcessor, and GCodeViewer for the new shear-only model; expose 12 new settings in printer UI

(yes, we're missing parts 2.1-2.4. They didn't work.)

Part 2.5: Global shear transform and belt UI

  • Implement per-object global shear transform in PrintObject with layer Z-offset calculation, config invalidation, and fix for shared-object layer optimization breaking copied objects
  • Clip support layers to the transformed belt floor plane
  • Improve belt UI: gray out inactive sub-options, add B keyboard shortcut for G-code viewer design-view toggle, fix mesh clipping through build plate after shear/scale transform

Part 2.6: Belt floor support clipping for all support types

  • Fix support clipping z-shift calculation by removing coordinate-space mismatch and sync belt_floor_z_shift with global_z_offset in global shear mode
  • Add belt floor polygon clipping to non-organic tree support (slim/strong/hybrid) with collision surface integration in TreeSupportData, belt extension layers, and first-layer brim suppression
  • Add belt floor clipping to organic tree support pipeline with virtual belt raft layers, per-layer polygons in TreeModelVolumes, and post-generation layer trimming
  • Fix pre-existing processing_last_mesh bug in TreeModelVolumes::calculateCollision() that prevented m_anti_overhang (support blockers) from ever being applied in the organic pipeline

Part 2.7: G-code back-transform

  • Add BeltBackTransform class that inverts the shear/scale matrix and applies it in GCodeWriter::to_machine_coords() so G-code outputs in the machine's physical coordinate space, gated by belt_gcode_back_transform config option
  • Fix tree drop_nodes() belt termination, organic support global Z offset, and collision calculation index bug

Part 3.1: Refactor into shared classes

  • Extract belt G-code logic into BeltGCode class consolidating shear matrix construction, back-transform initialization, and config validation
  • Extract machine coordinate conversion into BeltGCodeWriter class wrapping axis remapping and back-transform application
  • Extract belt floor polygon logic into BeltFloorContext class, replacing duplicated inline polygon construction across SupportMaterial.cpp, TreeSupport.cpp, TreeSupport3D.cpp, and TreeModelVolumes.cpp

Part 3.2: Decouple axis remapping

  • Decouple axis remapping from belt mode so it can be used independently
  • Enable viewing belt settings in Developer mode or when Belt mode is active

New config options (printer-level)

Option Type Description
belt_printer bool Enable belt printer mode
belt_printer_angle float Belt tilt angle (degrees)
belt_printer_infinite_y bool Infinite Y axis (conveyor)
belt_shear_{x,y,z} enum Shear mode per axis (None/PosCot/NegCot/PosTan/NegTan)
belt_shear_{x,y,z}_angle float Shear angle per axis
belt_shear_{x,y,z}_from enum Source axis for shear (X/Y/Z)
belt_gcode_remap_{x,y,z} enum G-code axis remapping
belt_gcode_back_transform bool Enable inverse transform in G-code output

Files changed (49 files, +3457 / -305)

New files

  • src/libslic3r/BeltGCode.{cpp,hpp} - Belt G-code initialization and config
  • src/libslic3r/BeltGCodeWriter.{cpp,hpp} - Machine coordinate conversion
  • src/libslic3r/BeltSliceStrategy.{cpp,hpp} - Slicing strategy for belt mode
  • src/libslic3r/BeltTransform.{cpp,hpp} - Shear/scale transform matrices
  • src/libslic3r/GCode/BeltBackTransform.{cpp,hpp} - Inverse transform for G-code
  • src/libslic3r/Support/BeltFloorContext.{cpp,hpp} - Belt floor polygon computation

Core slicing

  • PrintConfig.{cpp,hpp} - 12+ new config options for belt shear/remap
  • PrintObject.cpp - Global shear Z-offset, support Z-offset handling, invalidation
  • PrintObjectSlice.cpp - Shear transform in slice pipeline, belt z-shift computation
  • Print.{cpp,hpp} - Belt mode validation, arc fitting disable, feature gating
  • GCode.{cpp,hpp} - Belt transform init, empty first layer bypass
  • GCodeWriter.{cpp,hpp} - to_machine_coords() with shear inverse + axis remap
  • Slicing.hpp - Belt floor parameters in SlicingParameters

Support generation

  • Support/SupportMaterial.cpp - Belt floor surface/valid-region polygon functions
  • Support/SupportCommon.hpp - Shared declarations
  • Support/TreeSupport.{cpp,hpp} - Belt floor collision, extension layers, brim skip
  • Support/TreeSupport3D.cpp - Organic belt floor clipping, belt raft layers
  • Support/TreeModelVolumes.{cpp,hpp} - Anti-overhang belt floor, per-layer polygons

GUI

  • GUI/3DBed.{cpp,hpp} - Tilted bed visualization
  • GUI/Tab.cpp - Belt printer settings UI
  • GUI/Plater.cpp - Belt mode toggle, slicing arrow
  • GUI/GCodeViewer.{cpp,hpp} - Raw/designed view toggle
  • GUI/ConfigManipulation.cpp - Belt mode feature gating (disable skirt/brim/raft)

What Works Today

  • Builds Pass on Linux, macOS, and Windows
    • Builds tested almost exclusively on Ubuntu 24.04.4 LTS on a fresh install with nVidia drivers.
  • All support types work
  • Arbitrary slicing angles
  • Local and global arbitrary shear planes
  • Test G-code back-transform produces valid machine coordinates
  • Axis Remapping
  • Multiple objects on belt (global Z offset correctness)

Known Issues

  • The settings are not simple yet. Some of the logic in them is slightly overlapping. There's a lot of freedom, but it's easy to get lost in the settings.
    • this cost me several hours but was made up for because I could test significantly more options per build.
  • There are no default printers yet. I don't have a functional belt printer yet to test against, but my BabyBelt Pro will be done soon.
  • Multimaterial / Multicolor prints have not been tested in any way. This is on the roadmap but hasn't been implemented yet.
  • No first layer compensation - G-code that lands on the buildplate needs to have first layer height thickness / overextrusion applied to make things stick better.
  • Brims are disabled.
  • My brain is fried and I need more eyes on this and testing to happen.
  • Several warnings about G-Code (mostly empty layer warnings). These haven't been disabled yet on purpose.
  • Previewing in machine frame coordinates doesn't work.
  • Support propagation direction needs some work

How To Test

  1. Enable Developer Mode in Preferences
    • Developer mode is no longer required for axis swapping if belt printing is enabled.
  2. Create a new printer. Aside from your normal setup, enable belt printer mode.
  3. Copy the following settings as defaults:
Setting Value
Mesh Shear X None
Mesh Shear Y None
Mesh Shear Z +cot(a)
Mesh Shear Z Angle your printer's angle, in degrees. Might need the inverse (i.e. 60* instead of 30*)
Mesh Shear Z Global TRUE
Pre-Slice Axis Remap Swap Y and Z
Origin Snap Y TRUE note: offset can be set negative to get the nozzle closer to the belt
Support Floor Mode Generator Only

Warning

Do not enable g-code back-transform unless you want to run tests on a normal printer. If you do that, check your nozzle and toolhead geometry and run shallow transform angles.

Screenshots

Screenshot from 2026-03-27 14-55-02 Screenshot 2026-03-27 144051

Tree Slim support at 30 degrees

tree-slim-global-30deg

G-Code Backtransform Result

This is, to my knowledge, the first benchy sliced and printed in Orcaslicer with a nonstandard slicing plane. One filament swap when I ran out of filament. Printed on a standard Sovol SV08 with the toolhead cover removed.
20260326_142754
20260326_142832

Slicer Recordings

G-Code Backtransform

https://github.com/user-attachments/assets/cdb9cc83-711d-48b7-9d86-a014a32c5e8e

Closes #2628
Closes #11344
Closes #6885
Closes #9004

*Originally created by @HarrierPigeon on 3/28/2026* # Add belt printer support to OrcaSlicer ...and: * generic shear transforms * axis swapping * axis mirroring * configurable slicing planes for normal printers too ## Description This PR adds nearly comprehensive belt printer (conveyor belt / infinite-Z) support to OrcaSlicer. Belt printers use a tilted conveyor belt as the build surface instead of a flat horizontal bed, which fundamentally changes the geometry of slicing, support generation, and G-code output. ### The problem belt printers pose for a slicer OrcaSlicer (and most other slicers) assume that the bed is on the XY plane, and that layers are horizontal cross-sections. ![IMG_0261](https://github.com/user-attachments/assets/a4d81a27-8a3b-467a-ab97-fe810d148b3a) On belt printers, the motor that advances the belt is usually the Z axis, meaning that the bed is now on the XZ plane. ![IMG_0262](https://github.com/user-attachments/assets/10140565-d363-4c67-8917-581d346feec1) > [!NOTE] > This means that most belt printers are intentionally violating the right-hand rule. That definitely didn't hurt my head at all. :/ To make things more complicated, we also need to deal with the fact that the slicer still wants to make g-code frames in the XY plane, *and* it wants to do so in a normal cartesian space, which means we have to modify the inputs to keep the slicing relatively untouched. Thankfully, most belt printers still have normal XY gantries, so all we have to do is swap the axes of the mesh around. (Usually this is a Y-Z swap.) This is done as a local transform. Unfortunately, we're still not out of the woods yet, because we need to deal with the belt printer's angle. This is done by adding height to the Z-coordinates of the object mesh depending on the Y position of the part. $$ Z = Z' + Y \cdot \cot(\alpha) $$ Now that objects are sheared and in the right coordinate space, the part can be sliced like normal and it should just *work*. Nice! However, because we sliced in a funky coordinate system (local coordinate swaps on a global non-swapped coordinate system) we need to snap the lower coordinates of the bounding boxes back to the axis origin in order to keep the Y-coordinates from growing. > [!IMPORTANT] > If you're reading this and you think you know where the pipeline broke down to require axis origin snapping, I'm all ears. This feels like a bit of a kludge, but it works in all tested cases so ummmmmm.... This is what the basic slicing workflow looks like without any axis swapping. <img width="12720" height="9536" alt="IMG_0265" src="https://github.com/user-attachments/assets/46d87e95-820c-4124-add0-635f4b7bb656" /> > *note: back-transforms are only required if going _back_ to a fully cartesian printer (aka what 99% of printers are,) and not when using a belt printer* #### Supports Supports are handled *after* slicing the part. These are handled by essentially putting in a fake surface on the shear transform base plane, and letting supports generate to that. This means that there aren't brims on these supports, but it was also the least invasive way to get the feature working. ## Changes by commit ### Part 1: Belt printer transform pipeline - Implement core belt slicing pipeline: `R(-alpha, X)` mesh rotation in `PrintObjectSlice` with corrected object height calculation for proper layer count - Add `to_machine_coords()` in `GCodeWriter` to convert slicing-frame coordinates back to machine-frame, propagated through `GCode`, `GCodeProcessor`, and `GCodeViewer` - Add belt-mode UI: tilted bed visualization, slicing-direction arrow, and raw G-code toggle to switch between machine-frame and slicing-frame views ### Part 2: Per-axis shear transforms and G-code axis remap - Replace monolithic belt rotation transform with independent per-axis shear controls (mode/angle/source-axis for X, Y, Z) and G-code axis remapping, giving full flexibility to match any belt printer's coordinate system - Remove all rotation mode logic, simplifying the pipeline to pure shear matrices while preserving the default behavior (`Y += Z*cot(45deg)` with identity remap) - Clean up `GCodeWriter`, `GCodeProcessor`, and `GCodeViewer` for the new shear-only model; expose 12 new settings in printer UI (yes, we're missing parts 2.1-2.4. They didn't work.) ### Part 2.5: Global shear transform and belt UI - Implement per-object global shear transform in `PrintObject` with layer Z-offset calculation, config invalidation, and fix for shared-object layer optimization breaking copied objects - Clip support layers to the transformed belt floor plane - Improve belt UI: gray out inactive sub-options, add B keyboard shortcut for G-code viewer design-view toggle, fix mesh clipping through build plate after shear/scale transform ### Part 2.6: Belt floor support clipping for all support types - Fix support clipping z-shift calculation by removing coordinate-space mismatch and sync `belt_floor_z_shift` with `global_z_offset` in global shear mode - Add belt floor polygon clipping to non-organic tree support (slim/strong/hybrid) with collision surface integration in `TreeSupportData`, belt extension layers, and first-layer brim suppression - Add belt floor clipping to organic tree support pipeline with virtual belt raft layers, per-layer polygons in `TreeModelVolumes`, and post-generation layer trimming - Fix pre-existing `processing_last_mesh` bug in `TreeModelVolumes::calculateCollision()` that prevented `m_anti_overhang` (support blockers) from ever being applied in the organic pipeline ### Part 2.7: G-code back-transform - Add `BeltBackTransform` class that inverts the shear/scale matrix and applies it in `GCodeWriter::to_machine_coords()` so G-code outputs in the machine's physical coordinate space, gated by `belt_gcode_back_transform` config option - Fix tree `drop_nodes()` belt termination, organic support global Z offset, and collision calculation index bug ### Part 3.1: Refactor into shared classes - Extract belt G-code logic into `BeltGCode` class consolidating shear matrix construction, back-transform initialization, and config validation - Extract machine coordinate conversion into `BeltGCodeWriter` class wrapping axis remapping and back-transform application - Extract belt floor polygon logic into `BeltFloorContext` class, replacing duplicated inline polygon construction across `SupportMaterial.cpp`, `TreeSupport.cpp`, `TreeSupport3D.cpp`, and `TreeModelVolumes.cpp` ### Part 3.2: Decouple axis remapping - Decouple axis remapping from belt mode so it can be used independently - Enable viewing belt settings in Developer mode or when Belt mode is active ## New config options (printer-level) | Option | Type | Description | |--------|------|-------------| | `belt_printer` | bool | Enable belt printer mode | | `belt_printer_angle` | float | Belt tilt angle (degrees) | | `belt_printer_infinite_y` | bool | Infinite Y axis (conveyor) | | `belt_shear_{x,y,z}` | enum | Shear mode per axis (None/PosCot/NegCot/PosTan/NegTan) | | `belt_shear_{x,y,z}_angle` | float | Shear angle per axis | | `belt_shear_{x,y,z}_from` | enum | Source axis for shear (X/Y/Z) | | `belt_gcode_remap_{x,y,z}` | enum | G-code axis remapping | | `belt_gcode_back_transform` | bool | Enable inverse transform in G-code output | ## Files changed (49 files, +3457 / -305) ### New files - `src/libslic3r/BeltGCode.{cpp,hpp}` - Belt G-code initialization and config - `src/libslic3r/BeltGCodeWriter.{cpp,hpp}` - Machine coordinate conversion - `src/libslic3r/BeltSliceStrategy.{cpp,hpp}` - Slicing strategy for belt mode - `src/libslic3r/BeltTransform.{cpp,hpp}` - Shear/scale transform matrices - `src/libslic3r/GCode/BeltBackTransform.{cpp,hpp}` - Inverse transform for G-code - `src/libslic3r/Support/BeltFloorContext.{cpp,hpp}` - Belt floor polygon computation ### Core slicing - `PrintConfig.{cpp,hpp}` - 12+ new config options for belt shear/remap - `PrintObject.cpp` - Global shear Z-offset, support Z-offset handling, invalidation - `PrintObjectSlice.cpp` - Shear transform in slice pipeline, belt z-shift computation - `Print.{cpp,hpp}` - Belt mode validation, arc fitting disable, feature gating - `GCode.{cpp,hpp}` - Belt transform init, empty first layer bypass - `GCodeWriter.{cpp,hpp}` - `to_machine_coords()` with shear inverse + axis remap - `Slicing.hpp` - Belt floor parameters in `SlicingParameters` ### Support generation - `Support/SupportMaterial.cpp` - Belt floor surface/valid-region polygon functions - `Support/SupportCommon.hpp` - Shared declarations - `Support/TreeSupport.{cpp,hpp}` - Belt floor collision, extension layers, brim skip - `Support/TreeSupport3D.cpp` - Organic belt floor clipping, belt raft layers - `Support/TreeModelVolumes.{cpp,hpp}` - Anti-overhang belt floor, per-layer polygons ### GUI - `GUI/3DBed.{cpp,hpp}` - Tilted bed visualization - `GUI/Tab.cpp` - Belt printer settings UI - `GUI/Plater.cpp` - Belt mode toggle, slicing arrow - `GUI/GCodeViewer.{cpp,hpp}` - Raw/designed view toggle - `GUI/ConfigManipulation.cpp` - Belt mode feature gating (disable skirt/brim/raft) ## What Works Today - Builds Pass on Linux, macOS, and Windows - Builds tested almost exclusively on Ubuntu 24.04.4 LTS on a fresh install with nVidia drivers. - All support types work - Arbitrary slicing angles - Local and global arbitrary shear planes - Test G-code back-transform produces valid machine coordinates - Axis Remapping - Multiple objects on belt (global Z offset correctness) ## Known Issues - The settings are not simple yet. Some of the logic in them is *slightly* overlapping. There's a lot of freedom, but it's easy to get lost in the settings. - this cost me several hours but was made up for because I could test significantly more options per build. - There are no default printers yet. I don't have a functional belt printer yet to test against, but my BabyBelt Pro will be done soon. - Multimaterial / Multicolor prints have not been tested in any way. This is on the roadmap but hasn't been implemented yet. - No first layer compensation - G-code that lands on the buildplate needs to have first layer height thickness / overextrusion applied to make things stick better. - Brims are disabled. - My brain is fried and I need more eyes on this and testing to happen. - Several warnings about G-Code (mostly empty layer warnings). These haven't been disabled yet on purpose. - Previewing in machine frame coordinates doesn't work. - Support propagation direction needs some work ## How To Test 1. ~~Enable Developer Mode in Preferences~~ - Developer mode is no longer required for axis swapping if belt printing is enabled. 2. Create a new printer. Aside from your normal setup, enable belt printer mode. 3. Copy the following settings as defaults: | Setting | Value | | :---: | :--- | | Mesh Shear X | ``None`` | | Mesh Shear Y | ``None`` | | Mesh Shear Z | +cot(a) | | Mesh Shear Z Angle | ``your printer's angle, in degrees. Might need the inverse (i.e. 60* instead of 30*)`` | | Mesh Shear Z Global | ``TRUE`` | | Pre-Slice Axis Remap | Swap Y and Z | | Origin Snap Y | ``TRUE`` *note: offset can be set negative to get the nozzle closer to the belt* | | Support Floor Mode | ``Generator Only`` | > [!WARNING] > Do not enable g-code back-transform unless you want to run tests on a normal printer. If you do that, check your nozzle and toolhead geometry and run shallow transform angles. ## Screenshots <img width="1853" height="1044" alt="Screenshot from 2026-03-27 14-55-02" src="https://github.com/user-attachments/assets/68e2e74e-9662-487e-92e7-600345ac846c" /> <img width="946" height="1290" alt="Screenshot 2026-03-27 144051" src="https://github.com/user-attachments/assets/e324dbbb-42f7-4497-8560-337e750456af" /> ### Tree Slim support at 30 degrees <img width="1840" height="962" alt="tree-slim-global-30deg" src="https://github.com/user-attachments/assets/5f6b5e72-70a1-4fd7-afd8-42553fb97bf2" /> ### G-Code Backtransform Result This is, to my knowledge, the first benchy sliced and printed in Orcaslicer with a nonstandard slicing plane. One filament swap when I ran out of filament. Printed on a standard Sovol SV08 with the toolhead cover removed. ![20260326_142754](https://github.com/user-attachments/assets/5378ec3e-c752-494d-a6e1-d30d0bf5051f) ![20260326_142832](https://github.com/user-attachments/assets/2828488e-753b-48c5-9ce5-1d55aaf9f17a) ### Slicer Recordings G-Code Backtransform https://github.com/user-attachments/assets/cdb9cc83-711d-48b7-9d86-a014a32c5e8e Closes #2628 Closes #11344 Closes #6885 Closes #9004
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/OrcaSlicer#113