This commit is contained in:
Nicolas Predella 2026-05-06 21:09:46 +03:00
parent b736f1821a
commit 35996fb956
6 changed files with 174 additions and 69 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
__pycache__
release

View file

@ -1,47 +1,50 @@
# 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
- **Custom Node Editor**: A dedicated node tree type for slicing workflows.
- **Fast Geometry Processing**: Uses NumPy for vectorized mesh operations and Shapely for robust 2D geometry manipulation.
- **G-code Generation**: Direct conversion of 2D contours (toolpaths) into G-code.
- **Live Preview**: Debug nodes to visualize generated toolpaths directly in the Blender viewport.
- **Extensible**: Modular architecture allowing for easy addition of new nodes and processing logic.
- **Custom Node Editor**: A dedicated node tree type (`NodeSlicer Tree`) for slicing workflows.
- **Fast Geometry Processing**: Vectorized mesh operations using NumPy and robust 2D geometry manipulation via Pyclipper.
- **G-code Lifecycle**: Direct conversion of 2D contours (toolpaths) into G-code, with support for loading, joining, and exporting G-code.
- **Advanced Slicing**:
- **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
### Requirements
- Blender 4.2 or newer (uses the new Extension system).
- Dependencies (bundled or installed via `uv`):
- `numpy`
- `shapely`
- `pyclipper`
- Blender 3.6 or newer.
- Dependencies: `numpy`, `pyclipper`. (Included in the `wheels/` directory or managed via `uv`).
### As a Blender Extension
1. Zip the repository contents (excluding `.venv`, `__pycache__`, etc.).
2. In Blender, go to `Edit > Preferences > Get Extensions`.
3. Click the arrow in the top right and select `Install from Disk`.
4. Select your zip file.
### Setup
1. Download or clone this repository.
2. In Blender, install as an addon by pointing to the directory or zip.
3. Ensure the dependencies are available in your Blender Python environment.
## Quick Start
## Workflow
1. Open the **Node Editor**.
2. Switch the tree type to **NodeSlicer Tree**.
3. Create a new tree.
4. Add an **Object Input** node and select a mesh object.
5. Connect it to a **Get Mesh** node.
6. Connect the mesh to **Slice Shells**.
7. Connect the slices to **Slices to Paths**, then **Paths to Gcode**.
8. Use a **Gcode To File** node to export your result.
1. **Initialize**: Open the **Node Editor** and switch the tree type to **NodeSlicer Tree**.
2. **Import**: Use a **Get Mesh** node to bring a Blender object into the slicing engine.
3. **Slice**: Use **Slice Shells** to generate layer boundaries.
4. **Process**:
* Add perimeters with **Buffer Shells**.
* Add internal structure with the **Infill** node.
* Combine or modify paths using **Join Paths** or **Join Slices**.
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
- [Project Overview](doc/README.md)
- [Module Reference](doc/MODULES.md)
For detailed information on nodes and modules, see:
- [User Guide](doc/USER_GUIDE.md) - **Start here!**
- [Node & Socket Reference](doc/NODES.md)
- [Module Architecture](doc/MODULES.md)
- [Project Overview](doc/README.md)
## 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
View 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"

View file

