-
Notifications
You must be signed in to change notification settings - Fork 22
added a simple program to export files in .vdb format #148
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: master
Are you sure you want to change the base?
Changes from all commits
22a5995
c871534
d809198
242edb5
79c96de
0649210
f83f709
09b88a3
3c93f8d
1765ae1
31831cb
c55366b
ea446d7
1e2fd80
145a1dd
4bd1d8a
d010391
c8e643d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| .. automodule:: gridData.OpenVDb | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,219 @@ | ||
| r""" | ||
| :mod:`~gridData.OpenVDB` --- routines to write OpenVDB files | ||
| ============================================================= | ||
|
|
||
| The `OpenVDB format`_ is used by Blender_ and other VFX software for | ||
| volumetric data. | ||
|
|
||
| .. _`OpenVDB format`: https://www.openvdb.org | ||
| .. _Blender: https://www.blender.org/ | ||
|
|
||
| This module uses the openvdb_ library to write OpenVDB files. | ||
|
|
||
| .. _openvdb: https://github.com/AcademySoftwareFoundation/openvdb | ||
|
|
||
| .. Note:: This module implements a simple writer for 3D regular grids, | ||
| sufficient to export density data for visualization in Blender_. | ||
| See the `Blender volume docs`_ for details on importing VDB files. | ||
|
|
||
| .. _`Blender volume docs`: https://docs.blender.org/manual/en/latest/modeling/volumes/introduction.html | ||
|
|
||
| The OpenVDB format uses a sparse tree structure to efficiently store | ||
| volumetric data. It is the native format for Blender's volume system. | ||
|
|
||
|
|
||
| Writing OpenVDB files | ||
| --------------------- | ||
|
|
||
| If you have a :class:`~gridData.core.Grid` object, you can write it to | ||
| OpenVDB format:: | ||
|
|
||
| from gridData import Grid | ||
| g = Grid("data.dx") | ||
| g.export("data.vdb") | ||
|
|
||
| This will create a file that can be imported directly into Blender | ||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| (File -> Import -> OpenVDB) or (shift+A -> Volume -> Import OpenVDB). See `importing VDB in Blender`_ for details. | ||
|
|
||
| .. _`importing VDB in Blender`: https://docs.blender.org/manual/en/latest/modeling/geometry_nodes/input/import/vdb.html | ||
|
|
||
|
|
||
| Building an OpenVDB field from a numpy array | ||
| --------------------------------------------- | ||
|
|
||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| If you want to create VDB files without using the Grid class, | ||
| you can directly use the OpenVDB field API. This is useful | ||
| for custom workflows or when integrating with other libraries. | ||
|
|
||
| Requires: | ||
|
|
||
| grid | ||
| numpy 3D array | ||
| origin | ||
| cartesian coordinates of the center of the (0,0,0) grid cell | ||
| delta | ||
| n x n array with the length of a grid cell along each axis | ||
spyke7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Example:: | ||
|
|
||
| import OpenVDB | ||
| vdb_field = OpenVDB.field('density') | ||
| vdb_field.populate(grid, origin, delta) | ||
| vdb_field.write('output.vdb') | ||
|
|
||
|
|
||
| Classes and functions | ||
| --------------------- | ||
|
|
||
| """ | ||
|
|
||
| import numpy | ||
|
|
||
| try: | ||
| import openvdb as vdb | ||
|
|
||
| except ImportError: | ||
| vdb = None | ||
|
|
||
|
|
||
| class OpenVDBField(object): | ||
| """OpenVDB field object for writing volumetric data. | ||
|
|
||
| This class provides a simple interface to write 3D grid data to | ||
| OpenVDB format, which can be imported into Blender and other | ||
| VFX software. | ||
|
|
||
| The field object holds grid data and metadata, and can write it | ||
| to a .vdb file. | ||
|
|
||
| Example | ||
| ------- | ||
| Create a field and write it:: | ||
|
|
||
| vdb_field = OpenVDB.field('density') | ||
| vdb_field.populate(grid, origin, delta) | ||
| vdb_field.write('output.vdb') | ||
|
|
||
| Or use directly from Grid:: | ||
|
|
||
| g = Grid(...) | ||
| g.export('output.vdb', format='vdb') | ||
|
|
||
| """ | ||
|
|
||
| def __init__(self, grid, origin, delta, name='density', tolerance=1e-10): | ||
| """Initialize an OpenVDB field. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| grid : numpy.ndarray | ||
| 3D numpy array with the data | ||
| origin : numpy.ndarray | ||
| Coordinates of the center of grid cell [0,0,0] | ||
| delta : numpy.ndarray | ||
| Grid spacing (can be 1D array or diagonal matrix) | ||
| name : str | ||
| Name of the grid (will be visible in Blender), default 'density' | ||
| threshold : float | ||
| Values below this threshold are treated as background (sparse), | ||
| default 1e-10 | ||
|
|
||
| Raises | ||
| ------ | ||
| ImportError | ||
| If openvdb is not installed | ||
| ValueError | ||
| If grid is not 3D, or if delta is not 1D/2D or describes | ||
| non-orthorhombic cell | ||
|
|
||
| """ | ||
| if vdb is None: | ||
| raise ImportError( | ||
| "openvdb is required to write VDB files. " | ||
| "Install it with: conda install -c conda-forge openvdb" | ||
| ) | ||
| self.name = name | ||
| self.tolerance = tolerance | ||
| self._populate(grid, origin, delta) | ||
|
|
||
| def _populate(self, grid, origin, delta): | ||
| """Populate the field with grid data. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| grid : numpy.ndarray | ||
| 3D numpy array with the data | ||
| origin : numpy.ndarray | ||
| Coordinates of the center of grid cell [0,0,0] | ||
| delta : numpy.ndarray | ||
| Grid spacing (can be 1D array or diagonal matrix) | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
| If grid is not 3D, or if delta is not 1D/2D or describes | ||
| non-orthorhombic cell | ||
|
|
||
| """ | ||
| grid = numpy.asarray(grid) | ||
| if grid.ndim != 3: | ||
| raise ValueError( | ||
| f"OpenVDB only supports 3D grids, got {grid.ndim}D") | ||
|
|
||
| self.grid = grid.astype(numpy.float32) | ||
| self.grid=numpy.ascontiguousarray(self.grid, dtype=numpy.float32) | ||
|
|
||
| self.origin = numpy.asarray(origin) | ||
|
|
||
| # Handle delta: could be 1D array or diagonal matrix | ||
| delta = numpy.asarray(delta) | ||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if delta.ndim == 2: | ||
| if (delta.shape != (3,3)): | ||
| raise ValueError("delta as a matrix must be 3x3") | ||
|
|
||
| if not numpy.allclose(delta, numpy.diag(numpy.diag(delta))): | ||
| raise ValueError("Non-orthorhombic cells are not supported") | ||
|
|
||
| self.delta = numpy.diag(delta) | ||
|
|
||
| elif delta.ndim == 1: | ||
| if (len(delta) != 3): | ||
| raise ValueError("delta must have length-3 for 3D grids") | ||
| self.delta=delta | ||
|
|
||
| else: | ||
| raise ValueError( | ||
| "delta must be either a length-3 vector or a 3x3 diagonal matrix" | ||
| ) | ||
|
|
||
| def write(self, filename): | ||
| """Write the field to an OpenVDB file. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| filename : str | ||
| Output filename (should end in .vdb) | ||
|
|
||
| """ | ||
|
|
||
| vdb_grid = vdb.FloatGrid() | ||
| vdb_grid.name = self.name | ||
|
|
||
| # this is an explicit linear transform using per-axis voxel sizes | ||
| # world = diag(delta) * index + corner_origin | ||
| corner_origin = (self.origin - 0.5 * self.delta) | ||
|
|
||
| matrix = [ | ||
| [self.delta[0], 0.0, 0.0, 0.0], | ||
| [0.0, self.delta[1], 0.0, 0.0], | ||
| [0.0, 0.0, self.delta[2], 0.0], | ||
| [corner_origin[0], corner_origin[1], corner_origin[2], 1.0] | ||
| ] | ||
|
|
||
| vdb_grid.background = 0.0 | ||
| vdb_grid.transform = vdb.createLinearTransform(matrix) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume that the transformation is required to make the VDB grid to have the correct origin and delta in general. Or is this something specific to the MN blender use, @PardhavMaradani ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I addressed this in the comment below. Thanks |
||
|
|
||
| vdb_grid.copyFromArray(self.grid, tolerance=self.tolerance) | ||
| vdb_grid.prune() | ||
|
|
||
| vdb.write(filename, grids=[vdb_grid]) | ||
Uh oh!
There was an error while loading. Please reload this page.