fidget
fidget copied to clipboard
Weird Rhai error
So I just started playing around with the viewer.
This Rhai script
fn length(x, y) {
sqrt(x*x + y*y)
}
draw(|x, y| length(x, y) - 1))
works as expected.
However
fn length(x, y) {
sqrt(x*x + y*y)
}
fn circle(x, y, r) {
length(x, y) - r
}
draw(|x, y| circle(x, y, 1))
Yields:
render thread got error "Rhai error: Function not found: __draw (Fn) (line 2, position 5)\nin call to function 'draw' (line 9, position 1)"; forwarding
This is somewhat sneaky: there is already a function named circle, and it's getting called instead of your function. In addition, it's already set up to return a lamda function, so you'd invoke it like
draw(circle(0, 0, 1)) // center x, center y, r -> (Fn(x, y) -> f32)
It works if you rename your function to not collide with the existing function:
fn length(x, y) {
sqrt(x*x + y*y)
}
fn my_circle(x, y, r) {
length(x, y) - r
}
draw(|x, y| my_circle(x, y, 1));
However, this violates the search order in the Rhai docs (and is confusing!), so let's leave this issue open.
However, this violates the search order in the Rhai docs (and is confusing!), so let's leave this issue open.
Shall I report this upstream to the rhai peeps?
It works if you rename your function to not collide with the existing function:
fn length(x, y) { sqrt(x*x + y*y) } fn my_circle(x, y, r) { length(x, y) - r } draw(|x, y| my_circle(x, y, 1));
When I try this with viewer in the current main branch, I get:
❯ cargo run -- test.rhai
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.09s
Running `/home/moritz/code/crates/fidget/target/debug/viewer test.rhai`
[2024-04-09T11:58:18Z ERROR viewer] render thread got error "Rhai error: Function not found: draw (Fn) (line 9, position 1)"; forwarding
[...]
Ah, I see, it doesn't take a closure any more. Sorry about the noise, kindly ignore!
Docs say there is a draw_rgb function in Rhai but I get an error when trying to call this. Also: what's the signature of this function?
Yes, #67 switched to using the new Tree type in scripts (instead of closures).
The new signature is draw_rgb(Tree, f32, f32, f32), e.g. this works for me:
draw_rgb(circle(0, 1, 2), 1.0, 0.0, 0.0)
Cheers, it was a typo.
Is there a list of built-ins somewhere? It seems e.g. Rhai is missing e.g. abs? Docs say one needs to include ArithmeticPackage but the docs also say Engine::new() would include that. What am I missing?
I can not get a simple box in the viewer. Whatever function I try, except for the circle, I only get the positive part of the axes, i.e.
fn abs(x) {
if x < 0 {
-x
} else {
x
}
}
fn box(x, y, radius_x, radius_y)
{
let p_x = abs(x) - radius_x;
let p_y = abs(y) - radius_y;
max(p_x, p_y)
}
draw(box(x, y, 1, 1))
I get:
Zooming out:
I also tried move(box(...),...) but no luck. What am I missing?
Here's the issue:
fn abs(x) {
if x < 0 {
-x
} else {
x
}
}
During script evaluation, x is a Tree handle. Normally, trees capture operations through operator overloading, e.g. x + 1 will return a new Tree. For some reason, Rhai comparisons of different types always return false, so x < 0 is evaluated during script evaluation and returns a new Tree that is always -x.
#70 (merging soon) adds overloaded operators to ban these comparisons, so that it will fail at script evaluation instead of returning a misleading result. This PR also adds missing opcodes, so you can write your script as
fn box(radius_x, radius_y)
{
let ax = axes();
let p_x = abs(ax.x) - radius_x;
let p_y = abs(ax.y) - radius_y;
max(p_x, p_y)
}
draw(box(1, 1))
(I'm still figuring out best practices, but using axes() within a function seems cleaner than passing x, y as arguments)
(I'm still figuring out best practices, but using axes() within a function seems cleaner than passing x, y as arguments)
Speaking of which: writing the functions in Rhai, doing each operation for each coordinate, is very verbose because of the lack of tuple types. Most functions from e.g. here almost double in code length. For 3D cases it will be even more verbose.
What is the performance hit if one used arrays of two (or three) elements to represent vectors?
Of course then one would need to write the entire shebang of basics like mul, add, div etc. that work on those arrays.
And the code of the kind of expressions used in SDFs would still look more like Lisp than math. :grin:.
I.e. best would probably be some language extension that supports vectors (and possible matrices) inside Rhai? Not sure this possible.
EDIT: I just saw this, so it seems this is possible and likely axes() does something like this already?
https://github.com/mkeeter/fidget/pull/70 (merging soon) adds overloaded operators to ban these comparisons, so that it will fail at script evaluation instead of returning a misleading result. This PR also adds missing opcodes, [...]
Cheers! :smiley:
So I have something like:
fn rounded_box(
height_x, height_y,
radius_top_right,
radius_bottom_right,
radius_top_left,
radius_bottom_left)
{
let ax = axes();
let x = ax.x;
let y = ax.y;
let r_x = if 0.0 < x { radius_top_right } else { radius_top_left };
let r_y = if 0.0 < x { radius_bottom_right } else { radius_bottom_left };
let r_x = if 0.0 < y { r_x } else { r_y };
let q_x = abs(x)- height_x + r_x;
let q_y = abs(y)- height_y + r_x;
min(max(q_x, q_y), 0) + length(max(q_x, 0.0), max(q_y, 0)) - r_x
}
And that gives me an error for the comparisons in the if a < bs:
cannot compare Tree types during function tracing
I tried rewriting the resp. expressions with compare(a, b) but this:
let r_x = if compare(0, x) == -1 { radius_top_right } else { radius_top_left };
let r_y = if compare(0, x) == -1 { radius_bottom_right } else { radius_bottom_left };
let r_x = if compare(0, y) == -1 { r_x } else { r_y };
results in the same error.
What is the workaround here?
EDIT: thinking back of my days as a VFX shader writer (where conditionals were a no-no): step()/filteredstep() would be the alternative(s). And re. the latter: will there be access to filter size(s)/derivatives?
And another one. A simple rounding op, i.e.
fn round(shape, radius) {
shape - radius
}
Only grows my shape by radius but there is no rounding. This is obviously somehow possible as visible in the viewer for the gradient 2D SDF view mode.
What am I missing/what is the workaround?