Compare commits
5 Commits
8865b9b032
...
4f48a519a9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f48a519a9
|
||
|
|
97199ac20f
|
||
|
|
f36f0cb230
|
||
|
|
ed3d48e07f
|
||
|
|
c610d6c991
|
@@ -4,7 +4,7 @@
|
|||||||
import { decodeFloat, splitNestedArray } from '@nodarium/utils';
|
import { decodeFloat, splitNestedArray } from '@nodarium/utils';
|
||||||
import type { PerformanceStore } from '@nodarium/utils';
|
import type { PerformanceStore } from '@nodarium/utils';
|
||||||
import { Canvas } from '@threlte/core';
|
import { Canvas } from '@threlte/core';
|
||||||
import { Vector3 } from 'three';
|
import { DoubleSide, Vector3 } from 'three';
|
||||||
import { type Group, MeshMatcapMaterial, TextureLoader } from 'three';
|
import { type Group, MeshMatcapMaterial, TextureLoader } from 'three';
|
||||||
import { createGeometryPool, createInstancedGeometryPool } from './geometryPool';
|
import { createGeometryPool, createInstancedGeometryPool } from './geometryPool';
|
||||||
import Scene from './Scene.svelte';
|
import Scene from './Scene.svelte';
|
||||||
@@ -14,7 +14,8 @@
|
|||||||
matcap.colorSpace = 'srgb';
|
matcap.colorSpace = 'srgb';
|
||||||
const material = new MeshMatcapMaterial({
|
const material = new MeshMatcapMaterial({
|
||||||
color: 0xffffff,
|
color: 0xffffff,
|
||||||
matcap
|
matcap,
|
||||||
|
side: DoubleSide
|
||||||
});
|
});
|
||||||
|
|
||||||
let sceneComponent = $state<ReturnType<typeof Scene>>();
|
let sceneComponent = $state<ReturnType<typeof Scene>>();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ function getValue(input: NodeInput, value?: unknown) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
if (input.type === 'vec3') {
|
if (input.type === 'vec3' || input.type === 'shape') {
|
||||||
return [
|
return [
|
||||||
0,
|
0,
|
||||||
value.length + 1,
|
value.length + 1,
|
||||||
|
|||||||
@@ -28,6 +28,13 @@
|
|||||||
"value": 1,
|
"value": 1,
|
||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
|
"rotation": {
|
||||||
|
"type": "float",
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"value": 0.5,
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
"depth": {
|
"depth": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
use glam::{Mat4, Quat, Vec3};
|
use glam::{Mat4, Quat, Vec3};
|
||||||
use nodarium_macros::nodarium_execute;
|
use nodarium_macros::{nodarium_execute, nodarium_definition_file};
|
||||||
use nodarium_macros::nodarium_definition_file;
|
|
||||||
use nodarium_utils::{
|
use nodarium_utils::{
|
||||||
concat_args, evaluate_float, evaluate_int,
|
concat_args, evaluate_float, evaluate_int,
|
||||||
geometry::{
|
geometry::{create_instance_data, wrap_geometry_data, wrap_instance_data, wrap_path},
|
||||||
create_instance_data, wrap_geometry_data, wrap_instance_data, wrap_path,
|
split_args,
|
||||||
},
|
|
||||||
log, split_args,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
nodarium_definition_file!("src/input.json");
|
nodarium_definition_file!("src/input.json");
|
||||||
@@ -15,13 +12,13 @@ nodarium_definition_file!("src/input.json");
|
|||||||
pub fn execute(input: &[i32]) -> Vec<i32> {
|
pub fn execute(input: &[i32]) -> Vec<i32> {
|
||||||
let args = split_args(input);
|
let args = split_args(input);
|
||||||
let mut inputs = split_args(args[0]);
|
let mut inputs = split_args(args[0]);
|
||||||
log!("WASM(instance): inputs: {:?}", inputs);
|
|
||||||
|
|
||||||
let mut geo_data = args[1].to_vec();
|
let mut geo_data = args[1].to_vec();
|
||||||
let geo = wrap_geometry_data(&mut geo_data);
|
let geo = wrap_geometry_data(&mut geo_data);
|
||||||
|
|
||||||
let mut transforms: Vec<Mat4> = Vec::new();
|
let mut transforms: Vec<Mat4> = Vec::new();
|
||||||
|
|
||||||
|
// Find max depth
|
||||||
let mut max_depth = 0;
|
let mut max_depth = 0;
|
||||||
for path_data in inputs.iter() {
|
for path_data in inputs.iter() {
|
||||||
if path_data[2] != 0 {
|
if path_data[2] != 0 {
|
||||||
@@ -30,7 +27,8 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
|
|||||||
max_depth = max_depth.max(path_data[3]);
|
max_depth = max_depth.max(path_data[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let depth = evaluate_int(args[5]);
|
let rotation = evaluate_float(args[5]);
|
||||||
|
let depth = evaluate_int(args[6]);
|
||||||
|
|
||||||
for path_data in inputs.iter() {
|
for path_data in inputs.iter() {
|
||||||
if path_data[3] < (max_depth - depth + 1) {
|
if path_data[3] < (max_depth - depth + 1) {
|
||||||
@@ -38,24 +36,34 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let amount = evaluate_int(args[2]);
|
let amount = evaluate_int(args[2]);
|
||||||
|
|
||||||
let lowest_instance = evaluate_float(args[3]);
|
let lowest_instance = evaluate_float(args[3]);
|
||||||
let highest_instance = evaluate_float(args[4]);
|
let highest_instance = evaluate_float(args[4]);
|
||||||
|
|
||||||
let path = wrap_path(path_data);
|
let path = wrap_path(path_data);
|
||||||
|
|
||||||
for i in 0..amount {
|
for i in 0..amount {
|
||||||
let alpha =
|
let alpha = lowest_instance
|
||||||
lowest_instance + (i as f32 / amount as f32) * (highest_instance - lowest_instance);
|
+ (i as f32 / (amount - 1) as f32) * (highest_instance - lowest_instance);
|
||||||
|
|
||||||
let point = path.get_point_at(alpha);
|
let point = path.get_point_at(alpha);
|
||||||
let direction = path.get_direction_at(alpha);
|
let tangent = path.get_direction_at(alpha);
|
||||||
|
let size = point[3] + 0.01;
|
||||||
|
|
||||||
|
let axis_rotation = Quat::from_axis_angle(
|
||||||
|
Vec3::from_slice(&tangent).normalize(),
|
||||||
|
i as f32 * rotation,
|
||||||
|
);
|
||||||
|
|
||||||
|
let path_rotation = Quat::from_rotation_arc(Vec3::Y, Vec3::from_slice(&tangent).normalize());
|
||||||
|
|
||||||
|
let rotation = path_rotation * axis_rotation;
|
||||||
|
|
||||||
let transform = Mat4::from_scale_rotation_translation(
|
let transform = Mat4::from_scale_rotation_translation(
|
||||||
Vec3::new(point[3], point[3], point[3]),
|
Vec3::new(size, size, size),
|
||||||
Quat::from_xyzw(direction[0], direction[1], direction[2], 1.0).normalize(),
|
rotation,
|
||||||
Vec3::from_slice(&point),
|
Vec3::from_slice(&point),
|
||||||
);
|
);
|
||||||
|
|
||||||
transforms.push(transform);
|
transforms.push(transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,11 +75,11 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
|
|||||||
);
|
);
|
||||||
let mut instances = wrap_instance_data(&mut instance_data);
|
let mut instances = wrap_instance_data(&mut instance_data);
|
||||||
instances.set_geometry(geo);
|
instances.set_geometry(geo);
|
||||||
(0..transforms.len()).for_each(|i| {
|
|
||||||
instances.set_transformation_matrix(i, &transforms[i].to_cols_array());
|
|
||||||
});
|
|
||||||
|
|
||||||
log!("WASM(instance): geo: {:?}", instance_data);
|
for (i, transform) in transforms.iter().enumerate() {
|
||||||
|
instances.set_transformation_matrix(i, &transform.to_cols_array());
|
||||||
|
}
|
||||||
|
|
||||||
inputs.push(&instance_data);
|
inputs.push(&instance_data);
|
||||||
|
|
||||||
concat_args(inputs)
|
concat_args(inputs)
|
||||||
|
|||||||
@@ -11,6 +11,14 @@
|
|||||||
"size": {
|
"size": {
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 1
|
"value": 1
|
||||||
|
},
|
||||||
|
"xResolution": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "The amount of stems to produce",
|
||||||
|
"min": 1,
|
||||||
|
"max": 64,
|
||||||
|
"value": 1,
|
||||||
|
"hidden": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,166 @@
|
|||||||
|
use std::convert::TryInto;
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
use nodarium_macros::nodarium_definition_file;
|
use nodarium_macros::nodarium_definition_file;
|
||||||
use nodarium_macros::nodarium_execute;
|
use nodarium_macros::nodarium_execute;
|
||||||
use nodarium_utils::{concat_args, log, split_args};
|
use nodarium_utils::encode_float;
|
||||||
|
use nodarium_utils::evaluate_float;
|
||||||
|
use nodarium_utils::evaluate_int;
|
||||||
|
use nodarium_utils::log;
|
||||||
|
use nodarium_utils::wrap_arg;
|
||||||
|
use nodarium_utils::{split_args, decode_float};
|
||||||
|
|
||||||
nodarium_definition_file!("src/input.json");
|
nodarium_definition_file!("src/input.json");
|
||||||
|
|
||||||
|
fn calculate_y(x: f32) -> f32 {
|
||||||
|
let term1 = (x * PI * 2.0).sin().abs();
|
||||||
|
let term2 = (x * 2.0 * PI + (PI / 2.0)).sin() / 2.0;
|
||||||
|
term1 + term2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper vector math functions
|
||||||
|
fn vec_sub(a: &[f32; 3], b: &[f32; 3]) -> [f32; 3] {
|
||||||
|
[a[0] - b[0], a[1] - b[1], a[2] - b[2]]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vec_cross(a: &[f32; 3], b: &[f32; 3]) -> [f32; 3] {
|
||||||
|
[
|
||||||
|
a[1] * b[2] - a[2] * b[1],
|
||||||
|
a[2] * b[0] - a[0] * b[2],
|
||||||
|
a[0] * b[1] - a[1] * b[0],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vec_normalize(v: &[f32; 3]) -> [f32; 3] {
|
||||||
|
let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
|
||||||
|
if len == 0.0 { [0.0, 0.0, 0.0] } else { [v[0]/len, v[1]/len, v[2]/len] }
|
||||||
|
}
|
||||||
|
|
||||||
#[nodarium_execute]
|
#[nodarium_execute]
|
||||||
pub fn execute(input: &[i32]) -> Vec<i32> {
|
pub fn execute(input: &[i32]) -> Vec<i32> {
|
||||||
let args = split_args(input);
|
let args = split_args(input);
|
||||||
log!("leaf input: {:?}", input);
|
let input_path = split_args(args[0])[0];
|
||||||
log!("leaf args: {:?}", args);
|
let size = evaluate_float(args[1]);
|
||||||
concat_args(args)
|
let width_resolution = evaluate_int(args[2]).max(3) as usize;
|
||||||
|
let path_length = (input_path.len() - 4) / 2;
|
||||||
|
|
||||||
|
let slice_count = path_length;
|
||||||
|
let face_amount = (slice_count - 1) * (width_resolution - 1) * 2;
|
||||||
|
let position_amount = slice_count * width_resolution;
|
||||||
|
|
||||||
|
let out_length =
|
||||||
|
3 // metadata
|
||||||
|
+ face_amount * 3 // indices
|
||||||
|
+ position_amount * 3 // positions
|
||||||
|
+ position_amount * 3; // normals
|
||||||
|
|
||||||
|
let mut out = vec![0 as i32; out_length];
|
||||||
|
|
||||||
|
log!("face_amount={:?} position_amount={:?}", face_amount, position_amount);
|
||||||
|
|
||||||
|
out[0] = 1;
|
||||||
|
out[1] = position_amount.try_into().unwrap();
|
||||||
|
out[2] = face_amount.try_into().unwrap();
|
||||||
|
let mut offset = 3;
|
||||||
|
|
||||||
|
// Writing Indices
|
||||||
|
let mut idx = 0;
|
||||||
|
for i in 0..(slice_count - 1) {
|
||||||
|
let base0 = (i * width_resolution) as i32;
|
||||||
|
let base1 = ((i + 1) * width_resolution) as i32;
|
||||||
|
|
||||||
|
for j in 0..(width_resolution - 1) {
|
||||||
|
let a = base0 + j as i32;
|
||||||
|
let b = base0 + j as i32 + 1;
|
||||||
|
let c = base1 + j as i32;
|
||||||
|
let d = base1 + j as i32 + 1;
|
||||||
|
|
||||||
|
// triangle 1
|
||||||
|
out[offset + idx + 0] = a;
|
||||||
|
out[offset + idx + 1] = b;
|
||||||
|
out[offset + idx + 2] = c;
|
||||||
|
|
||||||
|
// triangle 2
|
||||||
|
out[offset + idx + 3] = b;
|
||||||
|
out[offset + idx + 4] = d;
|
||||||
|
out[offset + idx + 5] = c;
|
||||||
|
|
||||||
|
idx += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += face_amount * 3;
|
||||||
|
|
||||||
|
// Writing Positions
|
||||||
|
let width = 50.0;
|
||||||
|
let mut positions = vec![[0.0f32; 3]; position_amount];
|
||||||
|
for i in 0..slice_count {
|
||||||
|
let ax = i as f32 / (slice_count -1) as f32;
|
||||||
|
|
||||||
|
let px = decode_float(input_path[2 + i * 2 + 0]);
|
||||||
|
let pz = decode_float(input_path[2 + i * 2 + 1]);
|
||||||
|
|
||||||
|
|
||||||
|
for j in 0..width_resolution {
|
||||||
|
let alpha = j as f32 / (width_resolution - 1) as f32;
|
||||||
|
let x = 2.0 * (-px * (alpha - 0.5) + alpha * width);
|
||||||
|
let py = calculate_y(alpha-0.5)*5.0*(ax*PI).sin();
|
||||||
|
let pz_val = pz - 100.0;
|
||||||
|
|
||||||
|
let pos_idx = i * width_resolution + j;
|
||||||
|
positions[pos_idx] = [x - width, py, pz_val];
|
||||||
|
|
||||||
|
let flat_idx = offset + pos_idx * 3;
|
||||||
|
out[flat_idx + 0] = encode_float((x - width) * size);
|
||||||
|
out[flat_idx + 1] = encode_float(py * size);
|
||||||
|
out[flat_idx + 2] = encode_float(pz_val * size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing Normals
|
||||||
|
offset += position_amount * 3;
|
||||||
|
let mut normals = vec![[0.0f32; 3]; position_amount];
|
||||||
|
|
||||||
|
for i in 0..(slice_count - 1) {
|
||||||
|
for j in 0..(width_resolution - 1) {
|
||||||
|
let a = i * width_resolution + j;
|
||||||
|
let b = i * width_resolution + j + 1;
|
||||||
|
let c = (i + 1) * width_resolution + j;
|
||||||
|
let d = (i + 1) * width_resolution + j + 1;
|
||||||
|
|
||||||
|
// triangle 1: a,b,c
|
||||||
|
let u = vec_sub(&positions[b], &positions[a]);
|
||||||
|
let v = vec_sub(&positions[c], &positions[a]);
|
||||||
|
let n1 = vec_cross(&u, &v);
|
||||||
|
|
||||||
|
// triangle 2: b,d,c
|
||||||
|
let u2 = vec_sub(&positions[d], &positions[b]);
|
||||||
|
let v2 = vec_sub(&positions[c], &positions[b]);
|
||||||
|
let n2 = vec_cross(&u2, &v2);
|
||||||
|
|
||||||
|
for &idx in &[a, b, c] {
|
||||||
|
normals[idx][0] += n1[0];
|
||||||
|
normals[idx][1] += n1[1];
|
||||||
|
normals[idx][2] += n1[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
for &idx in &[b, d, c] {
|
||||||
|
normals[idx][0] += n2[0];
|
||||||
|
normals[idx][1] += n2[1];
|
||||||
|
normals[idx][2] += n2[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize and write to output
|
||||||
|
for i in 0..position_amount {
|
||||||
|
let n = vec_normalize(&normals[i]);
|
||||||
|
let flat_idx = offset + i * 3;
|
||||||
|
out[flat_idx + 0] = encode_float(n[0]);
|
||||||
|
out[flat_idx + 1] = encode_float(n[1]);
|
||||||
|
out[flat_idx + 2] = encode_float(n[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap_arg(&out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -274,6 +274,11 @@
|
|||||||
stroke-width: 1px;
|
stroke-width: 1px;
|
||||||
stroke: var(--color-layer-3);
|
stroke: var(--color-layer-3);
|
||||||
fill: var(--color-layer-2);
|
fill: var(--color-layer-2);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
svg:hover circle {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
circle.active,
|
circle.active,
|
||||||
circle:hover {
|
circle:hover {
|
||||||
|
|||||||
Reference in New Issue
Block a user