Source/Objects/Volume

= Volume Object =

The volume object is aimed at smoke simulation, procedural volume generation with modifiers, and importing OpenVDB files from other applications.


 * #73201 on projects.blender.org

Data Structures

 * `Object` can be of type `OB_VOLUME`, and then uses a `Volume` datablock as object data.
 * `Volume` is datablock that contains a list of volume grids. These grids may either come from a file, or be procedurally generated by a modifier.
 * `VolumeGrid` contains one OpenVDB grid. For details on this data structure, see the OpenVDB documentation.

OpenVDB grids consist of:
 * Metadata: name and other fields.
 * Transform: linear (or perspective) transform from voxel index to object space.
 * Tree: a tree data structure of nodes, with leaf nodes that contain a grid of 8x8x8 voxels.

File Loading
`Volume` datablocks have a filepath, and if set the volume will be loaded from that file. The list of grids and their contents is loaded on-demand, on modifier evaluation, drawing, user interface or when Python code needs it.


 * `BKE_volume_load` loads the list of grids and their name, metadata and transform.
 * `BKE_volume_grid_load` loads the grid tree and voxels into memory.

To share grid memory between original and CoW datablocks, and between volume datablocks using the same filepath, the grid memory is managed by a global volume file cache. Only grids loaded from file are in this cache, procedurally generated grids are not. When the number of users of a grid in the cache drops to zero, it is immediately freed.

Different volume datablocks may need either only the list of grids and their metadata, or the actual grid tree. This is accounted for in the global volume cache, with a distinction between metadata users and tree users. If the number of tree users drops to zero, the grid tree is freed while its metadata may still remain in memory for metadata users.

Modifiers and Nodes
Volume modifiers and nodes may take a `Volume` as input and output a new `Volume`. The input volume should be considered read-only. The modifier or node can either create a new `Volume` with no grids, or make a copy of an existing `Volume` for editing.

To access the actual OpenVDB grid and its contents, one of the following functions must be used:
 * `BKE_volume_grid_openvdb_for_metadata`: for reading metadata and transform only.
 * `BKE_volume_grid_openvdb_for_read`: for reading only, ensures grid tree is loaded into memory.
 * `BKE_volume_grid_openvdb_for_write`: for read and write, ensures grid tree is loaded into memory and writable.

Volume datablocks use a copy-on-write system. When a copy of a volume datablock is made, both the original and new datablock will reference the same grid in memory. Only when calling `BKE_volume_grid_openvdb_for_write` will a deep copy of the grid be made.

Together with the file cache, the copy-on-write system helps to ensure that the same grid is not duplicated in memory, even when the dependency graph and modifier stack make copies of volume datablocks.

Modifiers and nodes must be implemented in C++, since OpenVDB grids are a C++ data structure.

Rendering
In Cycles, the OpenVDB data structure is converted to NanoVDB, which is then used for rendering. A bounding mesh is built to determine when a ray is inside or outside a volume, and the NanoVDB tree is used for sampling.

Eevee and workbench render volumes as a dense 3D texture. This is to be optimized.

Grid Names
Modifiers, nodes and shaders expect the following grid names by default, which matches conventions in some other apps:
 * `density`: volume density
 * `temperature`: for fire simulations, temperature with unit Kelvin/1000
 * `velocity`: for motion blur, 3D velocity vector