Live data from Hacker News

Writing a small ray tracer in Rust and Zig

nelari.us

41–50 of 98 posts

Re: Writing a small ray tracer in Rust and Zig

#41
post #24

This is an awesome post. At the risk of shedding it to bikes, one point that the author makes is that Zig's lack of operator overloading makes him write vector math like this: if (discriminant > 0.0) { // I stared at this monster for a while to ensure I got it right return uv.sub(n.mul(dt)).mul(ni_over_nt).sub(n.mul(math.sqrt(discriminant))); } He signs off with: > How do C programmers manage? The answer is simple: w…

In my experience writing math code the intermediary values get quite goofy Ex: orthogonal-vector-to-plane-bisecting-input-vector-and-first-column-vector But I rather use crazy descriptive names than hiding it away. Otherwise it gets quite incomprehensible when you reread it 3 months later Anyone else hit this problem? I suspect most people just reference a paper or book and use the letters to match the source ( x/y/n…

I think people's brains must work different, because for me this would be a terrible way to do it. I simply cannot read and comprehend math with very long descriptive variable names.

Whenever I see people do that, I have to write down the equation with single letters, and then look at it.

I am more of a literate programming type of person. I prefer writing longer explanations of code. But usually as a header. I like keeping the core of the code as clean and noise free as possible.

So I write code more like a math or physics book I guess. The equations are kept simple and clutter free, and then there is a body of text above or below explaining how to think about it. I tend to prefer using a lot of unicode, because following conventions helps me a lot. If I see a t₀, t and Δt variable e.g. I immediately get a sense of what sort of variables this is and how they are related. If instead it said start_time_of_incident, current_time and time_difference_between_events I could not quickly parse and internalize that.

Re: Writing a small ray tracer in Rust and Zig

#42
post #39

Earlier quoted context omitted.

In my opionion the stdlib is a bit too conservative. It is easy to end up with 200+ dependencies on more complex projects. Some things should definitely be moved into std over the long term. BUT: the time is not now. The language is still evolving rapidly. Upcoming features like specialization and a form of higher kinded types have the potential to impact API design a lot. I also really want named function arguments.…

The main problem is that you cannot version the standard library (well, there are "editions" but that's a bit of a workaround for other language changes). Go has the exact same problem, and has also historically made similar mistakes to Rust in their stdlib (the "syscall" module is strongly recommended against -- instead you should use "golang.org/x/sys"). And it should be noted that Go is even more bare-bones than R…

> And it should be noted that Go is even more bare-bones than Rust

In certain ways Go is more bare bones, but Go also comes with common hashes, some crypto primitives, encodings like JSON, compression/archives, logging, date/time utilities, Regex, a templating engine, an http client and server, regex, .... All of which requires a dependency with Rust.

I do remember an effort of a meta package like you mentioned. I think it was driven by brson and on Github, but I can't find it now, and it was abandoned anyway.

Re: Writing a small ray tracer in Rust and Zig

#43

> But rendering in separate threads turned out to be (unsurprisingly) harder than the way I would do it in C++...It was a bit frustrating to figure out how to accomplish this. Googling yielded a few stack overflow posts with similar questions, and were answered by people basically saying use my crate! Based on some discussion in r/rust ( https://www.reddit.com/r/rust/comments/c7t5za/writing_a_smal... ) I went ahead a…

https://rust-lang-nursery.github.io/rust-cookbook/ is sorta kinda this, sorta

I will say, the one example they have there which is sort-of analogous to "render each pixel of this image in parallel" is the "draw a julia set" one [0], and it's a very bad way of convincing a C/C++ programmer that Rust is good at this sort of thing. Even if the "loop over all rows in the main thread, adding to the pool a lambda that loops over each column" is somehow optimized in a good data-parallel way (I doubt it compares favorably performance-wise with "#pragma omp parallel for"), the lambdas then push each finished pixel into a channel along with their coordinates. The main thread then has to literally loop through every pixel and read from the channel for each and every one.

The natural way to do that in C/C++ is to just write the pixel to the bitmap in each thread. There are no race conditions here (everything is embarassingly parallel), just write the resulting pixel to the bitmap and be done with it. The only reason to have that channel with all that overhead (and that final synchronization on the main thread) is to satisfy the borrow checker, which is just silly in this case. It adds a tremendous amount of overhead just to make it idiomatic Rust.

It's true that you can do it the "C++ way" in Rust using unsafe and raw pointers (and there's probably crates that can do the "parallel for" in a way that compares well with OpenMP), but as a graphics programmer who's done a lot of this sort of thing, that piece of code made a very bad first impression of Rust as a high-performance language.

EDIT: also, the description is wrong. It says: "ThreadPool::execute receives each pixel as a separate job". No it doesn't, it receives each scanline as a separate job. It might be better if the pool had each pixel as a separate job, but that's not what the code is doing.

[0]: https://rust-lang-nursery.github.io/rust-cookbook/concurrenc...

Re: Writing a small ray tracer in Rust and Zig

#44
post #30

> But rendering in separate threads turned out to be (unsurprisingly) harder than the way I would do it in C++...It was a bit frustrating to figure out how to accomplish this. Googling yielded a few stack overflow posts with similar questions, and were answered by people basically saying use my crate! Based on some discussion in r/rust ( https://www.reddit.com/r/rust/comments/c7t5za/writing_a_smal... ) I went ahead a…

> But the article highlights that discovering the de facto standards is still a challenge for new Rust users -- does anyone know of a well-maintained list of the 10-20 most critical crates that new users should familiarize themselves with after reading The Book? I came across this exact thing recently: https://github.com/brson/stdx

That seems old, especially as error-chain is no longer maintained so I wouldn't recommend it.

[0]: https://users.rust-lang.org/t/error-chain-is-no-longer-maint...

Re: Writing a small ray tracer in Rust and Zig

#45
I didn't quite grok this bit:

> The ability to return values from if expressions and blocks is awesome and I don’t know how I’ve managed to live up until now without it. Instead of conditionally assigning to a bunch of variables it is better to return them from an if expression instead.

The example shown (aside from the fact it's assigning a tuple, which is a different point) would naturally be a ternary in C/C++. Does the awesomeness kick in for more complicated examples where you want intermediate vars etc in the two branches?

Re: Writing a small ray tracer in Rust and Zig

#46
post #45

I didn't quite grok this bit: > The ability to return values from if expressions and blocks is awesome and I don’t know how I’ve managed to live up until now without it. Instead of conditionally assigning to a bunch of variables it is better to return them from an if expression instead. The example shown (aside from the fact it's assigning a tuple, which is a different point) would naturally be a ternary in C/C++. Do…

Yeah, exactly. YOu know how it becomes a pain to make a const variable that needs some setup in C and C++? This lets you const all the things.

Re: Writing a small ray tracer in Rust and Zig

#47
post #39

Earlier quoted context omitted.

The main problem is that you cannot version the standard library (well, there are "editions" but that's a bit of a workaround for other language changes). Go has the exact same problem, and has also historically made similar mistakes to Rust in their stdlib (the "syscall" module is strongly recommended against -- instead you should use "golang.org/x/sys"). And it should be noted that Go is even more bare-bones than R…

> And it should be noted that Go is even more bare-bones than Rust In certain ways Go is more bare bones, but Go also comes with common hashes, some crypto primitives, encodings like JSON, compression/archives, logging, date/time utilities, Regex, a templating engine, an http client and server, regex, .... All of which requires a dependency with Rust. I do remember an effort of a meta package like you mentioned. I th…

The problem is that several of those standard library components are no longer recommended for general usage:

* As with "syscall", users are strongly suggested to use "golang.org/x/crypto" for crypto primitives like AEAD. All of the crypto bits in the standard library are probably still "okay" but there are better interfaces and more efficient implementations in "golang.org/x/crypto".

* The "flags" package is basically useless for large projects (everyone uses "cobra" or "spf13/cli" to create CLI interfaces now). It also has the really weird Go-ism of "-flag" arguments.

* For logging, most people use "logrus" or similar. "log" isn't necessarily bad, but it's not full-featured enough that most people end up not using it.

* As for HTTP servers, at the very least you'll use "gorilla" to deal with routes -- if not completely switch to a different HTTP server implementation.

* Not to mention some of the other weird bits and bobs which are useful, but are strange to include in such a small stdlib, like "mime". Or some of the more fruity stuff like "database".

This is the downside of the batteries-included model. Especially when a lot of the bits in the Go stdlib were included early in the language's life and then quickly became a clearly bad idea but it was too late to remove them.

Re: Writing a small ray tracer in Rust and Zig

#48
post #39

Earlier quoted context omitted.

In my opionion the stdlib is a bit too conservative. It is easy to end up with 200+ dependencies on more complex projects. Some things should definitely be moved into std over the long term. BUT: the time is not now. The language is still evolving rapidly. Upcoming features like specialization and a form of higher kinded types have the potential to impact API design a lot. I also really want named function arguments.…

The main problem is that you cannot version the standard library (well, there are "editions" but that's a bit of a workaround for other language changes). Go has the exact same problem, and has also historically made similar mistakes to Rust in their stdlib (the "syscall" module is strongly recommended against -- instead you should use "golang.org/x/sys"). And it should be noted that Go is even more bare-bones than R…

Ah, I found the meta approach I mentioned: https://github.com/brson/stdx

Re: Writing a small ray tracer in Rust and Zig

#49
post #21

Earlier quoted context omitted.

The Rust stdlib is specifically intended to be as lightweight as possible (while still providing those idiomatic abstractions that might be needed throughout the ecosystem, e.g. std.future) in order to avoid the Python "dead batteries" problem. What the Rust ecosystem is still lacking is a quasi-standard "Rust Platform" of best-practice library components where the community can freely deprecate something when a clea…

Rust needs something like Rust dev blessed "extension packs", in my opinion. Sort of like VS Code has extension packs. Basically have some metapackages for common development areas, that pull in community vetted, high quality libraries for certain areas.

why do they need to be dev blessed? You could do something like conda that's basically a distribution.

Re: Writing a small ray tracer in Rust and Zig

#50
post #43

Earlier quoted context omitted.

https://rust-lang-nursery.github.io/rust-cookbook/ is sorta kinda this, sorta

I will say, the one example they have there which is sort-of analogous to "render each pixel of this image in parallel" is the "draw a julia set" one [0], and it's a very bad way of convincing a C/C++ programmer that Rust is good at this sort of thing. Even if the "loop over all rows in the main thread, adding to the pool a lambda that loops over each column" is somehow optimized in a good data-parallel way (I doubt…

To me, this somehow says that most truely interesting problems can only be solved efficiently in Rust using unsafe. Granted, my definition of interesting may be a bit limited, but my initial takeaway here is that Rusts safety story is much more limited than its proponents claim.
Post reply on HN