WIP: Cycles: Implement volume stack priority and nested IOR support #118478

Draft
Lukas Stockner wants to merge 1 commits from LukasStockner/blender:volume-stack-priority into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Member

This patch implements proper support for nested volumes and dielectrics.

Effectively, there's two parts to it:
First, it implements a priority/masking system for overlapping volumes. By default, in Cycles, overlapping volumes just combine so that both apply. This patch adds a "priority" value to materials, which allows to override this. In particular, if a volume with a higher priority overlaps one with lower priority, only the one with higher priority applies (as if a boolean was used to cut it away). If two have equal priority, they mix as usual. Volumes with priority 0 (the default) ignore this system and always apply.
Second, the volume stack is extended to also track the IOR of each volume. This is used to implement nested dielectics in the same way as pretty much every renderer: If a refractive interface is hit while inside a volume with higher priority, the hit is ignored. Otherwise, we look up the "opposite IOR" by checking the IOR of the volume we're currently in (if entering a volume) or of the volume that's next in the stack (if leaving a volume), and use that in the refraction calculation instead of assuming air/vacuum on the other side.

Quick comparison (the obligatory "glass with liquid and ice cubes" scene), with and without priorities:

Without With
nested-without.png nested-with.png

Note how the reflection is weaker (since there no longer is air->glass and air->liquid, but just air->glass and glass->liquid) and how the ice cubes show barely any refraction (since the IORs are almost identical), but do "carve out" the absorption of the liquid.
There's no booleans or any of the usual tricks (e.g. explicitly modeling the boundary) here, just overlapping meshes and priorities.

TODOs:

  • No OSL support yet.
  • Currently surface hits are only masked/skipped for Glass and Principled BSDF. In theory, we could enable this for all surface shaders, but that might be unexpected. Alternatively, we could expose "current/next priority" as inputs for shaders, so advanced users can build custom stuff (we need to expose them for OSL anyways).
  • If we don't want to block all surface shading, the Principled BSDF code should be changed to only replace the transmission component with transparency.
  • The Principled BSDF only accounts for the opposite IOR for transmission, things like coat/specular still assume air. I think this is fine though, the opposite might be confusing/unexpected.
  • The current logic for determining the necessary stack depth doesn't work anymore.
  • Shadow volume stacks shouldn't track IOR, it's just a waste of space.
This patch implements proper support for nested volumes and dielectrics. Effectively, there's two parts to it: First, it implements a priority/masking system for overlapping volumes. By default, in Cycles, overlapping volumes just combine so that both apply. This patch adds a "priority" value to materials, which allows to override this. In particular, if a volume with a higher priority overlaps one with lower priority, only the one with higher priority applies (as if a boolean was used to cut it away). If two have equal priority, they mix as usual. Volumes with priority 0 (the default) ignore this system and always apply. Second, the volume stack is extended to also track the IOR of each volume. This is used to implement nested dielectics [in the same way as pretty much every renderer](https://escholarship.org/content/qt9h83s3m0/qt9h83s3m0_noSplash_693fb7df0433335e068723e435d6a371.pdf): If a refractive interface is hit while inside a volume with higher priority, the hit is ignored. Otherwise, we look up the "opposite IOR" by checking the IOR of the volume we're currently in (if entering a volume) or of the volume that's next in the stack (if leaving a volume), and use that in the refraction calculation instead of assuming air/vacuum on the other side. Quick comparison (the obligatory "glass with liquid and ice cubes" scene), with and without priorities: | Without | With | | - | - | | ![nested-without.png](/attachments/f4b0b09c-cb93-47cc-992a-2d0eee26b8e9) | ![nested-with.png](/attachments/6205db6d-e7ab-4acc-b4e6-2e7205d836c2) | Note how the reflection is weaker (since there no longer is air->glass and air->liquid, but just air->glass and glass->liquid) and how the ice cubes show barely any refraction (since the IORs are almost identical), but do "carve out" the absorption of the liquid. There's no booleans or any of the usual tricks (e.g. explicitly modeling the boundary) here, just overlapping meshes and priorities. TODOs: - No OSL support yet. - Currently surface hits are only masked/skipped for Glass and Principled BSDF. In theory, we could enable this for all surface shaders, but that might be unexpected. Alternatively, we could expose "current/next priority" as inputs for shaders, so advanced users can build custom stuff (we need to expose them for OSL anyways). - If we don't want to block all surface shading, the Principled BSDF code should be changed to only replace the transmission component with transparency. - The Principled BSDF only accounts for the opposite IOR for transmission, things like coat/specular still assume air. I think this is fine though, the opposite might be confusing/unexpected. - The current logic for determining the necessary stack depth doesn't work anymore. - Shadow volume stacks shouldn't track IOR, it's just a waste of space.
Lukas Stockner added the
Module
Render & Cycles
label 2024-02-20 03:28:50 +01:00
Lukas Stockner added 1 commit 2024-02-20 03:28:57 +01:00
Member