@ -10,42 +10,40 @@ This file provides a mapping of modules to their primary responsibilities and ke
- **Sockets**: Definitions for all `SLICESOCK_*` classes.
- **Nodes**: Definitions for all `SLICENODE_*` classes.
- **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.
- `_follow_reroute()`: Handles Blender's Reroute nodes during evaluation.
- **Error Handling**: `NodeException` for user-facing evaluation errors.
- `registry.py`:
- **Auto-Registration**: Utility to track classes decorated with `@register_class`.
- **Resource Management**: Logic for dynamic icon and timer registration.
- `blender_manifest.toml`:
- Metadata for the Blender Extension platform.
- Lists required wheels (Shapely, PyClipper) for different platforms.
- `pyproject.toml`:
- Standard Python project configuration.
- Lists development and runtime dependencies.
## `/core` (Geometry & Slicing)
- `slice.py`:
- `slice_at_range()`: Top-level slicing function that iterates through Z-heights.
- `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.
- `segments_to_slice()`: Utility to convert raw intersection segments into closed loops using Pyclipper and the Even-Odd fill rule.
- `Pather`: Class that converts toolpaths into G-code strings.
- `segments_to_slice()`: Utility to convert raw intersection segments into closed loops using Pyclipper.
- `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`:
- `crc32_array()`: High-performance checksum generation for NumPy arrays, used for internal caching and data validation.
- Geometry utility functions.
## `/infra` (Blender Integration)
- `blender_mesh_capture.py`:
- `SlicingObject`: Represents a single mesh as a NumPy triangle array. Computes bounding boxes and checksums.
- `SlicingCollection` / `SlicingGroup`: Hierarchical wrappers for managing multiple meshes and their metadata (e.g., Wipe Tower location).
- `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.
- `SlicingObject`: Represents a single mesh as a NumPy triangle array.
- `capture_mesh_edges()`: Extracts edges from a Blender mesh for path-based workflows.
- `blender_bridge.py`:
- **Hierarchy Utilities**: Helpers like `get_all_children()` for traversing Blender's object tree.
- `blender_slice_nodes_generic.py`:
- Base classes for NodeSlicer nodes (`SliceNode`) and sockets (`SliceNodeSocket`).
- Core evaluation logic (`resolve_input`).

View file

@ -8,23 +8,24 @@
| `SLICESOCK_Float` | `float` | Python float | Numeric value |
| `SLICESOCK_Int` | `int` | Python int | Integer 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_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 |
## Detailed Data Types
### SlicingObject (`SLICESOCK_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.
- `[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).
### Paths (`SLICESOCK_Paths`)
A `list[np.ndarray]` (each `(N, 3)`) containing toolpaths or slice results.
- **Content**: Can be open or closed segments. When generated from `Slice Shells`, they are guaranteed to be closed loops forming valid manifold boundaries.
### SlicePaths (`SLICESOCK_Paths`)
A custom list subclass `SlicePaths(list[np.ndarray])` containing toolpaths.
- **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.
- **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.
- **Format**: `G0` for travels, `G1` for extrusions.
- **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
### Input Nodes
- `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.
All nodes are found in the **Add (Shift+A)** menu under the **SliceNodes** category.
### Processing Nodes
- `SLICENODE_GetMesh`: Converts a Blender Object into internal `SlicingObject` format.
- `SLICENODE_SliceShells`: Slices a `SlicingObject` into 2D `Paths` at a given layer height.
- `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.
- `SLICENODE_GridInfill`: Generates a grid of lines clipped by boundary paths.
- `SLICENODE_PathsToGcode`: Converts `Paths` into G-code blocks.
### Data & Input
- **Object**: Blender object picker.
- **Float**: Single float input.
- **Integer**: Single integer input.
- **String**: Single string/path input.
- **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)
- `SLICENODE_JoinMesh`: Merges multiple `SlicingObject` instances into one.
- `SLICENODE_JoinPaths`: Merges multiple paths.
- `SLICENODE_JoinGcode`: Concatenates multiple G-code strings with newline separators.
### Geometry Processing
- **Get Mesh**: Converts a Blender Object into internal `SlicingObject` format.
- **Get Paths**: Extracts existing edges from a mesh as paths.
- **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)
- `SLICENODE_GcodeToFile`: Writes G-code string to a file on disk.
- `SLICENODE_GcodeToMesh`: Decodes G-code and creates a Blender mesh (Edges) for visualization/debugging.
- `SLICENODE_LoadGcode`: Reads a G-code file from disk into a string.
- `SLICENODE_Test`: Triggers evaluation for debugging purposes.
### Utility & Joiners
- **Join Mesh**: Merges multiple `SlicingObject` instances into one.
- **Join Paths**: Combines multiple `SlicePaths`. Supports Sequential or Interleaved modes.
- **Join Gcode**: Concatenates multiple G-code strings.
- **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
View 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.