129 lines
3.9 KiB
Markdown
129 lines
3.9 KiB
Markdown
|
# Developing Nodes
|
||
|
|
||
|
This guide will help you developing your first Nodarium Node written in Rust. As an example we will implement a `cylinder` node, which generates a 3D model of a cylinder.
|
||
|
|
||
|
## Prerequesites
|
||
|
|
||
|
You need to have [Rust](https://www.rust-lang.org/tools/install) and [wasm-pack](https://rustwasm.github.io/wasm-pack/book/) installed. Rust is the language we are going to develop our node in and wasm-pack helps us compile our rust code into a webassembly file.
|
||
|
|
||
|
```bash
|
||
|
# install rust
|
||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||
|
# install wasm-pack
|
||
|
cargo install wasm-pack
|
||
|
```
|
||
|
|
||
|
## Clone Template
|
||
|
|
||
|
```bash
|
||
|
wasm-pack new my-new-node --template https://github.com/jim-fx/nodarium_template
|
||
|
cd my-new-node
|
||
|
```
|
||
|
|
||
|
## Setup Definition
|
||
|
|
||
|
Now we create the definition file of the node.
|
||
|
Here we define what kind of inputs our node will expect and what kind of output it produces. If you want to dive deeper into this topic, have a look at [NODE_DEFINITION.md](./NODE_DEFINITION.md).
|
||
|
|
||
|
`src/definition.json`
|
||
|
```json
|
||
|
{
|
||
|
"id": "my-name/my-namespace/zylinder-node",
|
||
|
"outputs": [
|
||
|
"geometry"
|
||
|
],
|
||
|
"inputs": {
|
||
|
"height": {
|
||
|
"type": "float",
|
||
|
"value": 2,
|
||
|
},
|
||
|
"radius": {
|
||
|
"type": "float",
|
||
|
"value": 0.4
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
If we take a look at the `src/lib.rs` file we see that `src/definition.json` is included with the following line:
|
||
|
|
||
|
```rust
|
||
|
include_definition_file!("src/definition.json");
|
||
|
```
|
||
|
|
||
|
This procedural rust macro loads the definition.json, validates its content and embeds it in our output file.
|
||
|
|
||
|
## Implement Node
|
||
|
|
||
|
This is the hardest part when developing a node, for now you can copy the following content into the `src/lib.rs` file:
|
||
|
|
||
|
```rust
|
||
|
use glam::Vec2;
|
||
|
use wasm_bindgen::prelude::*;
|
||
|
|
||
|
nodarium_macros::include_definition_file!("src/definition.json");
|
||
|
|
||
|
#[wasm_bindgen]
|
||
|
pub fn execute(input: &[i32]) -> Vec<i32> {
|
||
|
let arguments = nodarium_utils::split_args(input);
|
||
|
|
||
|
let height = nodarium_utils::evaluate_float(arguments[0]);
|
||
|
let radius = nodarium_utils::evaluate_float(arguments[1]);
|
||
|
|
||
|
let mut geometry_data = nodarium_utils::geometry::create_geometry_data(16, 16);
|
||
|
|
||
|
let geometry = nodarium_utils::geometry::wrap_geometry_data(&mut geometry_data);
|
||
|
|
||
|
// bottom circle
|
||
|
for i in 0..8 {
|
||
|
let x = radius * (2.0 * std::f32::consts::PI * i as f32 / 8.0).cos();
|
||
|
let y = radius * (2.0 * std::f32::consts::PI * i as f32 / 8.0).sin();
|
||
|
|
||
|
let vec = Vec2::new(x, y).normalize();
|
||
|
|
||
|
// bottom circle
|
||
|
geometry.positions[i * 3 + 0] = x;
|
||
|
geometry.positions[i * 3 + 1] = 0.0;
|
||
|
geometry.positions[i * 3 + 2] = y;
|
||
|
|
||
|
geometry.normals[i * 3 + 0] = vec[0];
|
||
|
geometry.normals[i * 3 + 1] = 0.0;
|
||
|
geometry.normals[i * 3 + 2] = vec[1];
|
||
|
|
||
|
// top circle
|
||
|
geometry.positions[24 + i * 3 + 0] = x;
|
||
|
geometry.positions[24 + i * 3 + 1] = height;
|
||
|
geometry.positions[24 + i * 3 + 2] = y;
|
||
|
|
||
|
geometry.normals[24 + i * 3 + 0] = vec[0];
|
||
|
geometry.normals[24 + i * 3 + 1] = 0.0;
|
||
|
geometry.normals[24 + i * 3 + 2] = vec[1];
|
||
|
|
||
|
geometry.faces[i * 6 + 0] = (i + 8) as i32;
|
||
|
geometry.faces[i * 6 + 1] = (i as i32 + 1) % 8;
|
||
|
geometry.faces[i * 6 + 2] = (i) as i32;
|
||
|
|
||
|
geometry.faces[i * 6 + 3] = 8 + (i % 8) as i32;
|
||
|
geometry.faces[i * 6 + 4] = 8 + (i as i32 + 1) % 8;
|
||
|
geometry.faces[i * 6 + 5] = (i as i32 + 1) % 8;
|
||
|
}
|
||
|
|
||
|
nodarium_utils::concat_arg_vecs(vec![geometry_data])
|
||
|
}
|
||
|
```
|
||
|
|
||
|
As you can see we import `glam` on the first line. Glam is a fantastic math library. Install it with the following command:
|
||
|
|
||
|
```bash
|
||
|
cargo add glam
|
||
|
```
|
||
|
|
||
|
## Build time
|
||
|
|
||
|
We compile our node by running the following command:
|
||
|
|
||
|
```bash
|
||
|
wasm-pack build --release
|
||
|
```
|
||
|
|
||
|
This will produce a `.wasm` file in the `pkg/` directory of our node. To check if the node works, we can drag it onto the node-graph on https://nodes.max-richter.dev and see if it loads.
|