up
This commit is contained in:
parent
b736f1821a
commit
35996fb956
6 changed files with 174 additions and 69 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
||||||
__pycache__
|
__pycache__
|
||||||
|
release
|
||||||
59
README.md
59
README.md
|
|
@ -1,47 +1,50 @@
|
||||||
# NodeSlicer
|
# NodeSlicer
|
||||||
|
|
||||||
NodeSlicer is a high-performance Blender extension that provides a custom node-based interface for mesh slicing and G-code generation. By bypassing traditional Blender modifiers and using NumPy and Shapely for geometry processing, it offers a flexible and extensible workflow for 3D printing and procedural geometry tasks.
|
NodeSlicer is a high-performance Blender extension that provides a custom node-based interface for mesh slicing and G-code generation. By using NumPy for geometry processing and Pyclipper for robust 2D polygon operations, it offers a flexible and extensible workflow for 3D printing, CNC toolpathing, and procedural geometry tasks.
|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
- **Custom Node Editor**: A dedicated node tree type for slicing workflows.
|
- **Custom Node Editor**: A dedicated node tree type (`NodeSlicer Tree`) for slicing workflows.
|
||||||
- **Fast Geometry Processing**: Uses NumPy for vectorized mesh operations and Shapely for robust 2D geometry manipulation.
|
- **Fast Geometry Processing**: Vectorized mesh operations using NumPy and robust 2D geometry manipulation via Pyclipper.
|
||||||
- **G-code Generation**: Direct conversion of 2D contours (toolpaths) into G-code.
|
- **G-code Lifecycle**: Direct conversion of 2D contours (toolpaths) into G-code, with support for loading, joining, and exporting G-code.
|
||||||
- **Live Preview**: Debug nodes to visualize generated toolpaths directly in the Blender viewport.
|
- **Advanced Slicing**:
|
||||||
- **Extensible**: Modular architecture allowing for easy addition of new nodes and processing logic.
|
- **Shell Slicing**: Accurate Z-layer extraction.
|
||||||
|
- **Buffered Offsetting**: Layer-independent offsetting with support for Euler rotations (tilted/non-planar offsetting).
|
||||||
|
- **Consistent Infill**: Cross-hatch grid infill that maintains alignment across layers and supports degree-based rotation.
|
||||||
|
- **Boolean Slices**: Union, Intersection, and Difference operations on slice boundaries.
|
||||||
|
- **Visual Preview**: Built-in G-code to Mesh conversion with automated Geometry Nodes integration ("Nonplanar Slicing Preview") for high-quality viewport feedback.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
- Blender 4.2 or newer (uses the new Extension system).
|
- Blender 3.6 or newer.
|
||||||
- Dependencies (bundled or installed via `uv`):
|
- Dependencies: `numpy`, `pyclipper`. (Included in the `wheels/` directory or managed via `uv`).
|
||||||
- `numpy`
|
|
||||||
- `shapely`
|
|
||||||
- `pyclipper`
|
|
||||||
|
|
||||||
### As a Blender Extension
|
### Setup
|
||||||
1. Zip the repository contents (excluding `.venv`, `__pycache__`, etc.).
|
1. Download or clone this repository.
|
||||||
2. In Blender, go to `Edit > Preferences > Get Extensions`.
|
2. In Blender, install as an addon by pointing to the directory or zip.
|
||||||
3. Click the arrow in the top right and select `Install from Disk`.
|
3. Ensure the dependencies are available in your Blender Python environment.
|
||||||
4. Select your zip file.
|
|
||||||
|
|
||||||
## Quick Start
|
## Workflow
|
||||||
|
|
||||||
1. Open the **Node Editor**.
|
1. **Initialize**: Open the **Node Editor** and switch the tree type to **NodeSlicer Tree**.
|
||||||
2. Switch the tree type to **NodeSlicer Tree**.
|
2. **Import**: Use a **Get Mesh** node to bring a Blender object into the slicing engine.
|
||||||
3. Create a new tree.
|
3. **Slice**: Use **Slice Shells** to generate layer boundaries.
|
||||||
4. Add an **Object Input** node and select a mesh object.
|
4. **Process**:
|
||||||
5. Connect it to a **Get Mesh** node.
|
* Add perimeters with **Buffer Shells**.
|
||||||
6. Connect the mesh to **Slice Shells**.
|
* Add internal structure with the **Infill** node.
|
||||||
7. Connect the slices to **Slices to Paths**, then **Paths to Gcode**.
|
* Combine or modify paths using **Join Paths** or **Join Slices**.
|
||||||
8. Use a **Gcode To File** node to export your result.
|
5. **Generate**: Convert paths to G-code using **Paths to Gcode**.
|
||||||
|
6. **Export & Preview**: Use **Gcode To File** to save the result, and **Gcode to Mesh** to visualize the final toolpaths in the viewport.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- [Project Overview](doc/README.md)
|
For detailed information on nodes and modules, see:
|
||||||
- [Module Reference](doc/MODULES.md)
|
- [User Guide](doc/USER_GUIDE.md) - **Start here!**
|
||||||
- [Node & Socket Reference](doc/NODES.md)
|
- [Node & Socket Reference](doc/NODES.md)
|
||||||
|
- [Module Architecture](doc/MODULES.md)
|
||||||
|
- [Project Overview](doc/README.md)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the GPL-3.0-or-later license. See `blender_manifest.toml` for details.
|
This project is licensed under the GPL-3.0-or-later license.
|
||||||
|
|
|
||||||
21
build.sh
Executable file
21
build.sh
Executable file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
TMPDIR="$(mktemp -d)"
|
||||||
|
cleanup() { rm -rf "$TMPDIR"; }
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
mapfile -t FILES < <(git ls-files -co --exclude-standard \
|
||||||
|
| grep -v -xE '(\.gitignore|build\.sh)')
|
||||||
|
|
||||||
|
tar -cf - "${FILES[@]}" | tar -xf - -C "$TMPDIR"
|
||||||
|
|
||||||
|
cd "$TMPDIR"
|
||||||
|
/home/nicolas/Applications/blender-5.1.0-linux-x64/blender \
|
||||||
|
--command extension build --split-platforms \
|
||||||
|
--output-filepath "$SCRIPT_DIR/release/NodeSlicer_0.0.1.zip"
|
||||||
|
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
@ -10,42 +10,40 @@ This file provides a mapping of modules to their primary responsibilities and ke
|
||||||
- **Sockets**: Definitions for all `SLICESOCK_*` classes.
|
- **Sockets**: Definitions for all `SLICESOCK_*` classes.
|
||||||
- **Nodes**: Definitions for all `SLICENODE_*` classes.
|
- **Nodes**: Definitions for all `SLICENODE_*` classes.
|
||||||
- **Evaluation Engine**:
|
- **Evaluation Engine**:
|
||||||
- `_resolve_input()`: Recursively evaluates linked sockets.
|
- `resolve_input()`: Recursively evaluates linked sockets.
|
||||||
- `_resolve_output()`: Computes node outputs with a caching system (`_EvalCache`) to avoid redundant calculations.
|
- `_resolve_output()`: Computes node outputs with a caching system (`_EvalCache`) to avoid redundant calculations.
|
||||||
- `_follow_reroute()`: Handles Blender's Reroute nodes during evaluation.
|
- `_follow_reroute()`: Handles Blender's Reroute nodes during evaluation.
|
||||||
- **Error Handling**: `NodeException` for user-facing evaluation errors.
|
|
||||||
|
|
||||||
- `registry.py`:
|
- `registry.py`:
|
||||||
- **Auto-Registration**: Utility to track classes decorated with `@register_class`.
|
- **Auto-Registration**: Utility to track classes decorated with `@register_class`.
|
||||||
- **Resource Management**: Logic for dynamic icon and timer registration.
|
|
||||||
|
|
||||||
- `blender_manifest.toml`:
|
- `blender_manifest.toml`:
|
||||||
- Metadata for the Blender Extension platform.
|
- Metadata for the Blender Extension platform.
|
||||||
- Lists required wheels (Shapely, PyClipper) for different platforms.
|
|
||||||
|
|
||||||
- `pyproject.toml`:
|
- `pyproject.toml`:
|
||||||
- Standard Python project configuration.
|
- Standard Python project configuration.
|
||||||
- Lists development and runtime dependencies.
|
|
||||||
|
|
||||||
## `/core` (Geometry & Slicing)
|
## `/core` (Geometry & Slicing)
|
||||||
|
|
||||||
- `slice.py`:
|
- `slice.py`:
|
||||||
- `slice_at_range()`: Top-level slicing function that iterates through Z-heights.
|
- `slice_at_range()`: Top-level slicing function that iterates through Z-heights.
|
||||||
- `slice_at_z()`: Vectorized plane-mesh intersection using NumPy.
|
- `slice_at_z()`: Vectorized plane-mesh intersection using NumPy.
|
||||||
- `Pather`: Class that converts toolpaths into G-code strings. Handles layer change comments and extrusion calculations.
|
- `Pather`: Class that converts toolpaths into G-code strings.
|
||||||
- `segments_to_slice()`: Utility to convert raw intersection segments into closed loops using Pyclipper and the Even-Odd fill rule.
|
- `segments_to_slice()`: Utility to convert raw intersection segments into closed loops using Pyclipper.
|
||||||
- `link_segments()`: Logic for joining loose segments into continuous paths.
|
- `link_segments()`: Logic for joining loose segments into continuous paths.
|
||||||
- `buffer_slice()`: Offset utility using PyclipperOffset. Groups paths by Z-height to ensure independent buffering of layers.
|
- `buffer_slice()`: Offset utility using PyclipperOffset. Supports rotated offsetting.
|
||||||
|
- `infill_slice()`: Generates rotated grid infill patterns, ensuring layer-to-layer consistency.
|
||||||
|
- `boolean_slice()`: Performs 2D boolean operations (Union, Intersection, etc.) on slice sets.
|
||||||
|
|
||||||
- `geometry.py`:
|
- `geometry.py`:
|
||||||
- `crc32_array()`: High-performance checksum generation for NumPy arrays, used for internal caching and data validation.
|
- Geometry utility functions.
|
||||||
|
|
||||||
## `/infra` (Blender Integration)
|
## `/infra` (Blender Integration)
|
||||||
|
|
||||||
- `blender_mesh_capture.py`:
|
- `blender_mesh_capture.py`:
|
||||||
- `SlicingObject`: Represents a single mesh as a NumPy triangle array. Computes bounding boxes and checksums.
|
- `SlicingObject`: Represents a single mesh as a NumPy triangle array.
|
||||||
- `SlicingCollection` / `SlicingGroup`: Hierarchical wrappers for managing multiple meshes and their metadata (e.g., Wipe Tower location).
|
- `capture_mesh_edges()`: Extracts edges from a Blender mesh for path-based workflows.
|
||||||
- `objects_to_tris()`: Performance-critical function that extracts mesh data from Blender objects into NumPy arrays using `foreach_get`. Handles world-space transformation and unit scaling.
|
|
||||||
|
|
||||||
- `blender_bridge.py`:
|
- `blender_slice_nodes_generic.py`:
|
||||||
- **Hierarchy Utilities**: Helpers like `get_all_children()` for traversing Blender's object tree.
|
- Base classes for NodeSlicer nodes (`SliceNode`) and sockets (`SliceNodeSocket`).
|
||||||
|
- Core evaluation logic (`resolve_input`).
|
||||||
|
|
|
||||||
63
doc/NODES.md
63
doc/NODES.md
|
|
@ -8,23 +8,24 @@
|
||||||
| `SLICESOCK_Float` | `float` | Python float | Numeric value |
|
| `SLICESOCK_Float` | `float` | Python float | Numeric value |
|
||||||
| `SLICESOCK_Int` | `int` | Python int | Integer value |
|
| `SLICESOCK_Int` | `int` | Python int | Integer value |
|
||||||
| `SLICESOCK_String` | `str` | Python string | Text/Path value |
|
| `SLICESOCK_String` | `str` | Python string | Text/Path value |
|
||||||
|
| `SLICESOCK_Vector` | `tuple` | Python tuple (3) | XYZ or Euler rotation value |
|
||||||
| `SLICESOCK_Mesh` | `SlicingObject` | NumPy NDArray (Triangles) | Internal mesh data (Transformed/Scaled) |
|
| `SLICESOCK_Mesh` | `SlicingObject` | NumPy NDArray (Triangles) | Internal mesh data (Transformed/Scaled) |
|
||||||
| `SLICESOCK_Paths` | `list[np.ndarray]` | List of paths (N, 3) | Generic toolpaths or slice boundaries |
|
| `SLICESOCK_Paths` | `SlicePaths` (list) | List of paths (N, 3) + groups | Generic toolpaths or slice boundaries |
|
||||||
| `SLICESOCK_Gcode` | `str` | Multi-line string | Generated G-code text |
|
| `SLICESOCK_Gcode` | `str` | Multi-line string | Generated G-code text |
|
||||||
|
|
||||||
## Detailed Data Types
|
## Detailed Data Types
|
||||||
|
|
||||||
### SlicingObject (`SLICESOCK_Mesh`)
|
### SlicingObject (`SLICESOCK_Mesh`)
|
||||||
The `SlicingObject` class wraps a high-performance NumPy representation of a Blender mesh.
|
The `SlicingObject` class wraps a high-performance NumPy representation of a Blender mesh.
|
||||||
- **`.mesh`**: A NumPy `ndarray` of type `float64` with shape `(N, 4, 3)`.
|
- **`.mesh`**: A NumPy `ndarray` of type `float64` with shape `(N, 3, 3)`.
|
||||||
- `N`: Number of triangles.
|
- `N`: Number of triangles.
|
||||||
- `[i, 0:3, :]`: The three vertices of the $i$-th triangle.
|
- `[i, 0:3, :]`: The three vertices of the $i$-th triangle.
|
||||||
- `[i, 3, :]`: The face normal of the $i$-th triangle.
|
|
||||||
- **Coordinates**: Transformed to world space and scaled by the Blender scene unit scale (multiplied by 1000 for mm-standard G-code).
|
- **Coordinates**: Transformed to world space and scaled by the Blender scene unit scale (multiplied by 1000 for mm-standard G-code).
|
||||||
|
|
||||||
### Paths (`SLICESOCK_Paths`)
|
### SlicePaths (`SLICESOCK_Paths`)
|
||||||
A `list[np.ndarray]` (each `(N, 3)`) containing toolpaths or slice results.
|
A custom list subclass `SlicePaths(list[np.ndarray])` containing toolpaths.
|
||||||
- **Content**: Can be open or closed segments. When generated from `Slice Shells`, they are guaranteed to be closed loops forming valid manifold boundaries.
|
- **Content**: Each `np.ndarray` has shape `(N, 3)`.
|
||||||
|
- **Groups**: Maintains a `.groups` list of integers mapping each path to a layer or logical group.
|
||||||
- **Z-Awareness**: Coordinates are stored as 3D `(X, Y, Z)` to maintain the correct layer height.
|
- **Z-Awareness**: Coordinates are stored as 3D `(X, Y, Z)` to maintain the correct layer height.
|
||||||
- **Topology**: Generated and cleaned using `pyclipper`.
|
- **Topology**: Generated and cleaned using `pyclipper`.
|
||||||
|
|
||||||
|
|
@ -32,30 +33,38 @@ A `list[np.ndarray]` (each `(N, 3)`) containing toolpaths or slice results.
|
||||||
A standard Python string containing formatted G-code.
|
A standard Python string containing formatted G-code.
|
||||||
- **Format**: `G0` for travels, `G1` for extrusions.
|
- **Format**: `G0` for travels, `G1` for extrusions.
|
||||||
- **Extrusion**: Calculated as absolute `E` values based on Euclidean distance and a configurable `EXTRUSION_RATE`.
|
- **Extrusion**: Calculated as absolute `E` values based on Euclidean distance and a configurable `EXTRUSION_RATE`.
|
||||||
|
- **Metadata**: Includes `;OFFSET_X=` and `;OFFSET_Y=` comments to allow reconstruction of original coordinates.
|
||||||
|
|
||||||
## Nodes
|
## Nodes
|
||||||
|
|
||||||
### Input Nodes
|
All nodes are found in the **Add (Shift+A)** menu under the **SliceNodes** category.
|
||||||
- `SLICENODE_InputFloat`: Single float input.
|
|
||||||
- `SLICENODE_InputInt`: Single integer input.
|
|
||||||
- `SLICENODE_InputString`: Single string/path input.
|
|
||||||
- `SLICENODE_InputObject`: Blender object picker.
|
|
||||||
- `SLICENODE_GcodeBlock`: Manual text area for entering raw G-code.
|
|
||||||
|
|
||||||
### Processing Nodes
|
### Data & Input
|
||||||
- `SLICENODE_GetMesh`: Converts a Blender Object into internal `SlicingObject` format.
|
- **Object**: Blender object picker.
|
||||||
- `SLICENODE_SliceShells`: Slices a `SlicingObject` into 2D `Paths` at a given layer height.
|
- **Float**: Single float input.
|
||||||
- `SLICENODE_BufferShells`: Offsets/buffers 2D `Paths` using a "Distance" parameter. Buffers each Z-layer independently to maintain 3D structure and uses winding rules to correctly handle nested holes.
|
- **Integer**: Single integer input.
|
||||||
- `SLICENODE_GridInfill`: Generates a grid of lines clipped by boundary paths.
|
- **String**: Single string/path input.
|
||||||
- `SLICENODE_PathsToGcode`: Converts `Paths` into G-code blocks.
|
- **Rotation**: Input for Euler rotation vectors.
|
||||||
|
- **Printer Intrinsics**: Configures bed size and extrusion rates.
|
||||||
|
- **Gcode Block**: Manual text area for entering raw G-code.
|
||||||
|
|
||||||
### Joiner Nodes (Variable Inputs)
|
### Geometry Processing
|
||||||
- `SLICENODE_JoinMesh`: Merges multiple `SlicingObject` instances into one.
|
- **Get Mesh**: Converts a Blender Object into internal `SlicingObject` format.
|
||||||
- `SLICENODE_JoinPaths`: Merges multiple paths.
|
- **Get Paths**: Extracts existing edges from a mesh as paths.
|
||||||
- `SLICENODE_JoinGcode`: Concatenates multiple G-code strings with newline separators.
|
- **Slice Shells**: Slices a `SlicingObject` into 2D `SlicePaths` at a given layer height.
|
||||||
|
- **Buffer Shells**: Offsets/buffers 2D `SlicePaths`. Supports rotated offsetting and multiple miter types.
|
||||||
|
- **Infill**: Generates a cross-hatch grid of lines clipped by boundary paths. Supports rotation in degrees.
|
||||||
|
- **Boolean Paths**: Performs 2D boolean operations (`UNION`, `INTERSECTION`, `DIFFERENCE`, `XOR`) on multiple slice sets.
|
||||||
|
|
||||||
### Action Nodes (Executable)
|
### Utility & Joiners
|
||||||
- `SLICENODE_GcodeToFile`: Writes G-code string to a file on disk.
|
- **Join Mesh**: Merges multiple `SlicingObject` instances into one.
|
||||||
- `SLICENODE_GcodeToMesh`: Decodes G-code and creates a Blender mesh (Edges) for visualization/debugging.
|
- **Join Paths**: Combines multiple `SlicePaths`. Supports Sequential or Interleaved modes.
|
||||||
- `SLICENODE_LoadGcode`: Reads a G-code file from disk into a string.
|
- **Join Gcode**: Concatenates multiple G-code strings.
|
||||||
- `SLICENODE_Test`: Triggers evaluation for debugging purposes.
|
- **Integer Math**: Simple integer operations (Add, Multiply, etc.).
|
||||||
|
|
||||||
|
### Action & I/O
|
||||||
|
- **Paths to Gcode**: Converts `SlicePaths` into G-code blocks.
|
||||||
|
- **Load Gcode**: Reads a G-code file from disk.
|
||||||
|
- **Gcode to File**: Writes G-code string to a file on disk.
|
||||||
|
- **Gcode to Mesh**: Decodes G-code and creates a Blender mesh ("Debug" object) for visualization.
|
||||||
|
- **Test**: Triggers evaluation for debugging purposes.
|
||||||
|
|
|
||||||
73
doc/USER_GUIDE.md
Normal file
73
doc/USER_GUIDE.md
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# NodeSlicer User Guide
|
||||||
|
|
||||||
|
This guide will walk you through finding the NodeSlicer interface and creating your first slicing workflow.
|
||||||
|
|
||||||
|
## 1. Finding NodeSlicer
|
||||||
|
|
||||||
|
NodeSlicer lives in its own dedicated Node Tree type. To access it:
|
||||||
|
|
||||||
|
1. Open any **Node Editor** area in Blender (usually found in the Shading or Geometry Nodes workspaces).
|
||||||
|
2. In the header, click the **Tree Type** icon (next to the "New" button).
|
||||||
|
3. Select **NodeSlicer Tree** from the list.
|
||||||
|
4. Click **New** to create a new slicing project.
|
||||||
|
|
||||||
|
## 2. Basic Usage: "The Quick Slice"
|
||||||
|
|
||||||
|
Follow these steps to generate G-code for a simple object and preview it:
|
||||||
|
|
||||||
|
### Step 1: Input your Object
|
||||||
|
* Press `Shift+A` to open the Add menu.
|
||||||
|
* Look for the **SliceNodes** sub-menu at the bottom.
|
||||||
|
* Select **Object** to add an object picker.
|
||||||
|
* Use the eyedropper to select the mesh you want to slice.
|
||||||
|
* From the same menu, add a **Get Mesh** node and connect the Object output to it. This converts the Blender object into a format the slicer understands.
|
||||||
|
|
||||||
|
### Step 2: Slice into Layers
|
||||||
|
* Add a **Slice Shells** node from the **SliceNodes** menu.
|
||||||
|
* Connect the Mesh output from "Get Mesh" to the Mesh input of "Slice Shells".
|
||||||
|
* Set your **Layer Height** (e.g., 0.2 mm).
|
||||||
|
|
||||||
|
### Step 3: Create Paths and G-code
|
||||||
|
* Add a **Paths to Gcode** node.
|
||||||
|
* Connect the Paths output of "Slice Shells" to the Paths input of "Paths to Gcode".
|
||||||
|
* This node generates the raw G-code text.
|
||||||
|
|
||||||
|
### Step 4: Preview the Result
|
||||||
|
* Add a **Gcode to Mesh** node.
|
||||||
|
* Connect the Gcode output to it.
|
||||||
|
* Click the **Update Debug Mesh** button on the node.
|
||||||
|
* A new object named **Debug** will appear in your scene, showing the toolpaths.
|
||||||
|
|
||||||
|
> **Pro Tip**: If your file contains a Geometry Nodes group called "Nonplanar Slicing Preview", it will be automatically assigned to the Debug object for a high-quality visualization.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Adding Perimeters and Infill
|
||||||
|
|
||||||
|
A single slice is just an outline. To make a 3D print, you need wall thickness and internal structure.
|
||||||
|
|
||||||
|
### Buffering (Walls)
|
||||||
|
* Use the **Buffer Shells** node between "Slice Shells" and "Paths to Gcode".
|
||||||
|
* Set a negative **Distance** (e.g., -0.4 mm) to create an inner perimeter.
|
||||||
|
* You can chain multiple Buffer nodes to create multiple walls.
|
||||||
|
|
||||||
|
### Infill (Internal Structure)
|
||||||
|
* Add an **Infill** node.
|
||||||
|
* Connect your slice paths to its input.
|
||||||
|
* **Density**: Controls how close the grid lines are.
|
||||||
|
* **Rotation**: Rotates the grid (in degrees). The grid is calculated globally, so it stays perfectly aligned across layers.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Exporting to a File
|
||||||
|
|
||||||
|
Once you are happy with the preview:
|
||||||
|
1. Add a **Gcode to File** node.
|
||||||
|
2. Connect your G-code string to it.
|
||||||
|
3. Type a **Filename** (e.g., `C:/temp/my_slice.gcode` or `/tmp/test.gcode`).
|
||||||
|
4. Click **Generate File**.
|
||||||
|
|
||||||
|
## 5. Tips for Success
|
||||||
|
* **Scale**: The slicer treats 1 Blender unit as 1 meter, but scales everything to **mm** for the G-code output.
|
||||||
|
* **Orientation**: The slicer currently assumes your object is oriented correctly for printing (Z is up).
|
||||||
|
* **Performance**: For very complex meshes, the "Get Mesh" and "Slice Shells" nodes might take a moment to compute. The result is cached, so changing settings further down the chain (like Infill density) will be much faster.
|
||||||
Loading…
Add table
Reference in a new issue