I'm working on a project where I'd really like to get voxel data loaded in cycles. This comment from a question I asked a while back indicates that it should be feasible by converting my voxel data to a smoke cache.

Is there a tool or api that can I can use to help create the a smoke cache from my voxel data? Or technical specification that describe the smoke cache file format such that I can write it from scratch?

Alternatively, I'm open to any other hacks or workarounds that can get my voxels into a Cycles texture!

  • $\begingroup$ I recently developed an add-on to convert smoke data into a tiled EXR image where each 'slice' of the smoke was represented by a tile. This could then be used in an Image Texture node with a carefully crafted transform from the XYZ coords in the volume into XY coords in the image. If you can convert your voxel data in a similar format you could use the same technique. See baldingwizard.wixsite.com/blog/smoke2exr for the add-on (download also available via github.com/baldingwizard/Blender-Addons/wiki/Smoke2EXR). $\endgroup$ Aug 20 '19 at 8:53

Since 2.77 Blender can use the OpenVDB format for smoke caching, and OpenVDB has a nice API and documentation. (There is also a Python API)

It is also an industry standard, which will be better supported in Blender in the future.

  • 1
    $\begingroup$ Any chance you'd be able to write a short example of how to write out a 3D numpy array to an OpenVDB volume? $\endgroup$
    – ajwood
    Feb 23 '17 at 23:38
  • $\begingroup$ There is a chapter named "Working with NumPy arrays" in the Python link. $\endgroup$
    – lbalazscs
    Feb 24 '17 at 9:21
  • $\begingroup$ I'm still having trouble getting it installed (on Ubuntu). Have you had difficulty with that? $\endgroup$
    – ajwood
    Feb 24 '17 at 13:18
  • $\begingroup$ No, I personally had no difficulty at all, because I didn't try :) But - considering that Blender itself uses it - it should be doable. It seems to be a pretty standard C++ program, but if you are not used to compiling this kind of stuff, it can be a challenge. Perhaps ask on the openvdb forums or on Ubuntu forums. $\endgroup$
    – lbalazscs
    Feb 24 '17 at 15:45

As part of developing the Smoke2EXR add-on mentioned in my answer to Voxel data in Cycles I did analyse the code that writes out the pointcache format so I could re-interpret the pointcache for my own purposes. The source file is pointcache.c and can be found in https://github.com/martijnberger/blender/blob/master/source/blender/blenkernel/intern/pointcache.c (there's probably a link to the actual blender.git repository but I couldn't easily find it).

The details I managed to extract from 'pointcache.c' to be able to interpret the pointcache file were as commented in the source of that add-on :

# Supports PointCache smoke version 1.04
# Smoke pointcache format :
# Bytes     Content
# 8         'BPHYSICS'
# 4         int - 3 (indicates Smoke)
# 4         int? (!!thought this was size of data... but compressed size exceeds this so one of them is wrong)
# 4         int (2 (???))
# 4         '1.04' (version)
# 4         int (fluid_fields)
# 4         int (active_fields)
# 4         int (res_X)
# 4         int (res_Y)
# 4         int (res_Z)
# 4         float? (dx)
# block - shadow (x * y * z * float)
# block - density (x * y * z * float)
# Optional :
#   block - heat (x * y * z * float)
#   block - heatold (x * y * z * float)
# Optional :
#   block - flame (x * y * z * float)
#   block - fuel (x * y * z * float)
#   block - react (x * y * z * float)
# Optional :
#   block - red (x * y * z * float)
#   block - green (x * y * z * float)
#   block - blue (x * y * z * float)
# block - vx (x * y * z * float)
# block - vy (x * y * z * float)
# block - vz (x * y * z * float)
# block - obstacles (x * y * z * byte?) (!!Doesn't seem to be populated)
# (more fields)
#       ptcache_file_write(pf, &dt, 1, sizeof(float));
#       ptcache_file_write(pf, &dx, 1, sizeof(float));
#       ptcache_file_write(pf, &sds->p0, 3, sizeof(float));
#       ptcache_file_write(pf, &sds->p1, 3, sizeof(float));
#       ptcache_file_write(pf, &sds->dp0, 3, sizeof(float));
#       ptcache_file_write(pf, &sds->shift, 3, sizeof(int));
#       ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float));
#       ptcache_file_write(pf, &sds->obmat, 16, sizeof(float));
#       ptcache_file_write(pf, &sds->base_res, 3, sizeof(int));
#       ptcache_file_write(pf, &sds->res_min, 3, sizeof(int));
#       ptcache_file_write(pf, &sds->res_max, 3, sizeof(int));
#       ptcache_file_write(pf, &sds->active_color, 3, sizeof(float));
# Optional turbulance - hi-res [...size based on number of 'divisions'+1 cubed - so 1 division is 2x2x2 times bigger, 2 divisions is 3x3x3 times bigger, etc.]
#   Optional:
#       block - density (hi-res)
#   Optional :
#       block - flame (hi-res)
#       block - fuel (hi-res)
#       block - react (hi-res)
#   Optional :
#       block - red (hi-res)
#       block - green (hi-res)
#       block - blue (hi-res)
#   block - tcu (x * y * z * float)
#   block - tcv (x * y * z * float)
#   block - tcw (x * y * z * float)

You could possibly use this to take your raw data and generate a pointcache file. However, I have not tried this and could not be sure of all the output fields - since I only needed to interpret certain blocks to be able to extract the content, so didn't analyse it to the depth to be able to create a consistent pointcache file. Note that many of the blocks are 'optional' (dependent on whether, say, Flame and/or Hi-Resolution is enabled) and you need to get the flags consistent with the blocks you need to have present.

The alternative is to convert your data into a different format that can be used in Cycles - such as the tiles EXR produced by the Smoke2EXR add-on mentioned above.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.