The "Volume Stack Priority" name doesn't seem right for this setting considering it handles Volume priority and nested dielectic priority. Although I can't think of a better name at the moment.

Sorry for "reviewing" minor features while you probably want feedback on the more important stuff.

The "Volume Stack Priority" name doesn't seem right for this setting considering it handles Volume priority and nested dielectic priority. Although I can't think of a better name at the moment. Sorry for "reviewing" minor features while you probably want feedback on the more important stuff.
  • Currently surface hits are only masked/skipped for Glass and Principled BSDF. In theory, we could enable this for all surface shaders, but that might be unexpected. Alternatively, we could expose "current/next priority" as inputs for shaders, so advanced users can build custom stuff (we need to expose them for OSL anyways).

I see that for many renderers this is an option on the BSDF / volume shader node, rather than the material. Do you know if there is a use case where you'd want different priority for different shader nodes in a single material? From a UI point of view it seems fine to have it per shader node, though I don't don't if there are potential implementation difficulties.

I'm not entirely sure what you mean by "current/next" priority, I thought that if we do it on shader nodes it would just be a single priority input?

  • If we don't want to block all surface shading, the Principled BSDF code should be changed to only replace the transmission component with transparency.

I'm not sure what this means, can you explain it more?

  • The Principled BSDF only accounts for the opposite IOR for transmission, things like coat/specular still assume air. I think this is fine though, the opposite might be confusing/unexpected.

It seems fine to me.

> - Currently surface hits are only masked/skipped for Glass and Principled BSDF. In theory, we could enable this for all surface shaders, but that might be unexpected. Alternatively, we could expose "current/next priority" as inputs for shaders, so advanced users can build custom stuff (we need to expose them for OSL anyways). I see that for many renderers this is an option on the BSDF / volume shader node, rather than the material. Do you know if there is a use case where you'd want different priority for different shader nodes in a single material? From a UI point of view it seems fine to have it per shader node, though I don't don't if there are potential implementation difficulties. I'm not entirely sure what you mean by "current/next" priority, I thought that if we do it on shader nodes it would just be a single priority input? > - If we don't want to block all surface shading, the Principled BSDF code should be changed to only replace the transmission component with transparency. I'm not sure what this means, can you explain it more? > - The Principled BSDF only accounts for the opposite IOR for transmission, things like coat/specular still assume air. I think this is fine though, the opposite might be confusing/unexpected. It seems fine to me.

In the meeting, we decided to make priority an object level property, same as for example Renderman. We did not see a good reason to have it at shader node level, and it seems convenient to be able to change this for objects that share the same material.

In the meeting, we decided to make priority an object level property, same as for example Renderman. We did not see a good reason to have it at shader node level, and it seems convenient to be able to change this for objects that share the same material.
First-time contributor

Hello guys!

As a user with an experience in Maxwell Render I'd like to have this feature implemented in a material output node or as material-wise option like it's done in Maxwell. For example it is useful in the case when you have a lot of objects sharing same material which should have the priority. In Maxwell the default priority is 0 and it's the highest priority. So when you create the glass and assign new material, it already has the highest priority. The only need to create some other priority occurs when you add some fluid/droplets geometry and/or mix of fluids/ice/etc. Used only for transparent rays, I suppose.

