How to deal with multiple volume grids in a geometry #91668

Open
opened 2021-09-24 07:34:13 +02:00 by Hans Goudey · 17 comments
Member

This task is for figuring out whether to map the idea of attribute grids to the attribute concept, and if so, how to do it.

Here's some background I wrote about in chat:

One of the level set nodes we could implement is a fracture node that splits up one level set into many pieces based on some other surface. The output is an arbitrary number of grids.
For meshes this is easy-- just have multiple "islands" in the mesh! But here we cannot just combine the grids. Theoretically each grid could be stored in a separate instance on the geometry, but they are not really instances, so that's a hack.
I think you shouldn't have to choose grid output names in this case, and if you pass it to another node it would just operate on whatever grids were part of the volume. Very quick, and not complicated!
On the other hand, a major use case for multiple grids is when they basically share the same topology but encode different information, like heat, pressure, velocity, etc.
In that case you really want to be able to choose a grid when generating points, or easily split the density grid from the volume. Both are fine I think, splitting is a more general solution.
In the first case, grids don't correspond to attributes at all, they're just a bunch of different shapes, e.g. cloud puffs or surfaces, etc.
In the second, they align well to attributes, except that there is no "main" attribute like position, unless that is the density grid

In D12100 I implemented volume to mesh transfer for all grids in a volume, and "Distribute Points in Volume" will have the same decision.

Below are a few different methods that I've been thinking about:

All Grids

{F11707663 size=full}

  • Volume nodes use all grids implicitly
  • There may be many grids that refer to the idea of "density", whether or not they all have the same name
  • In order to be used in operations, grids do not have to be merged. This is huge improvement for performance
  • The join geometry node does not merge grids, the volume boolean node does that in union mode
  • Volume nodes can function without a grid selection or input
  • A "Split Volume" node is the main method of working on a subset of grids

Pros

  • Nodes that operate on grids tend to become much simpler, because the grids don't have to be manually selected.
  • Better performance, since grids don't have to be merged

Cons

  • Less visual interaction with grids and grid types
  • Not clear how math operations will be done on grid values (maybe an attribute-processor-like approach?)

Named Grids

Currently I don't think this option is very compelling, I just included it for the sake of completion.

  • Volume nodes only work on a single grid at a time
  • The grid choice is specified by a name
  • This is what we had before.
  • There is a conceptual distinction between fields and volume grids
  • Working with volumes is significantly slower due to the need to type names in nodes

Pros

  • Compared to the anonymous grid system, no need for every node to have the options necessary for creating new grids

Cons

  • The downsides of the anonymous grid system without any of its benefits, except explicitly accessing a single grid

Anonymous Grids

