-
Notifications
You must be signed in to change notification settings - Fork 398
Add testrender volumes #2053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add testrender volumes #2053
Conversation
|
Hi, just checking up on this. It's still marked as draft, still needs a DCO sign-off on all commits, and it's failing some CI tests. DCO -- the easiest fix is on your end to squash all the little commits into one, make sure that one has the "Signed-off-by: Your Name your@email", then do a force push to the same branch to replace what you have. CI tests -- I suspect that some numerical differences between platforms simply require more than one reference output. I can help with this, if you can fix the other problems. |
528f6d6 to
64f56b6
Compare
|
Thanks for the follow-up and guidance. I’ve squashed the commits into one and signed off. Are there any other changes I should address aside from the CI issues? |
src/testrender/shading.cpp
Outdated
| OSL_HOSTDEVICE BSDF::Sample | ||
| Medium::sample_phase_func_vrtl(const Vec3& wo, float rx, float ry, float rz) const | ||
| { | ||
| return dispatch([&](auto medium) { return medium.sample_phase_func(wo, rx, ry, rz); }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not const auto& ?
Also, happy to see more people using this "static-virtual" trick. Sometimes when it doesn't like what you do the compile errors are nightmare-ish.
| scatter = s.t < hit.t || scatter; | ||
| combined_sample.t = s.t < combined_sample.t ? s.t | ||
| : combined_sample.t; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, mediums are combined? I thought they were exclusive with the priority. I must be missing something.
|
Very nice addition. I would just ask for clarification on the stack, priorities and policy. In my mind, an ice cube with medium A floating in water with medium B pushes the water away. So in the stack inside the ice you have A (highest prio) But only A is active. When you exit the ice your stack is only B, making the water active. No? |
Alongside the rest of the initialization for subpixel_radiance, an empty MediumStack is initialized. Its behavior is conceptually similar to the existing CompositeBSDF. Media are stored in a statically allocated char pool, with pointers maintained in mediums[MaxMediums]. In processing medium closures, either HomogeneousMedium or EmptyMedium are inserted into the medium stack. There is a simple priority handling scheme that will shuffle the incumbent medium pointers to give high priority mediums lower indices. They both inherit from a shared CRTP interface, Medium. When processing BSDF closures, intersections with MxDielectric or MxGeneralizedSchlick may only be added when priority < current_priority or are both 0 (the precious priority). MediumStack exposes an integrate method that operates on aggregated parameters from all media sharing the same priority as the topmost medium; these aggregated parameters are stored on the stack and updated whenever media are added. A CDF built from these parameters is then sampled to select one of the overlapping media for scattering. At present, only Henyey–Greenstein phase functions are supported, implemented as a BSDF subclass. Signed-off-by: Owen O'Malley <theowen@email.com>
64f56b6 to
99e45d5
Compare
|
I'll let @fpsunflower and @aconty comment in detail, but glancing and the results, I think this is a lot more along the lines of what we expect for this feature in a renderer. |
|
@ThyOwen Do you know what's up with the CI failures? |
fpsunflower
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The general setup seems like its going in the right direction - see comments below for some things I think should be checked though.
Also - I would make sure the code works with closures like glass than can both reflect and refract. At a high level it looks like the medium update happens when we hit the surface (depending on the backfacing flag). I would expect the medium stack to change only if we pick a direction that actually crosses from one side to another. I might have missed something though.
| }; | ||
|
|
||
|
|
||
| struct HenyeyGreenstein final : public BSDF { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is already an implementation of this in the BSDL headers - is it possible to re-use that one?
| }; | ||
|
|
||
| struct EmptyMedium final : public Medium { | ||
| MediumParams params; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If even the empty medium needs to have MediumParams - maybe the field should be in the base class?
Do we even need a class hierarchy here given that this medium tracking is only ever going to support homogeneous media?
| num_overlapping++; | ||
| } | ||
|
|
||
| if (num_overlapping > 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is needed. You can just merge the sigma_t's by summing them up and then sample from that summed value.
When sampling the phase function, you want to take into account all the different overlapping sigma_s's and pick one.
|
|
||
| Vec3 rand_vol = sampler.get(); | ||
| float t_volume = -logf(1.0f - rand_vol.x) | ||
| / current_params.avg_sigma_t(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to perform MIS among the 3 color channels. Sampling using the average will not work well if there is a strong difference between the channels.
| weight = combined_albedo / tr; | ||
| } else { | ||
| tr = transmittance(current_params.sigma_t, hit.t); | ||
| weight = Color3(1.0 / tr.x, 1.0 / tr.y, 1.0 / tr.z); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be missing something, but this doesn't look correct. The weight should be the transmittance divided by the PDF. This is computing the 1 / transmittance which seems odd.
| tr = transmittance(current_params.sigma_t, t_volume); | ||
| Color3 combined_albedo = current_params.sigma_s | ||
| / current_params.sigma_t; | ||
| weight = combined_albedo / tr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be simpler to merge this block and the one bellow so all the scatter logic is together.
Like below, I'm not quite following the logic on how the weight is computed here.
The weight should be transmittance / pdf, not albedo / transmittance.
To include MIS between the color channels, you want to consider sampling from r,g,b for sigma_t independently. The weighting between these should depend on the combined sigma_s (so that channels that don't have any scattering will not contribute). This way - if you don't have any scattering - you won't generate any sample for transmittance and can pass straight through without an additional random decision.
| rand_phase.y, | ||
| rand_phase.z); | ||
|
|
||
| if (phase_sample.pdf <= 0.0f) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you see negative values in practice?
I would write the test as if (pdf > 0) { ... return true; } return false; to be defensive against any NaN values.


Description
Alongside the rest of the initialization for
subpixel_radiance, an emptyMediumStackis initialized. Its behavior is conceptually similar to the existingCompositeBSDF. Media are stored in a statically allocatedcharpool, with pointers maintained inmediums[MaxMediums]. In processing medium closures, eitherHomogeneousMediumorEmptyMediumare inserted into the medium stack. There is a simple priority handling scheme that will shuffle the incumbent medium pointers to give high priority mediums lower indices. They both inherit from a shared CRTP interface,Medium. When processing BSDF closures, intersections withMxDielectricorMxGeneralizedSchlickmay only be added whenpriority < current_priorityor are both 0 (the precious priority). Attached to theMediumStack, anintegratemethod transmittance samples each medium and scatters using the phase function of the highest priority medium. As of now, onlyHenyeyGreensteinis implemented and inherits fromBSDF.With this being both a sizable update and my first commit to the project, I’m more than happy to iterate on this.
Tests
render-mx-medium-glass,render-mx-medium-vdf,render-mx-medium-anisotropicwith OptiX references of the latter two. The images forrender-mx-generalized-schlick-glassandrender-mx-dielectric-schlick-glasshave been updated as well.Checklist:
already run clang-format v17 before submitting, I definitely will look at
the CI test that runs clang-format and fix anything that it highlights as
being nonconforming.