It would be also a great addition if there was some option (turned on by default) in the material to be able to tick on/off render-wise boolean merging for the objects that are sharing the same transparent material. So if we have different overlapping objects (or maybe even the same or additional one with self-overlapping geometry) to avoid mess with same material overlapping geometry artifacts when needed.

Also there could be object-level priority left for more flexible setup in specific cases as described above (derived from Renderman). In this case I suppose it could work at render time as nested object priority list inside the parent material priority instance in material priority list.

So long story short: everybody could choose between the two concepts or combine them depending on personal experience and taste.

I'm not a coder while somewhat familiar with basics of programming. But I suppose I was clear, and I think that would be very cool functionality. So is that possible, how do you think?

Hello guys! As a user with an experience in Maxwell Render I'd like to have this feature implemented in a material output node or as material-wise option like it's done in Maxwell. For example it is useful in the case when you have a lot of objects sharing same material which should have the priority. In Maxwell the default priority is 0 and it's the highest priority. So when you create the glass and assign new material, it already has the highest priority. The only need to create some other priority occurs when you add some fluid/droplets geometry and/or mix of fluids/ice/etc. Used only for transparent rays, I suppose. It would be also a great addition if there was some option (turned on by default) in the material to be able to tick on/off render-wise boolean merging for the objects that are sharing the same transparent material. So if we have different overlapping objects (or maybe even the same or additional one with self-overlapping geometry) to avoid mess with same material overlapping geometry artifacts when needed. Also there could be object-level priority left for more flexible setup in specific cases as described above (derived from Renderman). In this case I suppose it could work at render time as nested object priority list inside the parent material priority instance in material priority list. So long story short: everybody could choose between the two concepts or combine them depending on personal experience and taste. I'm not a coder while somewhat familiar with basics of programming. But I suppose I was clear, and I think that would be very cool functionality. So is that possible, how do you think?
First-time contributor

It might make sense to offer the same options as what cryptomattes do, just for flexibility? I.e. on an Object level, a Material level, and an Asset level. Maybe also a Collection level?
Although it might not be super clear how to handle that in the GUI in a way that makes clear what takes precedent in any given situation.
Certainly, if you were to build some complicated object through Geometry Nodes, you'd want to set that there procedurally too.

It might make sense to offer the same options as what cryptomattes do, just for flexibility? I.e. on an Object level, a Material level, and an Asset level. Maybe also a Collection level? Although it might not be super clear how to handle that in the GUI in a way that makes clear what takes precedent in any given situation. Certainly, if you were to build some complicated object through Geometry Nodes, you'd want to set that there procedurally too.

I would also like to point out that even if it might be tricky for EEVEE to support this, this is not impossible (at least for the volume absorption). So I would make it sure to implement the settings on the blender side.

I would also like to point out that even if it might be tricky for EEVEE to support this, this is not impossible (at least for the volume absorption). So I would make it sure to implement the settings on the blender side.
Contributor

I'm not clear why the default of 0 has to behave differently than any specific value. An old scene will have all objects at the default priority so how these interact with objects at other priorities is irrelevent.

As noted by Artistus it does seem like the default should be the highest priority, so adding a new object will produce a visible result even if it is imbedded in an existing object that has a priority. This can be done by making the numbers backwards, so 0 is highest, by making the default a large number, or by making 0 be higher priority than any non-zero number.

I'm not clear why the default of 0 has to behave differently than any specific value. An old scene will have all objects at the default priority so how these interact with objects at other priorities is irrelevent. As noted by Artistus it does seem like the default should be the highest priority, so adding a new object will produce a visible result even if it is imbedded in an existing object that has a priority. This can be done by making the numbers backwards, so 0 is highest, by making the default a large number, or by making 0 be higher priority than any non-zero number.
This pull request has changes conflicting with the target branch.
  • intern/cycles/kernel/types.h

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u volume-stack-priority:LukasStockner-volume-stack-priority
git checkout LukasStockner-volume-stack-priority
Sign in to join this conversation.
No reviewers
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
7 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#118478
No description provided.