three-gpu-pathtracer
three-gpu-pathtracer copied to clipboard
Add support for "Ray Splitting"
https://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/Russian_Roulette_and_Splitting
I can put a bounty on an accepted PR of "Ray Splitting" of $500 USD sponsored by @Threekit.
I might take a look at this next. @gkjohnson Can you elaborate a bit more on what you expect from a successful implementation?
Heh to be honest I made this issue pretty flippantly once I saw the article on splitting thinking it was something to look into later 😅.
Looking at the article again it looks like what's involved is generating multiple rays off of the surface after the first camera ray hit to save on at least that first ray. So you can split that first hit N number of times based on some uniform. It likely won't help a lot for cases where heavy depth of field is used but for sharp images it should help a bit, at least.
Another place where splitting a ray could be useful is when hitting a translucent or transparent surface and two rays could be traced (one transmissive, one reflective) so we could avoid noisiness in the initial render. But I think this is more complicated and would require some more significant refactoring.
I'm imagining the former being considered successful here. @bhouston is that what you're imagining, as well? Open to other thoughts on how this kind of splitting could be used to save on the total number of rays cast.
@gkjohnson i am supporting your vision here - it is your call. I just put bounties on bunch of your issues to help move the project forward in general. I didn’t have a personal or company stake in this one.
If the speed up is worth the added complexity and this is a standard feature in path tracers we should do it. @erichlof what do you think? Is this a viable direction we should go to speed things up or should we look at other things first?
Hello everyone, I carefully read and re-read the pbr book link provided, and after thinking about it, I'm not so sure if RR or Splitting would significantly benefit this particular renderer in either quality or converging performance. Please allow me to explain:
First, regarding Russian Roulette, on several occasions I have experimented with the RR technique of randomly terminating rays. The decision on whether or not to terminate them is usually influenced by the amount of (or lack of) their contribution to the final image. Where this technique makes sense is if we wanted a totally unbiased renderer, which, to be unbiased, must allow rays to continue infinitely, or until they run out of energy. Obviously we don't have the computing resources to allow this to play out, so RR guarantees that our program won't take forever, while also guaranteeing that because we up-weighted the surviving rays, that the renderer would match the infinitely recursive renderer, if we could stick around long enough to compare the two.
So to use RR in the intended fashion, there could be no more caps like Max_Bounces and such: the bounces loop would need to be of the 'while(true)' variety. Speaking personally, I'd rather have a guarantee of Max_bounces ending the loop with slight, unnoticeable bias, rather than leaving it up to probability and an infinite loop. Case in point, even with this all in place, there were a few times when my simple Cornell Box scene locked up on me and crashed the browser, because somehow a few rays kept passing the RR test. It's a little unsettling having that under the hood. Also, with RR, I got more black spots and noise(variance) towards the beginning of the samples requestAnimation loop (or when the camera moved), due to rays getting terminated that would have ended up hitting something important, if they had been allowed to continue for just a few more bounces. But such is the way with RR and probability and being truly unbiased. Again, if the ultimate physical/photo-realistic result was required for scientific research, then RR totally makes sense, and is almost a necessity. But I don't think that is a requirement for this renderer - it is still possible to get the highest visual quality and at the same time enforce a slightly biased Max_bounces limit.
Now with Ray Splitting, from reading the pbr book passage, Garrett I think the author had something different in mind. It is an unfortunate chapter name, Ray Splitting, because I don't believe any rays are actually split, like you alluded to with transparent surfaces. What you were referring to is called Ray trees and branching, where 2 rays are spawned at every transparent surface, one branch following the reflected path off the material, and the other following the refracted path through the same material. You are right that this would indeed be more expensive and memory intensive, and would require refactoring of all the bounces loops in the codebase. The only upside to this is, like you mentioned, you get noise-free transparent materials on the very first sample - (but at what cost?). My renderer has employed both strategies in the past (ray trees vs randomly sampling BRDF), but I have since settled on Peter Shirley's method of Monte Carlo-style randomly choosing either a reflective ray path or a refraction ray path at each juncture. In my opinion, the GPU performance outweighs the slight initial material noise.
What the author is meaning by Splitting, (and I wish he had expounded further, because it feels a little truncated and unfinished), is that the rays themselves aren't being split, but the initial work distribution is. In other words, you might be able to get the same soft shadow quality if you send one camera ray on every pass, but send multiple shadow ray samples from whatever that camera ray intersects. Rather than wasting 50 anti-aliased pixel camera rays, each having to send multiple shadow rays for soft shadows, you could just 'split' the gpu work into less camera rays and a few more shadow rays. The end result is less total rays being used, but the same shadow quality. Note that this would not work so well with Depth of Field effects, like Garrett also mentioned.
Therefore, I don't think that RR or 'Splitting' would be magic bullets here. In the case of Splitting, it would need to be hand-tuned for each scene, because the user may not know in advance what the proportion, or Splitting, of camera rays vs shadow rays should be, until they get a sub-par image back.
Anyway, that's my take on that particular section of the PBR book. I'm sure that it could be useful for certain renderers out there, but the refactoring cost/complexity and per-scene fine tuning make it less than desirable.
Thank for @erichlof for taking the time analyze and explain your reasoning on this potential feature. Yes, it feels like we do not need to proceed in this direction at this time.
Thanks for the detailed analysis @erichlof. I will not pursue this at this time.
Yeah thanks for the detailed write up @erichlof - it sounds like maybe at some point ray splitting could be valuable (still saves some rays!) but improving feature capability seems like a better place to focus at the moment. And wasn't under the impression that RR required infinite bounces but it does make sense!
@gkjohnson
Yes I suppose you wouldn't need an infinite bounce loop in order to be able to use RR, as I just read in this link you shared from your 'add RR' issue thread: https://computergraphics.stackexchange.com/questions/2316/is-russian-roulette-really-the-answer
The 1st reply to the question is really great and taught me a thing or two (thanks for sharing that link)! From reading this, I think it would be possible to simultaneously have unbiased RR and a biased max bounces cap, but as the answer poster mentions, the settings would have to be carefully tuned from scene to scene, and not set too low as to reveal the artificial-looking biased nature (especially on translucent materials), or not set too high and be wasting computer/gpu processing power (which kind of defeats the purpose of adding RR in the first place, ha).
I don't know, I suppose down the road if translucency/SS materials were becoming an issue, we could maybe look into trying out RR with a sensible max bounces cap, like 10 or something. Maybe it would save on the deep number of random bounces required to successfully get through thick subsurface materials. And since adding RR is only 5 lines of shader code, I wouldn't write off RR forever, but maybe to have in the toolkit if SS/translucent materials need additional strategies in the future.