Wednesday, August 13, 2014

Blender Voxel Data File Format (bvox, 8bit raw)

You can do cool stuff with manual Blender voxel data. See for example this video:
Unfortunately there is not much documentation about the input file formats ".bvox" or 8bit raw. Both are simple structured rectangular grids in which usually 'x' is the fastest and 'z' the slowest dimension.

bvox format

bvox is a very simple binary file that looks like this:
nx ny nz nframes data[1,0,0] data[2,0,0] .... data[nx-1,ny-1,nz-1]
nx,ny,nz,nframes are 32bit integers, data_xyz are 32bit floats between 0 and 1. This is a purely rectangular structured grid which is mapped to the appropriate domain within blender. There are options for spherical and cylindrical mappings, but I have only tried mapping it to a simple cube. Here is an example script that creates a simple 3D texture:
#!/usr/bin/env python
import numpy as np

#specify dimensions header
nx, ny, nz, nframes = 100,100,100,1
header = np.array([nx,ny,nz,nframes])

#create simple distance to origin texture
x = np.linspace(-1,1,nx)
y = np.linspace(-1,1,ny)
z = np.linspace(-1,1,nz)
zz,yy,xx = np.meshgrid(z,y,x,indexing='ij')
pointdata = yy.flatten()**2+zz.flatten()**2+xx.flatten()**2

#open and write to file
binfile = open('test1.bvox','wb')
header.astype('<i4').tofile(binfile)
pointdata.astype('<f4').tofile(binfile)

8bit raw format

This format is even simpler and saves space. It is just a long array of 8bit uints, frame by frame. The dimensions are specified in blender itself.
frame1[1,0,0] frame1[2,0,0] .... frame1[nx-1,ny-1,nz-1] frame2[0,0,0] ...
A test file can be written with:
#!/usr/bin/env python
import numpy as np

nx, ny, nz = 100,100,100

#create simple distance to center texture
x = np.linspace(-1,1,nx)
y = np.linspace(-1,1,ny)
z = np.linspace(-1,1,nz)
zz,yy,xx = np.meshgrid(z,y,x,indexing='ij')
pointdata = yy.flatten()**2+zz.flatten()**2+xx.flatten()**2

#open and write to file
binfile = open('test_8bit.raw','wb')
pointdata *= 255/pointdata.max()
pointdata.astype(np.uint8).tofile(binfile)

test render

EDIT: see Leo's comment below the text for a quick overview on how to get this into blender!
As you can see the volume data receives and casts shadows, can be made transparent, change the color and much more.

5 comments:

  1. Nice basic explanation of the Blender Voxel file format! It is however not quite clear how to proceed once the .bvox file has been created. Could you give me a hint on how to import this file into Blender?

    ReplyDelete
  2. I had to struggle with this as well...
    (0) select blender render
    (1) define a cube to hold your 3d data
    (2) set its material to "Volume", set "Density" to 0
    (3) add a new texture of type Voxeldata and load the file
    (4) activate "Still frame" and set Still frame number to 1 (not 0!)
    (5) ramp up the "Intensity" (may well be 100 or more) until you see somthing in the render output
    Note: You may never see anything in the preview (at least that was the case for me)

    Another important point: There is a slight problem in the python scripts above that appears when nx, ny and nz are not all equal. Say, you have a 3d numpy array "data", then you should do

    nx, ny, nz = data.shape
    header = np.array([nz,ny,nx,nframes])

    Best,
    Leo

    ReplyDelete
  3. thank's for answering the question Leo! I'll refer to your comment in the text...

    Matthias

    ReplyDelete
  4. Hi,
    With those and Leo's instructions I got empty render.
    My files: https://www.dropbox.com/sh/4c3kndz7f78v0c1/AABTEYyoZw3LOmf9hgb0m4rsa?dl=0
    Can you help me?

    ReplyDelete
  5. I'm confused by using numpy arrays (and the associated functions) to do this. I have functions which evaluate a point at x, y, z and then nested loops which go through space and then plot points in a few different graphical display formats including ascii display... it may not be efficient, but how do I then plot these points in a bvox file?

    ReplyDelete