Live data from Hacker News

Writing a small ray tracer in Rust and Zig

nelari.us

51–60 of 98 posts

Re: Writing a small ray tracer in Rust and Zig

#51
post #47

Earlier quoted context omitted.

> 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 basical…

I agree and I'm not advocating for Rust's std to gain things like http clients or template engines.

But some parts of the ecosystem end up in a lot of projects. Conservatively extending std would be good for the language, IMO. To set a standard, reduce compile times, and ease the burden for companies that have hard review requirements for each dependency.

Some things I'd like to see in std in a few years:

* `serde`

* `rand`

* `log`, but probably without a backend, or a simple default

* a subset of `chrono`

* some parts of `rayon`

Re: Writing a small ray tracer in Rust and Zig

#52
post #40

Earlier quoted context omitted.

No, there are plenty of safe ways to achieve this in the standard library. The chunks and split families of functions on slices are all designed to do pretty much exactly this.

In fairness to GP, they are implemented using unsafe (which is unsurprising since they take one &mut and return two to the same borrowed data).

If you go by that definition, I think you’ll eventually find out that everything depends on unsafe, and thus nothing is actually safe

Which isn’t a very useful distinction

Re: Writing a small ray tracer in Rust and Zig

#53
post #47

Earlier quoted context omitted.

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 basical…

I agree and I'm not advocating for Rust's std to gain things like http clients or template engines. But some parts of the ecosystem end up in a lot of projects. Conservatively extending std would be good for the language, IMO. To set a standard, reduce compile times, and ease the burden for companies that have hard review requirements for each dependency. Some things I'd like to see in std in a few years: * `serde` *…

What about a set of "blessed" crates (that can only depend on other "blessed" crates) that are maintained by the language developers? Seems like the best of both worlds to me.

Re: Writing a small ray tracer in Rust and Zig

#54
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…

Yes, anything which is more complex than a very simple if-else. The advantage is even more obvious with switch-expressions, e.g.:

https://ziglang.org/documentation/master/#switch

https://doc.rust-lang.org/reference/expressions/match-expr.h...

Re: Writing a small ray tracer in Rust and Zig

#55
post #29

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…

So why not just write the original formula into the comment above the code? Maybe it's not the purest approach, but it sure would help parsing the code in this case.

Why not one step further, and let the original formula be the code? Directly compilable Latex:

    \vec r = \frac {n_{1}}{n_{2}} \cdot (\vec v - dot(\vec v, \vec n) \cdot \vec N) - \sqrt{1 - \frac {n_{1}^2}{n_{2}^2} \cdot (1 - dot(\vec v, \vec n))} \cdot \vec N
(This is partly a joke and partly a serious suggestion, there are definitely people out there who would find that easier to write, especially if the IDE rendered it properly. I stole it by searching for ni_over_nt and finding http://viclw17.github.io/2018/08/05/raytracing-dielectric-ma... )

Re: Writing a small ray tracer in Rust and Zig

#56
post #55
post #29

Earlier quoted context omitted.

So why not just write the original formula into the comment above the code? Maybe it's not the purest approach, but it sure would help parsing the code in this case.

Why not one step further, and let the original formula be the code? Directly compilable Latex: \vec r = \frac {n_{1}}{n_{2}} \cdot (\vec v - dot(\vec v, \vec n) \cdot \vec N) - \sqrt{1 - \frac {n_{1}^2}{n_{2}^2} \cdot (1 - dot(\vec v, \vec n))} \cdot \vec N (This is partly a joke and partly a serious suggestion, there are definitely people out there who would find that easier to write, especially if the IDE rendered…

You could probably do it that way in Julia.

Re: Writing a small ray tracer in Rust and Zig

#57
post #50
post #43

Earlier quoted context omitted.

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.

To reply to both you and your parent at once, yes, the reason this is in the nursery is that it's not a complete resource yet. I agree that this particular example is bad; it's showing the right pattern for the wrong example.

The right way is to use rayon, which is similar to OpenMP in this sense. Each thread would get a pointer to the chunk of the buffer it's operating on. You don't need to write any unsafe code to do this.

Re: Writing a small ray tracer in Rust and Zig

#58

> 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…

I find lib.rs mentioned in the article a good tool. Here on concurrency: https://lib.rs/concurrency

Re: Writing a small ray tracer in Rust and Zig

#59

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…

> I’m convinced that there’s a proper mathy / lighting-y word for each component in that expression.

Sometimes yes, but often no. Frequently this kind of expression is the result of solving an equation, so it’s just an expression.

Graphics people often use two approaches for sub-expressions:

- You can name them with the same letters that are in the expression, just with the punctuation & operators removed, for example:

    const uvMinusNTimesDt = uv.sub(n.mul(dt))
- Alternatively, just like with equations, math people often freely assign single letter names to variables without worrying about semantic meaning.

    const q = uv.sub(n.mul(dt))
Nothing really wrong with naming sub-expressions after fruits, or single letters, or spelling them out explicitly.

It might be worth reflecting on what the goals are with your naming, and whether it matters what they’re named. As software engineers, our biases lean toward making choices that improve readability and maintainability. But for a specific equation that will never change once it works correctly, our preconceived notions about good software design and best practices might not actually apply to this situation. It might be more important to document the source of the equation than to make the implementation readable.

Re: Writing a small ray tracer in Rust and Zig

#60
post #24

Earlier quoted context omitted.

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…

Yeah, I feel you on that and I started out writing in a similar style b/c it's terse and easy to digest. To be clear, this is mostly a hobby things for me so I'm not speaking from a position of authority, but in my limited experience once the problem gets bigger and you worry about performance/caching/recursion/etc. the math and equation start to diverge from the code substantially.

For instance over the last few months I've been playing with BLAS and the BLAS operators just don't really map cleanly to equations - and the way you structure efficient solutions just ends up being more nuanced and complicated than the simple clean "theoretical" on-paper solution. All the nuances need to be captured in the variable names to have any chance of making the code understandable

Post reply on HN