I felt like ray marching a signed distance field in PICO-8.

(Don't ask me why..).

Now that is very interesting. It seems that the built in square root becomes less accurate with non-integer values. Not only is sqrt(3.999)<sqrt(4.0001), but it seems that sqrt(3.9) is equal to sqrt(4.08407). However, sqrt tends to work fine with large numbers so this gave me an idea.

mysqrt(v) return shr(sqrt(shl(v,2)),1) end |

This is essentially sqrt(v*4)/2, but using bit shifting. Its not measurably faster than us multiplication but I think its useful to know what is being done here. Here it is implemented into the posted cart.

Now this does have some limitations. It cuts off the top two bits of the input, limiting the size of inputs it can handle. Although the top bit is for sign, which may be outside of the domain for a sqrt function and could be handled separately if it isn't(it may involve switch to a logical shift, I haven't put thought into which is appropriate here). That only leaves one bit of magnitude being lost which will only be a problem for rather large numbers. Also since this only shifts the input by two bits, numbers may be small enough that they are still to small too be accurately handled.

You could also use multiplication and division directly as shifting can only multiply/divide by powers of two, but that will be slower and possibly less accurate. Picking the amount to shift/multiply will depend on the size of the inputs you expect.

I had a play with some colours, patterns and reflections.

It still uses my slow square root. @Shoxidizer's trick unfortunately wasn't accurate enough to make the reflections come out okay - although it did make a big improvement in the original cart.

Can you avoid the slow sqrt by comparing squared values only?

Eg x^2+y^2>r^2

Hmm.. Couldn't quite get it working comparing the squared distances.

The issue is that it's a signed distance field, so sometimes the distances are negative (for points sampled inside solids).

I was able to kindof fudge it by calculating the squared distance times the sign of the value (e.g. if the distance is -5, it would use -25). I think it was working, but it was a bit of a mess and didn't feel much faster after all the workarounds, so I've rolled it back.

Anyway, here's a version that randomises the colours and positions, so you don't always get the same image.

[Please log in to post a comment]