Repository navigation
fix/volume detection - #730
thot-experiment wants to merge 4 commits into
Conversation
PathTracer::RenderLightSample() and the PhotonGI photon tracer started every light path with an empty volume stack and never read the light's volume (scene.lights.<name>.volume), unlike BIDIRCPU which already pushes it. RenderLightSample() is used by LIGHTCPU and by the hybrid back/forward light tracing of PATHCPU and PATHOCL (native threads). In hybrid mode caustic paths are rendered only by the light tracer, so for a light inside a volume the first light path segments ignored the volume whenever they ended on an object without an exterior volume: volume caustics went missing and surface caustics were too bright, as the fog attenuation before the first surface was skipped. The light paths now start inside the light volume (no change for lights without a volume). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BlendLuxCore (and most scenes) define the volume of a light only when the user explicitly sets one, so the light paths of a light inside a volume started with an empty volume stack. Each segment then took its volume from the surface it ended on, which is wrong for segments ending on objects inside the volume without an exterior volume (i.e. a glass sphere inside fog): the fog was ignored along those segments. Lights without a scene-defined volume now get the volume including their position: - Scene::GetPointVolume() follows a ray through all the surfaces and collects the volumes including its origin: the interior volumes of the objects exited without having been entered (only objects with an interior volume are counted, as they must be closed meshes) and the exterior volume of the first surface entered, if defined. The result is the current volume of a PathVolumeInfo filled with them from the outermost to the innermost, so volume priorities are applied as for a path entering all of them from the outside. Without any, the default world volume is used. - Scene::UpdateLightVolumes() runs after the light preprocessing (on geometry, material, light and image map edits). It uses the origin of an emitted ray as the light position; environmental lights keep no volume and the triangles of a mesh light share one lookup. - LightSource::autoVolume marks the computed volumes: an explicit scene.lights.<name>.volume, or the exterior volume of the material of a mesh light, is kept as before, and computed volumes are not written back by ToProperties(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With scene.camera.autovolume.enable (the BlendLuxCore default), the camera volume was taken from the first surface hit by a ray through the center of the screen: its exterior volume when entering, its interior volume when exiting. With a camera inside a volume and the center of the screen on an object without an exterior volume (i.e. a glass object inside fog), the camera got no volume: eye paths started with an empty volume stack and the fog disappeared in front of all the objects inside the volume, depending on where the camera was aimed. The camera volume is now the volume including the camera position, computed with Scene::GetPointVolume() as for light sources (including the volume priorities). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scene::Intersect() (CPU and GPU) used the same pseudo-random number, passThrough, for two decisions: the volume scattering along the ray segment and, as the pass-through event of the hit point, the event sampled by the material at the end of the segment (i.e. glass uses it to choose between reflection and transmission). The code already noted the "subtle correlation". The correlation is not subtle: a segment has no scattering event only when u >= 1 - exp(-sigmaS * distance), while glass transmits only when u < threshold, with the threshold clamped to at most 0.75. Behind an optical depth larger than ln(4) (~1.39), every ray reaching the glass without scattering was reflected and refractions seen through fog disappeared entirely (i.e. a glass sphere 3.5 units away in a fog with sigmaS = 0.5). The volume scattering now uses its own pseudo-random number, the first value of a Tausworthe generator seeded with passThrough (the same on CPU and GPU), while passThrough is still used for the pass-through events. With absorption-only fog, the refracted image is now attenuated by the expected exp(-sigmaA * distance). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
For this one, I requested @CodeFHD's review, as he's much more an expert in that field than me. |
|
Noted, I will review on the weekend |
|
@thot-experiment Can you share your test scene for comparison purposes? I will set up my own as well. |
|
oh i'm so sorry, i had actually made it public i just forgot to link it https://github.com/thot-experiment/luxcore-demo-scenes/tree/main/fix_volume-detection |
|
I've been looking into this today. I did find some side-effects of this, as well as other observations that seem to be unrelated. First, a conceptual problem: the new function UpdateLightVolumes() adds meshlight volumes in a preprocessing step based on a single ray with fixed parameters: Another note on this, given those fixed parameters, Moving on, the addition of Another regression happens when dealing with overlapping volumes, where somehow wrong volumes are being taken. See my attached scene (description below) and move the object I also noticed some changed behavior depending on whether objects have internal and or external volumes assigned or nothing connected, even though this should imply the same clear volume. I still need to understand the rest properly, and figure out what was a pre-existing condition and what is new. Attached is a test-scene of my own. Let me know if I missed anything obvious in terms of the intended changes. |
|
Thanks for the thorough review, I was aware of this
but I had thought this was the original behavior. I wasn't aware of the other bugs, I've found some other strange interactions with volume detection in further testing, for one it seems like a camera inside a bubble causes scattering to behave strangely in the outer medium. I've moved this to a draft PR until I have some time to look into it, no need to bother investigating further unless you feel like it. Thanks again. |
|
Well, at least this PR induces the specific scenario. Before, you can induce it by assigning a fixed exterior volume, which is not what you are doing in your test scene. You have to consider the problem of automatically determining volumes in 3D modelling. If you look at it from the reality perspective, all meshes need to be manifold with well defined interior/exterior sides (no faces crossing), and only defining interior volumes. Then, for auto-detection, you might need to trace two or more rays until you hit a surface on its interior side (imagine bouncing off multiple mirrors inside a scattering volume), trace additional diagnostic rays, or probably other techniques exists to determine which volume a point is inside, I don't know. In Blender, you may create non-manifold meshes, making it more complex. I am not sure how much that can ever be worked around though (personally I would not treat it more than really necessary, but that is my preference for spending time). |
This is a group of fixes that irons out a few bugs when detecting camera volumes, see commit messages for more info.
Comparison Grid