{F11707672 size=full}

  • Volume nodes only work on a single grid (though possibly merging could be done lazily as an optimization?)
  • Grid inputs are specified by a field input
  • Volume nodes output grids with the same method as anonymous attributes
  • Math nodes can be used on the sockets used to pass fields around (otherwise it's misleading to use fields)
  • Many nodes need more options to make this possible, because any node can make a new grid, including data type and resolution options
  • Every volume node must support the ability to create a new grid with a field input, complicating code greatly

Pros

  • The path forward for math operations on grids is much clearer

Cons

  • Lots of noodles to connect, even for simple operations
  • UX is much more different than what is happening internally
  • Very easy to do surprisingly expensive operations like use geometry proximity to build a grid, when the other methods force more performant solutions.
  • Much more complicated to develop, since it encompasses generic math operations on grids
This task is for figuring out whether to map the idea of attribute grids to the attribute concept, and if so, how to do it. Here's some background I wrote about in chat: >One of the level set nodes we could implement is a fracture node that splits up one level set into many pieces based on some other surface. The output is an arbitrary number of grids. >For meshes this is easy-- just have multiple "islands" in the mesh! But here we cannot just combine the grids. Theoretically each grid could be stored in a separate instance on the geometry, but they are not really instances, so that's a hack. >I think you shouldn't have to choose grid output names in this case, and if you pass it to another node it would just operate on whatever grids were part of the volume. Very quick, and not complicated! >On the other hand, a major use case for multiple grids is when they basically share the same topology but encode different information, like heat, pressure, velocity, etc. >In that case you really want to be able to choose a grid when generating points, or easily split the density grid from the volume. Both are fine I think, splitting is a more general solution. >**In the first case, grids don't correspond to attributes at all, they're just a bunch of different shapes, e.g. cloud puffs or surfaces, etc.** >**In the second, they align well to attributes, except that there is no "main" attribute like position, unless that is the density grid** In [D12100](https://archive.blender.org/developer/D12100) I implemented volume to mesh transfer for all grids in a volume, and "Distribute Points in Volume" will have the same decision. Below are a few different methods that I've been thinking about: ### All Grids {[F11707663](https://archive.blender.org/developer/F11707663/image.png) size=full} - Volume nodes use all grids implicitly - There may be many grids that refer to the idea of "density", whether or not they all have the same name - In order to be used in operations, grids do not have to be merged. This is huge improvement for performance - The join geometry node does not merge grids, the volume boolean node does that in union mode - Volume nodes can function without a grid selection or input - A "Split Volume" node is the main method of working on a subset of grids **Pros** - Nodes that operate on grids tend to become much simpler, because the grids don't have to be manually selected. - Better performance, since grids don't have to be merged **Cons** - Less visual interaction with grids and grid types - Not clear how math operations will be done on grid values (maybe an attribute-processor-like approach?) ### Named Grids *Currently I don't think this option is very compelling, I just included it for the sake of completion.* - Volume nodes only work on a single grid at a time - The grid choice is specified by a name - This is what we had before. - There is a conceptual distinction between fields and volume grids - Working with volumes is significantly slower due to the need to type names in nodes **Pros** - Compared to the anonymous grid system, no need for every node to have the options necessary for creating new grids **Cons** - The downsides of the anonymous grid system without any of its benefits, except explicitly accessing a single grid ### Anonymous Grids {[F11707672](https://archive.blender.org/developer/F11707672/image.png) size=full} - Volume nodes only work on a single grid (though possibly merging could be done lazily as an optimization?) - Grid inputs are specified by a field input - Volume nodes output grids with the same method as anonymous attributes - Math nodes can be used on the sockets used to pass fields around (otherwise it's misleading to use fields) - Many nodes need more options to make this possible, because any node can make a new grid, including data type and resolution options - Every volume node must support the ability to create a new grid with a field input, complicating code greatly **Pros** - The path forward for math operations on grids is much clearer **Cons** - Lots of noodles to connect, even for simple operations - UX is much more different than what is happening internally - Very easy to do surprisingly expensive operations like use geometry proximity to build a grid, when the other methods force more performant solutions. - Much more complicated to develop, since it encompasses generic math operations on grids
Author
Member

Changed status from 'Needs Triage' to: 'Confirmed'

Changed status from 'Needs Triage' to: 'Confirmed'
Author
Member

Added subscriber: @HooglyBoogly

Added subscriber: @HooglyBoogly
Author
Member

I think with 8ddfdfd2b2 we have settled on the approach of using all grids in most nodes, and adding something like a "Separate Volume Grids" node to allow only holding a subset of grids in a geometry.

I think with 8ddfdfd2b2 we have settled on the approach of using all grids in most nodes, and adding something like a "Separate Volume Grids" node to allow only holding a subset of grids in a geometry.
Member

Changed status from 'Confirmed' to: 'Resolved'

Changed status from 'Confirmed' to: 'Resolved'
Jacques Lucke self-assigned this 2021-10-27 17:36:55 +02:00
Author
Member

Changed status from 'Resolved' to: 'Confirmed'

Changed status from 'Resolved' to: 'Confirmed'
Jacques Lucke was unassigned by Hans Goudey 2021-11-03 04:16:18 +01:00
Author
Member

Added subscriber: @JacquesLucke

Added subscriber: @JacquesLucke

Added subscriber: @GeorgiaPacific

Added subscriber: @GeorgiaPacific

Added subscriber: @brecht

Added subscriber: @brecht

Attributes

I think integrating with fields / anonymous grids in some way makes sense, to have a consistent user experience with other types of geometry.

The equivalent of a mesh attribute to me seems to be one or more grids with the same name. We could name the attributes in the UI also for consistency, and when an attribute consists of multiple grids also communicate that in the properties editor / spreadsheet.

Looking at the nodes in the screenshots, I would expect Advect Volume or Fracture Volume to work on all grids, no need for field sockets. To me that's like a deforming a mesh or booleans, you do it for the entire mesh including attributes. For level sets I'd consider the signed distance a built-in attribute similar to a mesh position. The number of links is then reduced.

Consistent Attribute Domains

For me the tricky thing is what happens when you mix attributes in fields. Often they might just be a single grid with identical transform, in which case it's efficient. If there are multiple grids or attributes with different transforms, then you need to resample them. That's relatively slow, and it's not well defined which of the transform it should use to resample to. The other issue is that you build a field from e.g. purely a procedural texture, that needs to have a resolution and be bounded somehow.

I'm thinking it may be reasonable to add some constraints on grid transforms within a single volume datablock. At least for them to be valid for use in fields. We could require that all attributes must have matching grid transforms. If there are multiple grids in an attribute, each attribute should have the same number of grids with matching transform (at least conceptually, in practice we may not store an empty grid). This way I think field operations are better defined, as there is a clear domain similar to mesh attributes.

If you then use a VDB file that does not follow this constraint, there would be a warning and it would have to be resampled or split into multiple volumes by the user to be usable for fields (and maybe some other volume nodes).

**Attributes** I think integrating with fields / anonymous grids in some way makes sense, to have a consistent user experience with other types of geometry. The equivalent of a mesh attribute to me seems to be one or more grids with the same name. We could name the attributes in the UI also for consistency, and when an attribute consists of multiple grids also communicate that in the properties editor / spreadsheet. Looking at the nodes in the screenshots, I would expect Advect Volume or Fracture Volume to work on all grids, no need for field sockets. To me that's like a deforming a mesh or booleans, you do it for the entire mesh including attributes. For level sets I'd consider the signed distance a built-in attribute similar to a mesh position. The number of links is then reduced. **Consistent Attribute Domains** For me the tricky thing is what happens when you mix attributes in fields. Often they might just be a single grid with identical transform, in which case it's efficient. If there are multiple grids or attributes with different transforms, then you need to resample them. That's relatively slow, and it's not well defined which of the transform it should use to resample to. The other issue is that you build a field from e.g. purely a procedural texture, that needs to have a resolution and be bounded somehow. I'm thinking it may be reasonable to add some constraints on grid transforms within a single volume datablock. At least for them to be valid for use in fields. We could require that all attributes must have matching grid transforms. If there are multiple grids in an attribute, each attribute should have the same number of grids with matching transform (at least conceptually, in practice we may not store an empty grid). This way I think field operations are better defined, as there is a clear domain similar to mesh attributes. If you then use a VDB file that does not follow this constraint, there would be a warning and it would have to be resampled or split into multiple volumes by the user to be usable for fields (and maybe some other volume nodes).

Added subscriber: @Diogo_Valadares

Added subscriber: @Diogo_Valadares
Author
Member

Here are some more mockups where I've attempted to take Brecht's feedback into account.

Builtin attributes

{F13014945 size=full}

Density and level set distance / signed distance are treated like builtin attributes.
This means that each have their own get and set nodes which can be used to change the values.
However, the "set" nodes do not alter topology, meaning they're only really useful for smaller tweaks.
It's not totally clear that it makes sense to change the distance grids like this at all.

Multiple grids with the same identifier

{F13015009 size=full}

The equivalent of a mesh attribute is one or more grids with the same name. Using multiple grids
to represent a single attribute is very important for performance reasons because merging grids
is slow and should be avoided where possible.

Above is an example of a node that by definition outputs multiple multiple grids. However,
every output grid represents the same "distance" concept that the input grid does. Using the
same name for all of them avoids complexity (e.g. assigning names like "density.001" density.002", etc.).

Accessing specific grids

{F13014996 size=full}

There are two ways to access data from specific grids.

  • Any named grid can be accessed with the named attribute node.
  • References to anonymous grids can be passed around just like anonymous attributes (they are the same thing).

Since creating a grid from scratch is inefficient, volume nodes can detect when a field input
references a grid directly, and avoid the entire field evaluation process.

Regular "tool" nodes

{F13015004 size=full}

Many (most?) nodes don't have to worry about selecting specific grids to operate on,
they can simply modify all grids in the volume data-block. This makes them easy to interact
with as high-level building blocks, because users can think of the volume as one item
rather than as a collection of grids/attributes-- just like a meshes or curves.

Accessing/adding/modifying grids

{F13015000 size=full}

When adding another grid to a volume, the nodes get to choose what topology to use when
creating it. For example, creating a new grid from scratch (no grid dependencies in the input field),
the node would use the topology of an existing grid in the volume. When creating a grid based
on an existing grid (i.e. a named attribute input), the input grid's topology might be unchanged.

If an input grid has a different transform than an existing grid on the volume than it also has to
be resampled to match the transform of existing grids.

Creating volumes from scratch

{F13014954 size=full}

I expect most volumes will be created by simulations or by converting from meshes or points,
but it seems reasonable to allow creating a volume from scratch. Conceptually this node would
create a dense volume and then make it sparse where possible, though there may be various
ways to optimize this to avoid a complete dense evaluation of the input field.

Conclusion

Overall I'm actually quite happy with how this is looking, it seems much more intuitive than
I expected. However, eventually I think we will be forced to add some less elegant aspects to the design
for performance reasons. One example is the efficiently stored "active states " that represent something
like a builtin selection attribute, which we've avoided doing so far. Things like that will be more appetizing
on a UI level once we get things like hidden sockets or subpanels on nodes.

Here are some more mockups where I've attempted to take Brecht's feedback into account. **Builtin attributes** {[F13014945](https://archive.blender.org/developer/F13014945/image.png) size=full} Density and level set distance / signed distance are treated like builtin attributes. This means that each have their own get and set nodes which can be used to change the values. However, the "set" nodes **do not alter topology**, meaning they're only really useful for smaller tweaks. It's not totally clear that it makes sense to change the distance grids like this at all. **Multiple grids with the same identifier** {[F13015009](https://archive.blender.org/developer/F13015009/image.png) size=full} The equivalent of a mesh attribute is one or more grids with the same name. Using multiple grids to represent a single attribute is very important for performance reasons because merging grids is slow and should be avoided where possible. Above is an example of a node that by definition outputs multiple multiple grids. However, every output grid represents the same "distance" concept that the input grid does. Using the same name for all of them avoids complexity (e.g. assigning names like "density.001" density.002", etc.). **Accessing specific grids** {[F13014996](https://archive.blender.org/developer/F13014996/image.png) size=full} There are two ways to access data from specific grids. - Any named grid can be accessed with the named attribute node. - References to anonymous grids can be passed around just like anonymous attributes (they are the same thing). Since creating a grid from scratch is inefficient, volume nodes can detect when a field input references a grid directly, and avoid the entire field evaluation process. **Regular "tool" nodes** {[F13015004](https://archive.blender.org/developer/F13015004/image.png) size=full} Many (most?) nodes don't have to worry about selecting specific grids to operate on, they can simply modify all grids in the volume data-block. This makes them easy to interact with as high-level building blocks, because users can think of the volume as one item rather than as a collection of grids/attributes-- just like a meshes or curves. **Accessing/adding/modifying grids** {[F13015000](https://archive.blender.org/developer/F13015000/image.png) size=full} When adding another grid to a volume, the nodes get to choose what topology to use when creating it. For example, creating a new grid from scratch (no grid dependencies in the input field), the node would use the topology of an existing grid in the volume. When creating a grid based on an existing grid (i.e. a named attribute input), the input grid's topology might be unchanged. If an input grid has a different transform than an existing grid on the volume than it also has to be resampled to match the transform of existing grids. **Creating volumes from scratch** {[F13014954](https://archive.blender.org/developer/F13014954/image.png) size=full} I expect most volumes will be created by simulations or by converting from meshes or points, but it seems reasonable to allow creating a volume from scratch. Conceptually this node would create a dense volume and then make it sparse where possible, though there may be various ways to optimize this to avoid a complete dense evaluation of the input field. ### Conclusion Overall I'm actually quite happy with how this is looking, it seems much more intuitive than I expected. However, eventually I think we will be forced to add some less elegant aspects to the design for performance reasons. One example is the efficiently stored "[active states ](https://www.openvdb.org/documentation/doxygen/faq.html#sState)" that represent something like a builtin selection attribute, which we've avoided doing so far. Things like that will be more appetizing on a UI level once we get things like hidden sockets or subpanels on nodes.

Added subscriber: @Robonnet

Added subscriber: @Robonnet
Member

Density and level set distance / signed distance are treated like builtin attributes.

I can see that the level set distance as built-in attribute makes sense. I'm not so sure about density. It seems quite reasonable to have volumetric data without a density (e.g. just a velocity field).
Not having a built-in density attribute opens up some compatibility questions for existing files of course, but I think that can be solved like so:

  • Output anonymous density attribute from Points to Volume node.
  • With versioning, add a store named attribute after the Points to Volume node to "rename" the anonymous attribute to density.
  • In the Volume to Mesh node, have an enum with two options: "All Scalar Grids" and "Field" (other names work as well of course).
  • The "All Scalar Grids" mode is equivalent to the old behavior. The "Field" mode would be the new default. In this mode the node has a "Density" field input.

This means that each have their own get and set nodes which can be used to change the values.

Do you have an example for how those nodes would be used in practice? Maybe those nodes are just not needed for now.

Using multiple grids to represent a single attribute is very important for performance reasons because merging grids is slow and should be avoided where possible.

Do you have an example for when multiple grids would be used for a single attribute?

  • When the density attribute is not built-in, the Set Density node is gone anyway.
  • If the Set Signed Distance node can't change topology, it probably can't do much, because the level set is roughly encoded in the topology.

Fracture Level Set, Level Set to Mask [Images]

What do these nodes do exactly?

the node would use the topology of an existing grid in the volume

Do you have an idea for a heuristic already for how to choose the topology? Maybe it shouldn't work when there are different topologies, and the user would have to be explicit by passing in a separate "reference field".

If an input grid has a different transform than an existing grid on the volume than it also has to be resampled to match the transform of existing grids.

Any thoughts on how implicit or explicit this resampling should be? Sounds like something the user should be informed about in one way or another.

> Density and level set distance / signed distance are treated like builtin attributes. I can see that the `level set distance` as built-in attribute makes sense. I'm not so sure about `density`. It seems quite reasonable to have volumetric data without a density (e.g. just a velocity field). Not having a built-in `density` attribute opens up some compatibility questions for existing files of course, but I think that can be solved like so: * Output anonymous density attribute from `Points to Volume` node. * With versioning, add a store named attribute after the Points to Volume node to "rename" the anonymous attribute to `density`. * In the Volume to Mesh node, have an enum with two options: "All Scalar Grids" and "Field" (other names work as well of course). * The "All Scalar Grids" mode is equivalent to the old behavior. The "Field" mode would be the new default. In this mode the node has a "Density" field input. > This means that each have their own get and set nodes which can be used to change the values. Do you have an example for how those nodes would be used in practice? Maybe those nodes are just not needed for now. > Using multiple grids to represent a single attribute is very important for performance reasons because merging grids is slow and should be avoided where possible. Do you have an example for when multiple grids would be used for a single attribute? * When the density attribute is not built-in, the Set Density node is gone anyway. * If the Set Signed Distance node can't change topology, it probably can't do much, because the level set is roughly encoded in the topology. > Fracture Level Set, Level Set to Mask [Images] What do these nodes do exactly? > the node would use the topology of an existing grid in the volume Do you have an idea for a heuristic already for how to choose the topology? Maybe it shouldn't work when there are different topologies, and the user would have to be explicit by passing in a separate "reference field". > If an input grid has a different transform than an existing grid on the volume than it also has to be resampled to match the transform of existing grids. Any thoughts on how implicit or explicit this resampling should be? Sounds like something the user should be informed about in one way or another.

For naming, in devtalk discussion there was an argument that "SDF" is a more common term than "Level Set" in 3D apps. I think it would make some sense to use "SDF" instead of "Level Set" in node names, and to then have "SDF Volume" and "Fog Volume" socket names where a specific type of volume is expected.

In #91668#1345038, @JacquesLucke wrote:
I can see that the level set distance as built-in attribute makes sense. I'm not so sure about density. It seems quite reasonable to have volumetric data without a density (e.g. just a velocity field).

I agree density does not need to be a built-in attribute to the same degree as level set distance. To me it seems more on a similar level to temperature and velocity, attributes that physics and rendering will recognize, and that may be used as default values in some attribute name fields.

Using multiple grids to represent a single attribute is very important for performance reasons because merging grids is slow and should be avoided where possible.

Do you have an example for when multiple grids would be used for a single attribute?

I think this would happen by default with Join Geometry, so that it's a cheap and well defined operation. And then if you want to resample it all to a single grid, you'd have a node for that (similar to Realize Instances) with settings for how the resampling should happen exactly.

I don't know to what extent this is even a standard OpenVDB feature but it is used by Houdini, see for example #86313 (Open VDB Doesn't Playback Clusters Correctly).

Though thinking about this more, I'm not entirely sure multiple grids are that great a solution, if we look at two distinct use cases:

  • Multiple grids can be useful if you want to transform and render multiple individual volumes as instances, without having to resample. However, arguably these should then just be geometry nodes instances.
  • If you want to generate multiple individual volumes and join them together at some point for further processing on voxels, then why wouldn't you generate all volumes with the same (unit) transform in the first place? Because resampling is just going to be more expensive without a clear benefit, and for users it will be a burden to have to understand that they need to do this for some nodes to behave as expected.

So another way to look at this would be, OpenVDB files with clusters could be imported as instances, and for volumes generated internally or single grid OpenVDB files we try to make everything use the same transform. I'm not sure what is best. It's a question of how much we try to adapt to OpenVDB, or try to restrict so things fit nicer in the geometry nodes design.

For naming, in devtalk discussion there was an argument that "SDF" is a more common term than "Level Set" in 3D apps. I think it would make some sense to use "SDF" instead of "Level Set" in node names, and to then have "SDF Volume" and "Fog Volume" socket names where a specific type of volume is expected. > In #91668#1345038, @JacquesLucke wrote: > I can see that the `level set distance` as built-in attribute makes sense. I'm not so sure about `density`. It seems quite reasonable to have volumetric data without a density (e.g. just a velocity field). I agree density does not need to be a built-in attribute to the same degree as level set distance. To me it seems more on a similar level to temperature and velocity, attributes that physics and rendering will recognize, and that may be used as default values in some attribute name fields. >> Using multiple grids to represent a single attribute is very important for performance reasons because merging grids is slow and should be avoided where possible. > > Do you have an example for when multiple grids would be used for a single attribute? I think this would happen by default with Join Geometry, so that it's a cheap and well defined operation. And then if you want to resample it all to a single grid, you'd have a node for that (similar to Realize Instances) with settings for how the resampling should happen exactly. I don't know to what extent this is even a standard OpenVDB feature but it is used by Houdini, see for example #86313 (Open VDB Doesn't Playback Clusters Correctly). Though thinking about this more, I'm not entirely sure multiple grids are that great a solution, if we look at two distinct use cases: * Multiple grids can be useful if you want to transform and render multiple individual volumes as instances, without having to resample. However, arguably these should then just be geometry nodes instances. * If you want to generate multiple individual volumes and join them together at some point for further processing on voxels, then why wouldn't you generate all volumes with the same (unit) transform in the first place? Because resampling is just going to be more expensive without a clear benefit, and for users it will be a burden to have to understand that they need to do this for some nodes to behave as expected. So another way to look at this would be, OpenVDB files with clusters could be imported as instances, and for volumes generated internally or single grid OpenVDB files we try to make everything use the same transform. I'm not sure what is best. It's a question of how much we try to adapt to OpenVDB, or try to restrict so things fit nicer in the geometry nodes design.
Author
Member

Coming back to this topic after some time, here is an adjusted design based on your feedback:

General

  • Volume grids are a subset of attributes conceptually
  • There is a new "Volume Grid" attribute domain
  • Grids can be created from scratch when the topology is specified externally of by an existing grid
  • SDF Volumes are grids that store a distance to an isosurface, also known as level sets
  • Volumes have one builtin SDF distance attribute. Others are generic named attributes or anonymous attributes
  • The volume node workflow makes use of anonymous attribute references for passing references to specific grids
  • All grids on a volume geometry must have the same transform

Creating Volume Grids

Volume grids can be created from scratch with primitives. In this case they have a resolution specified manually.
The SDF sphere volume creates a builtin grid called distance. The volume cube node creates an anonymous grid.
The cube node has a new anonymous attribute output to reference the grid it creates, and a type option to clarify the choice for other nodes and applications.

F13263587 F13263305

Volume grids can also be created by converting from other geometry types. In that case the resolution is specified by the user and the topology specified by the geometry.

F13263551 F13263565 F13263315

New grids can be created on existing volumes, but not from scratch, since the resolution and topology must be specified somehow.
The existing nodes for creating attributes would work in this case, but they need an existing grid to use for the topology.
If there are two existing grids, that introduces an arbitrary choice of topology. Eventually there can be a "reference grid" input that must reference a grid.
In the short term we could just require that there only be one other existing grid, or we could use a heuristic to choose the grid. Choosing the first grid or preferring certain grids may work.

Since we control the creation of volume grids, we ensure that all grids on the same geometry have the same transform.

F13263420 F13263422

Modifying Volumes

The builtin distance grid can be converted to another type, which is outputted as an anonymous attribute.
For example, an SDF volume can be converted to a fog volume or a mask/boolean grid

F13263542 F13263446

Some nodes modify all grids implicitly in-place. Just like meshes, these builtin nodes are often necessary for topology-changing operations.
The Advect Volume node offsets each voxels in a volume by the given translation.
The SDF Volume Filter node corresponds to the "level set filter" OpenVDB tool and applies some topology changing operation to all SDF grids.

F13263448 F13263454

Some nodes deal with multiple volumes, potentially using a subset of the volume grids with some property.
The Volume Boolean node does Union, Intersect, and Difference operations on scalar grids. (This may need anonymous attribute inputs).
The Fracture SDF Volume node uses the builtin SDF distance on a main grid and a "cutter" grid, and creates separate volume instances for each "chunk".
That's a non-obvious API, but it uses the existing geometry nodes instances, and is similar to the existing Curve to Mesh node.

F13263451 F13263456

Using Volumes

The Volume to Mesh node is modified to have a choice between processing "All Scalar Grids" and just a single field (possibly an anonymous attribute).
The "all grids" mode is the default, since that's the current behavior of the node.

F13263593 F13263520

The Sample Volume node uses a field to choose which grid to reference (or evaluate a new one on the volume).
It samples the volume at specific points in space defined by the field evaluation.

F13263523 F13263526

Examples

Here, two SDF volumes are created and the fracture node is used to split one of them in half, forming two unconnected volume instances.
Then the volume to mesh node is used on each instance to convert the volumes to a mesh.
F13263546

Here, an SDF volume is created from points. Then a new grid is created by multiplying that signed distance with a noise texture.
Setting the values in an SDF grid without changing the topology is potentially error-prone, but it should still be possible and may give a useful effect.
F13263576

Further Questions

  • How should the input grids be specified for the Volume Boolean node. Can it use all grids?
  • Do we need a node to split a grid into a separate volume geometry? If so, how would that work?
  • I would imagine the position field input would give the local-space position of each voxel. Does that make sense?

Thoughts

  • Generally I think this is getting to the point where it's worth prototyping.
  • I could imagine some pain points with the process of referencing grids with anonymous attributes, especially for the typical "density" grid which is a very common case.
  • For the implementation, I would probably write the creation of grids from fields on an existing volumes last, and just use fields to pass direct references to grids at first.
  • The existing geometry component field context with virtual arrays could be used at first. Eventually it might be important to specialize a field evaluation system for volume data.

Here is the file I used to create the mockups:
Volume Node Mockups.blend

Coming back to this topic after some time, here is an adjusted design based on your feedback: # General * Volume grids are a subset of attributes conceptually * There is a new "Volume Grid" attribute domain * Grids can be created from scratch when the topology is specified externally of by an existing grid * SDF Volumes are grids that store a distance to an isosurface, also known as level sets * Volumes have one builtin SDF `distance` attribute. Others are generic named attributes or anonymous attributes * The volume node workflow makes use of anonymous attribute references for passing references to specific grids * All grids on a volume geometry must have the same transform # Creating Volume Grids Volume grids can be created from scratch with primitives. In this case they have a resolution specified manually. The SDF sphere volume creates a builtin grid called `distance`. The volume cube node creates an anonymous grid. The cube node has a new anonymous attribute output to reference the grid it creates, and a type option to clarify the choice for other nodes and applications. | ![F13263587](https://archive.blender.org/developer/F13263587/image.png) | ![F13263305](https://archive.blender.org/developer/F13263305/image.png) | | -- | -- | Volume grids can also be created by converting from other geometry types. In that case the resolution is specified by the user and the topology specified by the geometry. | ![F13263551](https://archive.blender.org/developer/F13263551/image.png) | ![F13263565](https://archive.blender.org/developer/F13263565/image.png) | ![F13263315](https://archive.blender.org/developer/F13263315/image.png) | | -- | -- | -- | New grids can be created on existing volumes, but not from scratch, since the resolution and topology must be specified somehow. The existing nodes for creating attributes would work in this case, but they need an existing grid to use for the topology. If there are two existing grids, that introduces an arbitrary choice of topology. Eventually there can be a "reference grid" input that must reference a grid. In the short term we could just require that there only be one other existing grid, or we could use a heuristic to choose the grid. Choosing the first grid or preferring certain grids may work. Since we control the creation of volume grids, we ensure that all grids on the same geometry have the same transform. | ![F13263420](https://archive.blender.org/developer/F13263420/image.png) | ![F13263422](https://archive.blender.org/developer/F13263422/image.png) | | -- | -- | # Modifying Volumes The builtin `distance` grid can be converted to another type, which is outputted as an anonymous attribute. For example, an SDF volume can be converted to a fog volume or a mask/boolean grid | ![F13263542](https://archive.blender.org/developer/F13263542/image.png) | ![F13263446](https://archive.blender.org/developer/F13263446/image.png) | | -- | -- | Some nodes modify all grids implicitly in-place. Just like meshes, these builtin nodes are often necessary for topology-changing operations. The Advect Volume node offsets each voxels in a volume by the given translation. The SDF Volume Filter node corresponds to the "level set filter" OpenVDB tool and applies some topology changing operation to all SDF grids. | ![F13263448](https://archive.blender.org/developer/F13263448/image.png) | ![F13263454](https://archive.blender.org/developer/F13263454/image.png) | | -- | -- | Some nodes deal with multiple volumes, potentially using a subset of the volume grids with some property. The Volume Boolean node does Union, Intersect, and Difference operations on scalar grids. (This may need anonymous attribute inputs). The Fracture SDF Volume node uses the builtin SDF distance on a main grid and a "cutter" grid, and creates separate volume instances for each "chunk". That's a non-obvious API, but it uses the existing geometry nodes instances, and is similar to the existing Curve to Mesh node. | ![F13263451](https://archive.blender.org/developer/F13263451/image.png) | ![F13263456](https://archive.blender.org/developer/F13263456/image.png) | | -- | -- | # Using Volumes The Volume to Mesh node is modified to have a choice between processing "All Scalar Grids" and just a single field (possibly an anonymous attribute). The "all grids" mode is the default, since that's the current behavior of the node. | ![F13263593](https://archive.blender.org/developer/F13263593/image.png) | ![F13263520](https://archive.blender.org/developer/F13263520/image.png) | | -- | -- | The Sample Volume node uses a field to choose which grid to reference (or evaluate a new one on the volume). It samples the volume at specific points in space defined by the field evaluation. | ![F13263523](https://archive.blender.org/developer/F13263523/image.png) | ![F13263526](https://archive.blender.org/developer/F13263526/image.png) | | -- | -- | # Examples Here, two SDF volumes are created and the fracture node is used to split one of them in half, forming two unconnected volume instances. Then the volume to mesh node is used on each instance to convert the volumes to a mesh. ![F13263546](https://archive.blender.org/developer/F13263546/image.png) Here, an SDF volume is created from points. Then a new grid is created by multiplying that signed distance with a noise texture. Setting the values in an SDF grid without changing the topology is potentially error-prone, but it should still be possible and may give a useful effect. ![F13263576](https://archive.blender.org/developer/F13263576/image.png) # Further Questions * How should the input grids be specified for the Volume Boolean node. Can it use all grids? * Do we need a node to split a grid into a separate volume geometry? If so, how would that work? * I would imagine the position field input would give the local-space position of each voxel. Does that make sense? # Thoughts * Generally I think this is getting to the point where it's worth prototyping. * I could imagine some pain points with the process of referencing grids with anonymous attributes, especially for the typical "density" grid which is a very common case. * For the implementation, I would probably write the creation of grids from fields on an existing volumes last, and just use fields to pass direct references to grids at first. * The existing geometry component field context with virtual arrays could be used at first. Eventually it might be important to specialize a field evaluation system for volume data. --- Here is the file I used to create the mockups: [Volume Node Mockups.blend](https://archive.blender.org/developer/F13263598/Volume_Node_Mockups.blend)

Added subscriber: @mod_moder

Added subscriber: @mod_moder
Author
Member

I wrote down the steps I would suggest to implement this design in #103248.
I'm sure this design will have to be tweaked a bit, but generally it seems worth trying, so hopefully some people will have the time to pick it up!
My main concerns are the need to plug in a bunch of extra connections for the grid fields and the unresolved questions about matching up grids for the boolean node.
Those both seems solvable to me though, so I don't think they're blocking.

I wrote down the steps I would suggest to implement this design in #103248. I'm sure this design will have to be tweaked a bit, but generally it seems worth trying, so hopefully some people will have the time to pick it up! My main concerns are the need to plug in a bunch of extra connections for the grid fields and the unresolved questions about matching up grids for the boolean node. Those both seems solvable to me though, so I don't think they're blocking.
Sign in to join this conversation.
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#91668
No description provided.