Implementation of OpenVDB as a possible cache format for smoke

simulations.

This commits implements OpenVDB as an extra cache format in the Point
Cache system for smoke simulations. Compilation with the library is
turned off by default for now, and shall be enabled when the library is
present.

A documentation of its doings is available here: http://
wiki.blender.org/index.php/User:Kevindietrich/OpenVDBSmokeExport.

A guide to compile OpenVDB can be found here (Linux): http://
wiki.blender.org/index.php?title=Dev:Doc/Building_Blender/Linux/
Dependencies_From_Source#OpenVDB

Reviewers: sergey, lukastoenne, brecht, campbellbarton

Reviewed By: brecht, campbellbarton

Subscribers: galenb, Blendify, robocyte, Lapineige, bliblubli,
jtheninja, lukasstockner97, dingto, brecht

Differential Revision: https://developer.blender.org/D1721
This commit is contained in:
Kévin Dietrich 2016-01-23 08:39:29 +01:00
parent 275abd14a0
commit e9452f909c
33 changed files with 2076 additions and 50 deletions

View File

@ -242,6 +242,9 @@ option(WITH_OPENSUBDIV "Enable OpenSubdiv for surface subdivision" _init_OPEN
option(WITH_SUBSURF_WERROR "Treat warnings as errors in subsurf code" OFF)
mark_as_advanced(WITH_COMPOSITOR_WERROR)
option(WITH_OPENVDB "Enable features relying on OpenVDB" OFF)
option(WITH_OPENVDB_BLOSC "Enable blosc compression for OpenVDB, only enable if OpenVDB was built with blosc support" OFF)
# GHOST Windowing Library Options
option(WITH_GHOST_DEBUG "Enable debugging output for the GHOST library" OFF)
mark_as_advanced(WITH_GHOST_DEBUG)
@ -677,10 +680,11 @@ if(NOT WITH_BOOST)
set_and_warn(WITH_CYCLES OFF)
set_and_warn(WITH_AUDASPACE OFF)
set_and_warn(WITH_INTERNATIONAL OFF)
set_and_warn(WITH_OPENVDB OFF)
set_and_warn(WITH_OPENAL OFF) # depends on AUDASPACE
set_and_warn(WITH_GAMEENGINE OFF) # depends on AUDASPACE
elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL)
elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL OR WITH_OPENVDB)
# Keep enabled
else()
# Enabled but we don't need it
@ -1056,6 +1060,24 @@ if(UNIX AND NOT APPLE)
endif()
endif()
if(WITH_OPENVDB)
find_package_wrapper(OpenVDB)
set(TBB ${LIBDIR}/tbb)
set(TBB_LIBRARIES tbb)
set(TBB_LIBPATH ${TBB}/lib)
set(OPENVDB_LIBRARIES ${OPENVDB_LIBRARIES} ${BOOST_LIBRARIES} ${ZLIB_LIBRARIES} ${TBB_LIBRARIES})
set(OPENVDB_LIBPATH) # TODO, remove and reference the absolute path everywhere
set(OPENVDB_DEFINITIONS)
if(NOT OPENVDB_FOUND)
set(WITH_OPENVDB OFF)
set(WITH_OPENVDB_BLOSC OFF)
message(STATUS "OpenVDB not found")
endif()
endif()
if(WITH_BOOST)
# uses in build instructions to override include and library variables
if(NOT BOOST_CUSTOM)
@ -1076,6 +1098,9 @@ if(UNIX AND NOT APPLE)
if(WITH_CYCLES_NETWORK)
list(APPEND __boost_packages serialization)
endif()
if(WITH_OPENVDB)
list(APPEND __boost_packages iostreams)
endif()
find_package(Boost 1.48 COMPONENTS ${__boost_packages})
if(NOT Boost_FOUND)
# try to find non-multithreaded if -mt not found, this flag
@ -1561,7 +1586,14 @@ elseif(WIN32)
set(OPENCOLORIO_LIBPATH ${LIBDIR}/opencolorio/lib)
set(OPENCOLORIO_DEFINITIONS)
endif()
if(WITH_OPENVDB)
set(OPENVDB ${LIBDIR}/openvdb)
set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES})
set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
set(OPENVDB_DEFINITIONS)
endif()
if(WITH_MOD_CLOTH_ELTOPO)
set(LAPACK ${LIBDIR}/lapack)
@ -1834,6 +1866,14 @@ elseif(WIN32)
set(SDL_LIBPATH ${SDL}/lib)
endif()
if(WITH_OPENVDB)
set(OPENVDB ${LIBDIR}/openvdb)
set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES})
set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
set(OPENVDB_DEFINITIONS)
endif()
set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
## DISABLE - causes linking errors
@ -2139,6 +2179,14 @@ elseif(APPLE)
set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib)
endif()
if(WITH_OPENVDB)
set(OPENVDB ${LIBDIR}/openvdb)
set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES})
set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
set(OPENVDB_DEFINITIONS)
endif()
if(WITH_LLVM)
set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
set(LLVM_VERSION "3.4" CACHE STRING "Version of LLVM to use")
@ -2981,6 +3029,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_CYCLES)
info_cfg_option(WITH_FREESTYLE)
info_cfg_option(WITH_OPENCOLORIO)
info_cfg_option(WITH_OPENVDB)
info_cfg_text("Compiler Options:")
info_cfg_option(WITH_BUILDINFO)

View File

@ -0,0 +1,74 @@
# - Find OPENVDB library
# Find the native OPENVDB includes and library
# This module defines
# OPENVDB_INCLUDE_DIRS, where to find openvdb.h, Set when
# OPENVDB_INCLUDE_DIR is found.
# OPENVDB_LIBRARIES, libraries to link against to use OPENVDB.
# OPENVDB_ROOT_DIR, The base directory to search for OPENVDB.
# This can also be an environment variable.
# OPENVDB_FOUND, If false, do not try to use OPENVDB.
#
# also defined, but not for general use are
# OPENVDB_LIBRARY, where to find the OPENVDB library.
#=============================================================================
# Copyright 2015 Blender Foundation.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If OPENVDB_ROOT_DIR was defined in the environment, use it.
IF(NOT OPENVDB_ROOT_DIR AND NOT $ENV{OPENVDB_ROOT_DIR} STREQUAL "")
SET(OPENVDB_ROOT_DIR $ENV{OPENVDB_ROOT_DIR})
ENDIF()
SET(_openvdb_SEARCH_DIRS
${OPENVDB_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt/openvdb
/opt/lib/openvdb
)
FIND_PATH(OPENVDB_INCLUDE_DIR
NAMES
openvdb/openvdb.h
HINTS
${_openvdb_SEARCH_DIRS}
PATH_SUFFIXES
include
)
FIND_LIBRARY(OPENVDB_LIBRARY
NAMES
openvdb
HINTS
${_openvdb_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
# handle the QUIETLY and REQUIRED arguments and set OPENVDB_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENVDB DEFAULT_MSG
OPENVDB_LIBRARY OPENVDB_INCLUDE_DIR)
IF(OPENVDB_FOUND)
SET(OPENVDB_LIBRARIES ${OPENVDB_LIBRARY})
SET(OPENVDB_INCLUDE_DIRS ${OPENVDB_INCLUDE_DIR})
ENDIF(OPENVDB_FOUND)
MARK_AS_ADVANCED(
OPENVDB_INCLUDE_DIR
OPENVDB_LIBRARY
)
UNSET(_openvdb_SEARCH_DIRS)

View File

@ -47,6 +47,7 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENMP OFF CACHE BOOL "" FORCE)
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE)

View File

@ -31,3 +31,4 @@ set(WITH_INPUT_NDOF OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)

View File

@ -282,6 +282,9 @@ function(SETUP_LIBDIRS)
if(WITH_OPENCOLORIO)
link_directories(${OPENCOLORIO_LIBPATH})
endif()
if(WITH_OPENVDB)
link_directories(${OPENVDB_LIBPATH})
endif()
if(WITH_IMAGE_OPENJPEG AND WITH_SYSTEM_OPENJPEG)
link_directories(${OPENJPEG_LIBPATH})
endif()
@ -400,6 +403,9 @@ function(setup_liblinks
target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES})
endif()
endif()
if(WITH_OPENVDB)
target_link_libraries(${target} ${OPENVDB_LIBRARIES})
endif()
if(WITH_CYCLES_OSL)
target_link_libraries(${target} ${OSL_LIBRARIES})
endif()
@ -713,6 +719,10 @@ function(SETUP_BLENDER_SORTED_LIBS)
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
if(WITH_OPENVDB)
list(APPEND BLENDER_SORTED_LIBS bf_intern_openvdb)
endif()
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
set(REMLIB ${SORTLIB})
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})

View File

@ -82,3 +82,7 @@ endif()
if(WIN32)
add_subdirectory(utfconv)
endif()
if(WITH_OPENVDB)
add_subdirectory(openvdb)
endif()

View File

@ -0,0 +1,69 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2015, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Kevin Dietrich.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
intern
)
set(INC_SYS
)
set(SRC
openvdb_capi.h
)
if(WITH_OPENVDB)
add_definitions(
-DWITH_OPENVDB
)
list(APPEND INC_SYS
${BOOST_INCLUDE_DIR}
${OPENEXR_INCLUDE_DIRS}
${OPENVDB_INCLUDE_DIRS}
)
list(APPEND SRC
intern/openvdb_dense_convert.cc
intern/openvdb_reader.cc
intern/openvdb_writer.cc
openvdb_capi.cc
openvdb_util.cc
intern/openvdb_dense_convert.h
intern/openvdb_reader.h
intern/openvdb_writer.h
openvdb_util.h
)
if(WITH_OPENVDB_BLOSC)
add_definitions(
-DWITH_OPENVDB_BLOSC
)
endif()
endif()
blender_add_lib(bf_intern_openvdb "${SRC}" "${INC}" "${INC_SYS}")

View File

@ -0,0 +1,167 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "openvdb_dense_convert.h"
#include <openvdb/tools/ValueTransformer.h> /* for tools::foreach */
namespace internal {
openvdb::Mat4R convertMatrix(const float mat[4][4])
{
return openvdb::Mat4R(
mat[0][0], mat[0][1], mat[0][2], mat[0][3],
mat[1][0], mat[1][1], mat[1][2], mat[1][3],
mat[2][0], mat[2][1], mat[2][2], mat[2][3],
mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
}
class MergeScalarGrids {
typedef openvdb::FloatTree ScalarTree;
openvdb::tree::ValueAccessor<const ScalarTree> m_acc_x, m_acc_y, m_acc_z;
public:
MergeScalarGrids(const ScalarTree *x_tree, const ScalarTree *y_tree, const ScalarTree *z_tree)
: m_acc_x(*x_tree)
, m_acc_y(*y_tree)
, m_acc_z(*z_tree)
{}
MergeScalarGrids(const MergeScalarGrids &other)
: m_acc_x(other.m_acc_x)
, m_acc_y(other.m_acc_y)
, m_acc_z(other.m_acc_z)
{}
void operator()(const openvdb::Vec3STree::ValueOnIter &it) const
{
using namespace openvdb;
const math::Coord xyz = it.getCoord();
float x = m_acc_x.getValue(xyz);
float y = m_acc_y.getValue(xyz);
float z = m_acc_z.getValue(xyz);
it.setValue(math::Vec3s(x, y, z));
}
};
openvdb::GridBase *OpenVDB_export_vector_grid(
OpenVDBWriter *writer,
const openvdb::Name &name,
const float *data_x, const float *data_y, const float *data_z,
const int res[3],
float fluid_mat[4][4],
openvdb::VecType vec_type,
const bool is_color,
const openvdb::FloatGrid *mask)
{
using namespace openvdb;
math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1));
Mat4R mat = convertMatrix(fluid_mat);
math::Transform::Ptr transform = math::Transform::createLinearTransform(mat);
FloatGrid::Ptr grid[3];
grid[0] = FloatGrid::create(0.0f);
tools::Dense<const float, tools::LayoutXYZ> dense_grid_x(bbox, data_x);
tools::copyFromDense(dense_grid_x, grid[0]->tree(), TOLERANCE);
grid[1] = FloatGrid::create(0.0f);
tools::Dense<const float, tools::LayoutXYZ> dense_grid_y(bbox, data_y);
tools::copyFromDense(dense_grid_y, grid[1]->tree(), TOLERANCE);
grid[2] = FloatGrid::create(0.0f);
tools::Dense<const float, tools::LayoutXYZ> dense_grid_z(bbox, data_z);
tools::copyFromDense(dense_grid_z, grid[2]->tree(), TOLERANCE);
Vec3SGrid::Ptr vecgrid = Vec3SGrid::create(Vec3s(0.0f));
/* Activate voxels in the vector grid based on the scalar grids to ensure
* thread safety later on */
for (int i = 0; i < 3; ++i) {
vecgrid->tree().topologyUnion(grid[i]->tree());
}
MergeScalarGrids op(&(grid[0]->tree()), &(grid[1]->tree()), &(grid[2]->tree()));
tools::foreach(vecgrid->beginValueOn(), op, true, false);
vecgrid->setTransform(transform);
if (mask) {
vecgrid = tools::clip(*vecgrid, *mask);
}
vecgrid->setName(name);
vecgrid->setIsInWorldSpace(false);
vecgrid->setVectorType(vec_type);
vecgrid->insertMeta("is_color", BoolMetadata(is_color));
vecgrid->setGridClass(GRID_STAGGERED);
writer->insert(vecgrid);
return vecgrid.get();
}
void OpenVDB_import_grid_vector(
OpenVDBReader *reader,
const openvdb::Name &name,
float **data_x, float **data_y, float **data_z,
const int res[3])
{
using namespace openvdb;
if (!reader->hasGrid(name)) {
std::fprintf(stderr, "OpenVDB grid %s not found in file!\n", name.c_str());
memset(*data_x, 0, sizeof(float) * res[0] * res[1] * res[2]);
memset(*data_y, 0, sizeof(float) * res[0] * res[1] * res[2]);
memset(*data_z, 0, sizeof(float) * res[0] * res[1] * res[2]);
return;
}
Vec3SGrid::Ptr vgrid = gridPtrCast<Vec3SGrid>(reader->getGrid(name));
Vec3SGrid::ConstAccessor acc = vgrid->getConstAccessor();
math::Coord xyz;
int &x = xyz[0], &y = xyz[1], &z = xyz[2];
size_t index = 0;
for (z = 0; z < res[2]; ++z) {
for (y = 0; y < res[1]; ++y) {
for (x = 0; x < res[0]; ++x, ++index) {
math::Vec3s value = acc.getValue(xyz);
(*data_x)[index] = value.x();
(*data_y)[index] = value.y();
(*data_z)[index] = value.z();
}
}
}
}
} /* namespace internal */

View File

@ -0,0 +1,130 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __OPENVDB_DENSE_CONVERT_H__
#define __OPENVDB_DENSE_CONVERT_H__
#include "openvdb_reader.h"
#include "openvdb_writer.h"
#include <openvdb/tools/Clip.h>
#include <openvdb/tools/Dense.h>
#include <cstdio>
#define TOLERANCE 1e-3f
namespace internal {
openvdb::Mat4R convertMatrix(const float mat[4][4]);
template <typename GridType, typename T>
GridType *OpenVDB_export_grid(
OpenVDBWriter *writer,
const openvdb::Name &name,
const T *data,
const int res[3],
float fluid_mat[4][4],
const openvdb::FloatGrid *mask)
{
using namespace openvdb;
math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1));
Mat4R mat = convertMatrix(fluid_mat);
math::Transform::Ptr transform = math::Transform::createLinearTransform(mat);
typename GridType::Ptr grid = GridType::create(T(0));
tools::Dense<const T, openvdb::tools::LayoutXYZ> dense_grid(bbox, data);
tools::copyFromDense(dense_grid, grid->tree(), (T)TOLERANCE);
grid->setTransform(transform);
if (mask) {
grid = tools::clip(*grid, *mask);
}
grid->setName(name);
grid->setIsInWorldSpace(false);
grid->setVectorType(openvdb::VEC_INVARIANT);
writer->insert(grid);
return grid.get();
}
template <typename GridType, typename T>
void OpenVDB_import_grid(
OpenVDBReader *reader,
const openvdb::Name &name,
T **data,
const int res[3])
{
using namespace openvdb;
if (!reader->hasGrid(name)) {
std::fprintf(stderr, "OpenVDB grid %s not found in file!\n", name.c_str());
memset(*data, 0, sizeof(T) * res[0] * res[1] * res[2]);
return;
}
typename GridType::Ptr grid = gridPtrCast<GridType>(reader->getGrid(name));
typename GridType::ConstAccessor acc = grid->getConstAccessor();
math::Coord xyz;
int &x = xyz[0], &y = xyz[1], &z = xyz[2];
size_t index = 0;
for (z = 0; z < res[2]; ++z) {
for (y = 0; y < res[1]; ++y) {
for (x = 0; x < res[0]; ++x, ++index) {
(*data)[index] = acc.getValue(xyz);
}
}
}
}
openvdb::GridBase *OpenVDB_export_vector_grid(
OpenVDBWriter *writer,
const openvdb::Name &name,
const float *data_x, const float *data_y, const float *data_z,
const int res[3],
float fluid_mat[4][4],
openvdb::VecType vec_type,
const bool is_color,
const openvdb::FloatGrid *mask);
void OpenVDB_import_grid_vector(
OpenVDBReader *reader,
const openvdb::Name &name,
float **data_x, float **data_y, float **data_z,
const int res[3]);
} /* namespace internal */
#endif /* __OPENVDB_DENSE_CONVERT_H__ */

View File

@ -0,0 +1,136 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "openvdb_reader.h"
#include "openvdb_util.h"
OpenVDBReader::OpenVDBReader()
: m_meta_map(new openvdb::MetaMap)
, m_file(NULL)
{
/* Although it is safe, it may not be good to have this here, could be done
* once instead of everytime we read a file. */
openvdb::initialize();
}
OpenVDBReader::~OpenVDBReader()
{
cleanupFile();
}
void OpenVDBReader::open(const openvdb::Name &filename)
{
cleanupFile();
try {
m_file = new openvdb::io::File(filename);
m_file->setCopyMaxBytes(0);
m_file->open();
m_meta_map = m_file->getMetadata();
}
/* Mostly to catch exceptions related to Blosc not being supported. */
catch (const openvdb::IoError &e) {
std::cerr << e.what() << '\n';
cleanupFile();
}
}
void OpenVDBReader::floatMeta(const openvdb::Name &name, float &value) const
{
try {
value = m_meta_map->metaValue<float>(name);
}
CATCH_KEYERROR;
}
void OpenVDBReader::intMeta(const openvdb::Name &name, int &value) const
{
try {
value = m_meta_map->metaValue<int>(name);
}
CATCH_KEYERROR;
}
void OpenVDBReader::vec3sMeta(const openvdb::Name &name, float value[3]) const
{
try {
openvdb::Vec3s meta_val = m_meta_map->metaValue<openvdb::Vec3s>(name);
value[0] = meta_val.x();
value[1] = meta_val.y();
value[2] = meta_val.z();
}
CATCH_KEYERROR;
}
void OpenVDBReader::vec3IMeta(const openvdb::Name &name, int value[3]) const
{
try {
openvdb::Vec3i meta_val = m_meta_map->metaValue<openvdb::Vec3i>(name);
value[0] = meta_val.x();
value[1] = meta_val.y();
value[2] = meta_val.z();
}
CATCH_KEYERROR;
}
void OpenVDBReader::mat4sMeta(const openvdb::Name &name, float value[4][4]) const
{
try {
openvdb::Mat4s meta_val = m_meta_map->metaValue<openvdb::Mat4s>(name);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
value[i][j] = meta_val[i][j];
}
}
}
CATCH_KEYERROR;
}
bool OpenVDBReader::hasGrid(const openvdb::Name &name) const
{
return m_file->hasGrid(name);
}
openvdb::GridBase::Ptr OpenVDBReader::getGrid(const openvdb::Name &name) const
{
return m_file->readGrid(name);
}
size_t OpenVDBReader::numGrids() const
{
return m_file->getGrids()->size();
}
void OpenVDBReader::cleanupFile()
{
if (m_file) {
m_file->close();
delete m_file;
}
}

View File

@ -0,0 +1,55 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __OPENVDB_READER_H__
#define __OPENVDB_READER_H__
#include <openvdb/openvdb.h>
struct OpenVDBReader {
private:
openvdb::MetaMap::Ptr m_meta_map;
openvdb::io::File *m_file;
void cleanupFile();
public:
OpenVDBReader();
~OpenVDBReader();
void open(const openvdb::Name &filename);
void floatMeta(const openvdb::Name &name, float &value) const;
void intMeta(const openvdb::Name &name, int &value) const;
void vec3sMeta(const openvdb::Name &name, float value[3]) const;
void vec3IMeta(const openvdb::Name &name, int value[3]) const;
void mat4sMeta(const openvdb::Name &name, float value[4][4]) const;
bool hasGrid(const openvdb::Name &name) const;
openvdb::GridBase::Ptr getGrid(const openvdb::Name &name) const;
size_t numGrids() const;
};
#endif /* __OPENVDB_READER_H__ */

View File

@ -0,0 +1,118 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "openvdb_writer.h"
#include "openvdb_util.h"
OpenVDBWriter::OpenVDBWriter()
: m_grids(new openvdb::GridPtrVec())
, m_meta_map(new openvdb::MetaMap())
, m_save_as_half(false)
{
m_meta_map->insertMeta("creator", openvdb::StringMetadata("Blender/Smoke"));
}
OpenVDBWriter::~OpenVDBWriter()
{}
void OpenVDBWriter::insert(const openvdb::GridBase::Ptr &grid)
{
grid->setSaveFloatAsHalf(m_save_as_half);
m_grids->push_back(grid);
}
void OpenVDBWriter::insert(const openvdb::GridBase &grid)
{
m_grids->push_back(grid.copyGrid());
}
void OpenVDBWriter::insertFloatMeta(const openvdb::Name &name, const float value)
{
try {
m_meta_map->insertMeta(name, openvdb::FloatMetadata(value));
}
CATCH_KEYERROR;
}
void OpenVDBWriter::insertIntMeta(const openvdb::Name &name, const int value)
{
try {
m_meta_map->insertMeta(name, openvdb::Int32Metadata(value));
}
CATCH_KEYERROR;
}
void OpenVDBWriter::insertVec3sMeta(const openvdb::Name &name, const openvdb::Vec3s &value)
{
try {
m_meta_map->insertMeta(name, openvdb::Vec3SMetadata(value));
}
CATCH_KEYERROR;
}
void OpenVDBWriter::insertVec3IMeta(const openvdb::Name &name, const openvdb::Vec3I &value)
{
try {
m_meta_map->insertMeta(name, openvdb::Vec3IMetadata(value));
}
CATCH_KEYERROR;
}
void OpenVDBWriter::insertMat4sMeta(const openvdb::Name &name, const float value[4][4])
{
openvdb::Mat4s mat = openvdb::Mat4s(
value[0][0], value[0][1], value[0][2], value[0][3],
value[1][0], value[1][1], value[1][2], value[1][3],
value[2][0], value[2][1], value[2][2], value[2][3],
value[3][0], value[3][1], value[3][2], value[3][3]);
try {
m_meta_map->insertMeta(name, openvdb::Mat4SMetadata(mat));
}
CATCH_KEYERROR;
}
void OpenVDBWriter::setFlags(const int compression, const bool save_as_half)
{
m_compression_flags = compression;
m_save_as_half = save_as_half;
}
void OpenVDBWriter::write(const openvdb::Name &filename) const
{
try {
openvdb::io::File file(filename);
file.setCompression(m_compression_flags);
file.write(*m_grids, *m_meta_map);
file.close();
/* Should perhaps be an option at some point */
m_grids->clear();
}
/* Mostly to catch exceptions related to Blosc not being supported. */
catch (const openvdb::IoError &e) {
std::cerr << e.what() << '\n';
}
}

View File

@ -0,0 +1,57 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __OPENVDB_WRITER_H__
#define __OPENVDB_WRITER_H__
#include <openvdb/openvdb.h>
struct OpenVDBWriter {
private:
openvdb::GridPtrVecPtr m_grids;
openvdb::MetaMap::Ptr m_meta_map;
int m_compression_flags;
bool m_save_as_half;
public:
OpenVDBWriter();
~OpenVDBWriter();
void insert(const openvdb::GridBase::Ptr &grid);
void insert(const openvdb::GridBase &grid);
void insertFloatMeta(const openvdb::Name &name, const float value);
void insertIntMeta(const openvdb::Name &name, const int value);
void insertVec3sMeta(const openvdb::Name &name, const openvdb::Vec3s &value);
void insertVec3IMeta(const openvdb::Name &name, const openvdb::Vec3I &value);
void insertMat4sMeta(const openvdb::Name &name, const float value[4][4]);
void setFlags(const int compression, const bool save_as_half);
void write(const openvdb::Name &filename) const;
};
#endif /* __OPENVDB_WRITER_H__ */

View File

@ -0,0 +1,240 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "openvdb_capi.h"
#include "openvdb_dense_convert.h"
#include "openvdb_util.h"
struct OpenVDBFloatGrid { int unused; };
struct OpenVDBIntGrid { int unused; };
struct OpenVDBVectorGrid { int unused; };
int OpenVDB_getVersionHex()
{
return openvdb::OPENVDB_LIBRARY_VERSION;
}
OpenVDBFloatGrid *OpenVDB_export_grid_fl(
OpenVDBWriter *writer,
const char *name, float *data,
const int res[3], float matrix[4][4],
OpenVDBFloatGrid *mask)
{
Timer(__func__);
using openvdb::FloatGrid;
FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask);
FloatGrid *grid = internal::OpenVDB_export_grid<FloatGrid>(
writer,
name,
data,
res,
matrix,
mask_grid);
return reinterpret_cast<OpenVDBFloatGrid *>(grid);
}
OpenVDBIntGrid *OpenVDB_export_grid_ch(
OpenVDBWriter *writer,
const char *name, unsigned char *data,
const int res[3], float matrix[4][4],
OpenVDBFloatGrid *mask)
{
Timer(__func__);
using openvdb::FloatGrid;
using openvdb::Int32Grid;
FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask);
Int32Grid *grid = internal::OpenVDB_export_grid<Int32Grid>(
writer,
name,
data,
res,
matrix,
mask_grid);
return reinterpret_cast<OpenVDBIntGrid *>(grid);
}
OpenVDBVectorGrid *OpenVDB_export_grid_vec(
struct OpenVDBWriter *writer,
const char *name,
const float *data_x, const float *data_y, const float *data_z,
const int res[3], float matrix[4][4], short vec_type,
const bool is_color, OpenVDBFloatGrid *mask)
{
Timer(__func__);
using openvdb::GridBase;
using openvdb::FloatGrid;
using openvdb::VecType;
FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask);
GridBase *grid = internal::OpenVDB_export_vector_grid(
writer,
name,
data_x,
data_y,
data_z,
res,
matrix,
static_cast<VecType>(vec_type),
is_color,
mask_grid);
return reinterpret_cast<OpenVDBVectorGrid *>(grid);
}
void OpenVDB_import_grid_fl(
OpenVDBReader *reader,
const char *name, float **data,
const int res[3])
{
Timer(__func__);
internal::OpenVDB_import_grid<openvdb::FloatGrid>(reader, name, data, res);
}
void OpenVDB_import_grid_ch(
OpenVDBReader *reader,
const char *name, unsigned char **data,
const int res[3])
{
internal::OpenVDB_import_grid<openvdb::Int32Grid>(reader, name, data, res);
}
void OpenVDB_import_grid_vec(
struct OpenVDBReader *reader,
const char *name,
float **data_x, float **data_y, float **data_z,
const int res[3])
{
Timer(__func__);
internal::OpenVDB_import_grid_vector(reader, name, data_x, data_y, data_z, res);
}
OpenVDBWriter *OpenVDBWriter_create()
{
return new OpenVDBWriter();
}
void OpenVDBWriter_free(OpenVDBWriter *writer)
{
delete writer;
}
void OpenVDBWriter_set_flags(OpenVDBWriter *writer, const int flag, const bool half)
{
int compression_flags = openvdb::io::COMPRESS_ACTIVE_MASK;
#ifdef WITH_OPENVDB_BLOSC
if (flag == 0) {
compression_flags |= openvdb::io::COMPRESS_BLOSC;
}
else
#endif
if (flag == 1) {
compression_flags |= openvdb::io::COMPRESS_ZIP;
}
else {
compression_flags = openvdb::io::COMPRESS_NONE;
}
writer->setFlags(compression_flags, half);
}
void OpenVDBWriter_add_meta_fl(OpenVDBWriter *writer, const char *name, const float value)
{
writer->insertFloatMeta(name, value);
}
void OpenVDBWriter_add_meta_int(OpenVDBWriter *writer, const char *name, const int value)
{
writer->insertIntMeta(name, value);
}
void OpenVDBWriter_add_meta_v3(OpenVDBWriter *writer, const char *name, const float value[3])
{
writer->insertVec3sMeta(name, value);
}
void OpenVDBWriter_add_meta_v3_int(OpenVDBWriter *writer, const char *name, const int value[3])
{
writer->insertVec3IMeta(name, value);
}
void OpenVDBWriter_add_meta_mat4(OpenVDBWriter *writer, const char *name, float value[4][4])
{
writer->insertMat4sMeta(name, value);
}
void OpenVDBWriter_write(OpenVDBWriter *writer, const char *filename)
{
writer->write(filename);
}
OpenVDBReader *OpenVDBReader_create()
{
return new OpenVDBReader();
}
void OpenVDBReader_free(OpenVDBReader *reader)
{
delete reader;
}
void OpenVDBReader_open(OpenVDBReader *reader, const char *filename)
{
reader->open(filename);
}
void OpenVDBReader_get_meta_fl(OpenVDBReader *reader, const char *name, float *value)
{
reader->floatMeta(name, *value);
}
void OpenVDBReader_get_meta_int(OpenVDBReader *reader, const char *name, int *value)
{
reader->intMeta(name, *value);
}
void OpenVDBReader_get_meta_v3(OpenVDBReader *reader, const char *name, float value[3])
{
reader->vec3sMeta(name, value);
}
void OpenVDBReader_get_meta_v3_int(OpenVDBReader *reader, const char *name, int value[3])
{
reader->vec3IMeta(name, value);
}
void OpenVDBReader_get_meta_mat4(OpenVDBReader *reader, const char *name, float value[4][4])
{
reader->mat4sMeta(name, value);
}

View File

@ -0,0 +1,108 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __OPENVDB_CAPI_H__
#define __OPENVDB_CAPI_H__
#ifdef __cplusplus
extern "C" {
#endif
struct OpenVDBReader;
struct OpenVDBWriter;
struct OpenVDBFloatGrid;
struct OpenVDBIntGrid;
struct OpenVDBVectorGrid;
int OpenVDB_getVersionHex(void);
enum {
VEC_INVARIANT = 0,
VEC_COVARIANT = 1,
VEC_COVARIANT_NORMALIZE = 2,
VEC_CONTRAVARIANT_RELATIVE = 3,
VEC_CONTRAVARIANT_ABSOLUTE = 4,
};
struct OpenVDBFloatGrid *OpenVDB_export_grid_fl(
struct OpenVDBWriter *writer,
const char *name, float *data,
const int res[3], float matrix[4][4],
struct OpenVDBFloatGrid *mask);
struct OpenVDBIntGrid *OpenVDB_export_grid_ch(
struct OpenVDBWriter *writer,
const char *name, unsigned char *data,
const int res[3], float matrix[4][4],
struct OpenVDBFloatGrid *mask);
struct OpenVDBVectorGrid *OpenVDB_export_grid_vec(
struct OpenVDBWriter *writer,
const char *name,
const float *data_x, const float *data_y, const float *data_z,
const int res[3], float matrix[4][4], short vec_type,
const bool is_color,
struct OpenVDBFloatGrid *mask);
void OpenVDB_import_grid_fl(
struct OpenVDBReader *reader,
const char *name, float **data,
const int res[3]);
void OpenVDB_import_grid_ch(
struct OpenVDBReader *reader,
const char *name, unsigned char **data,
const int res[3]);
void OpenVDB_import_grid_vec(
struct OpenVDBReader *reader,
const char *name,
float **data_x, float **data_y, float **data_z,
const int res[3]);
struct OpenVDBWriter *OpenVDBWriter_create(void);
void OpenVDBWriter_free(struct OpenVDBWriter *writer);
void OpenVDBWriter_set_flags(struct OpenVDBWriter *writer, const int flag, const bool half);
void OpenVDBWriter_add_meta_fl(struct OpenVDBWriter *writer, const char *name, const float value);
void OpenVDBWriter_add_meta_int(struct OpenVDBWriter *writer, const char *name, const int value);
void OpenVDBWriter_add_meta_v3(struct OpenVDBWriter *writer, const char *name, const float value[3]);
void OpenVDBWriter_add_meta_v3_int(struct OpenVDBWriter *writer, const char *name, const int value[3]);
void OpenVDBWriter_add_meta_mat4(struct OpenVDBWriter *writer, const char *name, float value[4][4]);
void OpenVDBWriter_write(struct OpenVDBWriter *writer, const char *filename);
struct OpenVDBReader *OpenVDBReader_create(void);
void OpenVDBReader_free(struct OpenVDBReader *reader);
void OpenVDBReader_open(struct OpenVDBReader *reader, const char *filename);
void OpenVDBReader_get_meta_fl(struct OpenVDBReader *reader, const char *name, float *value);
void OpenVDBReader_get_meta_int(struct OpenVDBReader *reader, const char *name, int *value);
void OpenVDBReader_get_meta_v3(struct OpenVDBReader *reader, const char *name, float value[3]);
void OpenVDBReader_get_meta_v3_int(struct OpenVDBReader *reader, const char *name, int value[3]);
void OpenVDBReader_get_meta_mat4(struct OpenVDBReader *reader, const char *name, float value[4][4]);
#ifdef __cplusplus
}
#endif
#endif /* __OPENVDB_CAPI_H__ */

View File

@ -0,0 +1,38 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "openvdb_util.h"
#include <cstdio>
ScopeTimer::ScopeTimer(const std::string &message)
: m_message(message)
, m_timer()
{}
ScopeTimer::~ScopeTimer()
{
std::printf("%s: %fms\n", m_message.c_str(), m_timer.delta());
}

View File

@ -0,0 +1,57 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __OPENVDB_UTIL_H__
#define __OPENVDB_UTIL_H__
#include <openvdb/openvdb.h>
#include <openvdb/util/CpuTimer.h>
#define CATCH_KEYERROR \
catch (const openvdb::KeyError &e) { \
std::cerr << e.what() << '\n'; \
}
//#define DEBUG_TIME
/* A utility class which prints the time elapsed during its lifetime, useful for
* e.g. timing the overall execution time of a function */
class ScopeTimer {
std::string m_message;
openvdb::util::CpuTimer m_timer;
public:
ScopeTimer(const std::string &message);
~ScopeTimer();
};
#ifdef DEBUG_TIME
# define Timer(x) \
ScopeTimer prof(x);
#else
# define Timer(x)
#endif
#endif /* __OPENVDB_UTIL_H__ */

View File

@ -151,6 +151,13 @@ def write_sysinfo(filepath):
else:
output.write("Blender was built without Cycles support\n")
openvdb = bpy.app.openvdb
output.write("OpenVDB: ")
if openvdb.supported:
output.write("%s\n" % openvdb.version_string)
else:
output.write("Blender was built without OpenVDB support\n")
if not bpy.app.build_options.sdl:
output.write("SDL: Blender was built without SDL support\n")

View File

@ -304,12 +304,26 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
md = context.smoke.domain_settings
cache = md.point_cache
domain = context.smoke.domain_settings
cache_file_format = domain.cache_file_format
layout.label(text="Compression:")
layout.prop(md, "point_cache_compress_type", expand=True)
layout.prop(domain, "cache_file_format")
if cache_file_format == 'POINTCACHE':
layout.label(text="Compression:")
layout.prop(domain, "point_cache_compress_type", expand=True)
elif cache_file_format == 'OPENVDB':
if not bpy.app.build_options.openvdb:
layout.label("Build without OpenVDB support.")
return
layout.label(text="Compression:")
layout.prop(domain, "openvdb_cache_compress_type", expand=True)
row = layout.row()
row.label("Data Depth:")
row.prop(domain, "data_depth", expand=True, text="Data Depth")
cache = domain.point_cache
point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE')

View File

@ -94,6 +94,9 @@ struct SmokeModifierData;
struct SoftBody;
struct RigidBodyWorld;
struct OpenVDBReader;
struct OpenVDBWriter;
/* temp structure for read/write */
typedef struct PTCacheData {
unsigned int index;
@ -119,13 +122,18 @@ typedef struct PTCacheFile {
#define PTCACHE_VEL_PER_SEC 1
enum {
PTCACHE_FILE_PTCACHE = 0,
PTCACHE_FILE_OPENVDB = 1,
};
typedef struct PTCacheID {
struct PTCacheID *next, *prev;
struct Scene *scene;
struct Object *ob;
void *calldata;
unsigned int type;
unsigned int type, file_type;
unsigned int stack_index;
unsigned int flag;
@ -147,6 +155,11 @@ typedef struct PTCacheID {
/* copies cache cata to point data */
int (*read_stream)(PTCacheFile *pf, void *calldata);
/* copies point data to cache data */
int (*write_openvdb_stream)(struct OpenVDBWriter *writer, void *calldata);
/* copies cache cata to point data */
int (*read_openvdb_stream)(struct OpenVDBReader *reader, void *calldata);
/* copies custom extradata to cache data */
void (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra);
/* copies custom extradata to cache data */

View File

@ -517,6 +517,19 @@ if(WITH_OPENSUBDIV)
endif()
endif()
if(WITH_OPENVDB)
add_definitions(-DWITH_OPENVDB)
list(APPEND INC
../../../intern/openvdb
)
if(WITH_OPENVDB_BLOSC)
add_definitions(
-DWITH_OPENVDB_BLOSC
)
endif()
endif()
## Warnings as errors, this is too strict!
#if(MSVC)
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")

View File

@ -83,6 +83,10 @@
#include "smoke_API.h"
#endif
#ifdef WITH_OPENVDB
#include "openvdb_capi.h"
#endif
#ifdef WITH_LZO
# ifdef WITH_SYSTEM_LZO
# include <lzo/lzo1x.h>
@ -887,6 +891,274 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
return 1;
}
#ifdef WITH_OPENVDB
/**
* Construct matrices which represent the fluid object, for low and high res:
* <pre>
* vs 0 0 0
* 0 vs 0 0
* 0 0 vs 0
* px py pz 1
* </pre>
*
* with `vs` = voxel size, and `px, py, pz`,
* the min position of the domain's bounding box.
*/
static void compute_fluid_matrices(SmokeDomainSettings *sds)
{
float bbox_min[3];
copy_v3_v3(bbox_min, sds->p0);
if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]);
bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]);
bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]);
add_v3_v3(bbox_min, sds->obj_shift_f);
}
/* construct low res matrix */
size_to_mat4(sds->fluidmat, sds->cell_size);
copy_v3_v3(sds->fluidmat[3], bbox_min);
/* The smoke simulator stores voxels cell-centered, whilst VDB is node
* centered, so we offset the matrix by half a voxel to compensate. */
madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f);
mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat);
if (sds->wt) {
float voxel_size_high[3];
/* construct high res matrix */
mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1));
size_to_mat4(sds->fluidmat_wt, voxel_size_high);
copy_v3_v3(sds->fluidmat_wt[3], bbox_min);
/* Same here, add half a voxel to adjust the position of the fluid. */
madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f);
mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt);
}
}
static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v)
{
SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
SmokeDomainSettings *sds = smd->domain;
OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16));
OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields);
OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res);
OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min);
OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max);
OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res);
OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0);
OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1);
OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0);
OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift);
OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f);
OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color);
OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat);
int fluid_fields = smoke_get_data_flags(sds);
struct OpenVDBFloatGrid *clip_grid = NULL;
compute_fluid_matrices(sds);
OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields);
if (sds->wt) {
struct OpenVDBFloatGrid *wt_density_grid;
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, NULL);
clip_grid = wt_density_grid;
if (fluid_fields & SM_ACTIVE_FIRE) {
OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
}
if (fluid_fields & SM_ACTIVE_COLORS) {
OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, wt_density_grid);
}
OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, wt_density_grid);
}
if (sds->fluid) {
struct OpenVDBFloatGrid *density_grid;
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat,
&heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx);
OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt);
const char *name = (!sds->wt) ? "density" : "density low";
density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, NULL);
clip_grid = sds->wt ? clip_grid : density_grid;
OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, NULL);
if (fluid_fields & SM_ACTIVE_HEAT) {
OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, clip_grid);
OpenVDB_export_grid_fl(writer, "heat old", heatold, sds->res, sds->fluidmat, clip_grid);
}
if (fluid_fields & SM_ACTIVE_FIRE) {
name = (!sds->wt) ? "flame" : "flame low";
OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, density_grid);
name = (!sds->wt) ? "fuel" : "fuel low";
OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, density_grid);
name = (!sds->wt) ? "react" : "react low";
OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, density_grid);
}
if (fluid_fields & SM_ACTIVE_COLORS) {
name = (!sds->wt) ? "color" : "color low";
OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, density_grid);
}
OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, clip_grid);
OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, NULL);
}
return 1;
}
static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v)
{
SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
if (!smd) {
return 0;
}
SmokeDomainSettings *sds = smd->domain;
int fluid_fields = smoke_get_data_flags(sds);
int active_fields, cache_fields = 0;
int cache_res[3];
float cache_dx;
bool reallocate = false;
OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min);
OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max);
OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res);
OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0);
OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1);
OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0);
OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift);
OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f);
OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color);
OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat);
OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields);
OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields);
OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx);
OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res);
/* check if resolution has changed */
if (sds->res[0] != cache_res[0] ||
sds->res[1] != cache_res[1] ||
sds->res[2] != cache_res[2])
{
if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
reallocate = true;
}
else {
return 0;
}
}
/* check if active fields have changed */
if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) {
reallocate = true;
}
/* reallocate fluid if needed*/
if (reallocate) {
sds->active_fields = active_fields | cache_fields;
smoke_reallocate_fluid(sds, cache_dx, cache_res, 1);
sds->dx = cache_dx;
copy_v3_v3_int(sds->res, cache_res);
sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
if (sds->flags & MOD_SMOKE_HIGHRES) {
smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1);
}
}
if (sds->fluid) {
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat,
&heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt);
OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res);
const char *name = (!sds->wt) ? "density" : "density Low";
OpenVDB_import_grid_fl(reader, name, &dens, sds->res);
if (fluid_fields & SM_ACTIVE_HEAT) {
OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res);
OpenVDB_import_grid_fl(reader, "heat old", &heatold, sds->res);
}
if (fluid_fields & SM_ACTIVE_FIRE) {
name = (!sds->wt) ? "flame" : "flame low";
OpenVDB_import_grid_fl(reader, name, &flame, sds->res);
name = (!sds->wt) ? "fuel" : "fuel low";
OpenVDB_import_grid_fl(reader, name, &fuel, sds->res);
name = (!sds->wt) ? "react" : "react low";
OpenVDB_import_grid_fl(reader, name, &react, sds->res);
}
if (fluid_fields & SM_ACTIVE_COLORS) {
name = (!sds->wt) ? "color" : "color low";
OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res);
}
OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res);
OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res);
}
if (sds->wt) {
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt);
if (fluid_fields & SM_ACTIVE_FIRE) {
OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt);
OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt);
OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt);
}
if (fluid_fields & SM_ACTIVE_COLORS) {
OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt);
}
OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res);
}
OpenVDBReader_free(reader);
return 1;
}
#endif
#else // WITH_SMOKE
static int ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra)) { return 0; }
static void ptcache_smoke_error(void *UNUSED(smoke_v), const char *UNUSED(message)) { }
@ -894,6 +1166,20 @@ static int ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) {
static int ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; }
#endif // WITH_SMOKE
#if !defined(WITH_SMOKE) || !defined(WITH_OPENVDB)
static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v)
{
UNUSED_VARS(writer, smoke_v);
return 0;
}
static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v)
{
UNUSED_VARS(reader, smoke_v);
return 0;
}
#endif
static int ptcache_dynamicpaint_totpoint(void *sd, int UNUSED(cfra))
{
DynamicPaintSurface *surface = (DynamicPaintSurface*)sd;
@ -1113,6 +1399,9 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
pid->write_stream = NULL;
pid->read_stream = NULL;
pid->write_openvdb_stream = NULL;
pid->read_openvdb_stream = NULL;
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
@ -1127,6 +1416,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
pid->default_step = 10;
pid->max_step = 20;
pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys)
{
@ -1154,6 +1444,9 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p
pid->write_stream = NULL;
pid->read_stream = NULL;
pid->write_openvdb_stream = NULL;
pid->read_openvdb_stream = NULL;
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
@ -1185,6 +1478,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p
pid->default_step = 10;
pid->max_step = 20;
pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd)
{
@ -1204,6 +1498,9 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->read_point = ptcache_cloth_read;
pid->interpolate_point = ptcache_cloth_interpolate;
pid->write_openvdb_stream = NULL;
pid->read_openvdb_stream = NULL;
pid->write_stream = NULL;
pid->read_stream = NULL;
@ -1219,6 +1516,7 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->default_step = 1;
pid->max_step = 1;
pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd)
{
@ -1246,6 +1544,9 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
pid->read_stream = ptcache_smoke_read;
pid->write_stream = ptcache_smoke_write;
pid->write_openvdb_stream = ptcache_smoke_openvdb_write;
pid->read_openvdb_stream = ptcache_smoke_openvdb_read;
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
@ -1263,6 +1564,7 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
pid->default_step = 1;
pid->max_step = 1;
pid->file_type = smd->domain->cache_file_format;
}
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface)
@ -1286,6 +1588,9 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu
pid->write_stream = ptcache_dynamicpaint_write;
pid->read_stream = ptcache_dynamicpaint_read;
pid->write_openvdb_stream = NULL;
pid->read_openvdb_stream = NULL;
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
@ -1300,6 +1605,7 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu
pid->default_step = 1;
pid->max_step = 1;
pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw)
@ -1322,6 +1628,9 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->write_stream = NULL;
pid->read_stream = NULL;
pid->write_openvdb_stream = NULL;
pid->read_openvdb_stream = NULL;
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
@ -1337,6 +1646,7 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->default_step = 1;
pid->max_step = 1;
pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
@ -1429,6 +1739,38 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup
/* File handling */
static const char *ptcache_file_extension(const PTCacheID *pid)
{
switch (pid->file_type) {
default:
case PTCACHE_FILE_PTCACHE:
return PTCACHE_EXT;
case PTCACHE_FILE_OPENVDB:
return ".vdb";
}
}
/**
* Similar to #BLI_path_frame_get, but takes into account the stack-index which is after the frame.
*/
static int ptcache_frame_from_filename(const char *filename, const char *ext)
{
const int frame_len = 6;
const int ext_len = frame_len + strlen(ext);
const int len = strlen(filename);
/* could crash if trying to copy a string out of this range */
if (len > ext_len) {
/* using frame_len here gives compile error (vla) */
char num[/* frame_len */6 + 1];
BLI_strncpy(num, filename + len - ext_len, sizeof(num));
return atoi(num);
}
return -1;
}
/* Takes an Object ID and returns a unique name
* - id: object id
* - cfra: frame for the cache, can be negative
@ -1507,18 +1849,19 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
}
if (do_ext) {
if (pid->cache->index < 0)
pid->cache->index = pid->stack_index = BKE_object_insert_ptcache(pid->ob);
const char *ext = ptcache_file_extension(pid);
if (pid->cache->flag & PTCACHE_EXTERNAL) {
if (pid->cache->index >= 0)
BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */
else
BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */
BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d%s", cfra, ext); /* always 6 chars */
}
else {
BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */
}
len += 16;
}
@ -2156,6 +2499,36 @@ static int ptcache_read_stream(PTCacheID *pid, int cfra)
return error == 0;
}
static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra)
{
#ifdef WITH_OPENVDB
char filename[FILE_MAX * 2];
/* save blend file before using disk pointcache */
if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0)
return 0;
ptcache_filename(pid, filename, cfra, 1, 1);
if (!BLI_exists(filename)) {
return 0;
}
struct OpenVDBReader *reader = OpenVDBReader_create();
OpenVDBReader_open(reader, filename);
if (!pid->read_openvdb_stream(reader, pid->calldata)) {
return 0;
}
return 1;
#else
UNUSED_VARS(pid, cfra);
return 0;
#endif
}
static int ptcache_read(PTCacheID *pid, int cfra)
{
PTCacheMem *pm = NULL;
@ -2297,8 +2670,12 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra)
return 0;
if (cfra1) {
if (pid->read_stream) {
if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
if (!ptcache_read_openvdb_stream(pid, cfra1)) {
return 0;
}
}
else if (pid->read_stream) {
if (!ptcache_read_stream(pid, cfra1))
return 0;
}
@ -2307,8 +2684,12 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra)
}
if (cfra2) {
if (pid->read_stream) {
if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
if (!ptcache_read_openvdb_stream(pid, cfra2)) {
return 0;
}
}
else if (pid->read_stream) {
if (!ptcache_read_stream(pid, cfra2))
return 0;
}
@ -2374,6 +2755,28 @@ static int ptcache_write_stream(PTCacheID *pid, int cfra, int totpoint)
return error == 0;
}
static int ptcache_write_openvdb_stream(PTCacheID *pid, int cfra)
{
#ifdef WITH_OPENVDB
struct OpenVDBWriter *writer = OpenVDBWriter_create();
char filename[FILE_MAX * 2];
BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra);
ptcache_filename(pid, filename, cfra, 1, 1);
BLI_make_existing_file(filename);
int error = pid->write_openvdb_stream(writer, pid->calldata);
OpenVDBWriter_write(writer, filename);
OpenVDBWriter_free(writer);
return error == 0;
#else
UNUSED_VARS(pid, cfra);
return 0;
#endif
}
static int ptcache_write(PTCacheID *pid, int cfra, int overwrite)
{
PointCache *cache = pid->cache;
@ -2505,7 +2908,10 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
if (ptcache_write_needed(pid, cfra, &overwrite)==0)
return 0;
if (pid->write_stream) {
if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->write_openvdb_stream) {
ptcache_write_openvdb_stream(pid, cfra);
}
else if (pid->write_stream) {
ptcache_write_stream(pid, cfra, totpoint);
}
else if (pid->write_point) {
@ -2563,7 +2969,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
#endif
/*if (!G.relbase_valid) return; *//* save blend file before using pointcache */
const char *fext = ptcache_file_extension(pid);
/* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
switch (mode) {
case PTCACHE_CLEAR_ALL:
@ -2585,7 +2993,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
len += 1;
}
BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
@ -2597,13 +3005,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
}
else {
/* read the number of the file */
unsigned int frame, len2 = (int)strlen(de->d_name);
char num[7];
const int frame = ptcache_frame_from_filename(de->d_name, ext);
if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
frame = atoi(num);
if (frame != -1) {
if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) ||
(mode == PTCACHE_CLEAR_AFTER && frame > cfra))
{
@ -2791,21 +3195,18 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra
if (dir==NULL)
return;
BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
const char *fext = ptcache_file_extension(pid);
BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
unsigned int frame, len2 = (int)strlen(de->d_name);
char num[7];
const int frame = ptcache_frame_from_filename(de->d_name, ext);
if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
frame = atoi(num);
if (frame >= sta && frame <= end)
cache->cached_frames[frame-sta] = 1;
if ((frame != -1) && (frame >= sta && frame <= end)) {
cache->cached_frames[frame-sta] = 1;
}
}
}
@ -3466,7 +3867,9 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
return;
}
BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
const char *fext = ptcache_file_extension(pid);
BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
/* put new name into cache */
BLI_strncpy(pid->cache->name, name_dst, sizeof(pid->cache->name));
@ -3475,13 +3878,9 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
if (STREQLEN(old_filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
int frame, len2 = (int)strlen(de->d_name);
char num[7];
if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
frame = atoi(num);
const int frame = ptcache_frame_from_filename(de->d_name, ext);
if (frame != -1) {
BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name);
ptcache_filename(pid, new_path_full, frame, 1, 1);
BLI_rename(old_path_full, new_path_full);
@ -3521,22 +3920,20 @@ void BKE_ptcache_load_external(PTCacheID *pid)
if (dir==NULL)
return;
const char *fext = ptcache_file_extension(pid);
if (cache->index >= 0)
BLI_snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index);
BLI_snprintf(ext, sizeof(ext), "_%02d%s", cache->index, fext);
else
BLI_strncpy(ext, PTCACHE_EXT, sizeof(ext));
BLI_strncpy(ext, fext, sizeof(ext));
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
int frame, len2 = (int)strlen(de->d_name);
char num[7];
if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
frame = atoi(num);
const int frame = ptcache_frame_from_filename(de->d_name, ext);
if (frame != -1) {
if (frame) {
start = MIN2(start, frame);
end = MAX2(end, frame);

View File

@ -527,6 +527,14 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
#ifdef WITH_OPENVDB_BLOSC
smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
#else
smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
#endif
smd->domain->data_depth = 0;
smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@ -617,6 +625,9 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
MEM_freeN(tsmd->domain->effector_weights);
tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights);
tsmd->domain->openvdb_comp = smd->domain->openvdb_comp;
tsmd->domain->data_depth = smd->domain->data_depth;
tsmd->domain->cache_file_format = smd->domain->cache_file_format;
}
else if (tsmd->flow) {
tsmd->flow->psys = smd->flow->psys;

View File

@ -7812,9 +7812,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* draw adaptive domain bounds */
if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) && !render_override) {
float p0[3], p1[3];
BoundBox bb;
/* draw domain max bounds */
BoundBox bb;
float p0[3], p1[3];
VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
BKE_boundbox_init_from_minmax(&bb, p0, p1);
@ -7825,6 +7825,20 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
draw_box(bb.vec);
#endif
/* draw a single voxel to hint the user about the resolution of the fluid */
copy_v3_v3(p0, sds->p0);
if (sds->flags & MOD_SMOKE_HIGHRES) {
madd_v3_v3v3fl(p1, p0, sds->cell_size, 1.0f / (sds->amplify + 1));
}
else {
add_v3_v3v3(p1, p0, sds->cell_size);
}
BKE_boundbox_init_from_minmax(&bb, p0, p1);
draw_box(bb.vec, false);
}
/* don't show smoke before simulation starts, this could be made an option in the future */

View File

@ -77,6 +77,12 @@ enum {
#define SM_ACTIVE_COLORS (1<<2)
#define SM_ACTIVE_COLOR_SET (1<<3)
enum {
VDB_COMPRESSION_BLOSC = 0,
VDB_COMPRESSION_ZIP = 1,
VDB_COMPRESSION_NONE = 2,
};
typedef struct SmokeDomainSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
struct FLUID_3D *fluid;
@ -103,6 +109,8 @@ typedef struct SmokeDomainSettings {
float obj_shift_f[3]; /* how much object has shifted since previous smoke frame (used to "lock" domain while drawing) */
float imat[4][4]; /* domain object imat */
float obmat[4][4]; /* domain obmat */
float fluidmat[4][4]; /* low res fluid matrix */
float fluidmat_wt[4][4]; /* high res fluid matrix */
int base_res[3]; /* initial "non-adapted" resolution */
int res_min[3]; /* cell min */
@ -129,8 +137,14 @@ typedef struct SmokeDomainSettings {
float strength;
int res_wt[3];
float dx_wt;
/* point cache options */
int cache_comp;
int cache_high_comp;
/* OpenVDB cache options */
int openvdb_comp;
char cache_file_format;
char data_depth;
char pad[2];
/* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading old files. */
struct PointCache *point_cache[2]; /* definition is in DNA_object_force.h */

View File

@ -311,6 +311,14 @@ if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
if(WITH_OPENVDB)
add_definitions(-DWITH_OPENVDB)
if(WITH_OPENVDB_BLOSC)
add_definitions(-DWITH_OPENVDB_BLOSC)
endif()
endif()
# Build makesrna executable
blender_include_dirs(
.

View File

@ -35,6 +35,7 @@
#include "BKE_modifier.h"
#include "BKE_smoke.h"
#include "BKE_pointcache.h"
#include "BLI_threads.h"
@ -332,6 +333,15 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem prop_compression_items[] = {
{ VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression" },
#ifdef WITH_OPENVDB_BLOSC
{ VDB_COMPRESSION_BLOSC, "BLOSC", 0, "Blosc", "Multithreaded compression, similar in size and quality as 'Zip'" },
#endif
{ VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression" },
{ 0, NULL, 0, NULL, NULL }
};
static EnumPropertyItem smoke_cache_comp_items[] = {
{SM_CACHE_LIGHT, "CACHELIGHT", 0, "Light", "Fast but not so effective compression"},
{SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"},
@ -345,6 +355,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem smoke_data_depth_items[] = {
{16, "16", 0, "Float (Half)", "Half float (16 bit data)"},
{0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem smoke_domain_colli_items[] = {
{SM_BORDER_OPEN, "BORDEROPEN", 0, "Open", "Smoke doesn't collide with any border"},
{SM_BORDER_VERTICAL, "BORDERVERTICAL", 0, "Vertically Open",
@ -353,6 +369,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem cache_file_type_items[] = {
{PTCACHE_FILE_PTCACHE, "POINTCACHE", 0, "Point Cache", "Blender specific point cache file format"},
#ifdef WITH_OPENVDB
{PTCACHE_FILE_OPENVDB, "OPENVDB", 0, "OpenVDB", "OpenVDB file format"},
#endif
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL);
RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings");
RNA_def_struct_sdna(srna, "SmokeDomainSettings");
@ -463,6 +487,19 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, smoke_cache_comp_items);
RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used");
prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp");
RNA_def_property_enum_items(prop, prop_compression_items);
RNA_def_property_ui_text(prop, "Compression", "Compression method to be used");
prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth");
RNA_def_property_enum_items(prop, smoke_data_depth_items);
RNA_def_property_ui_text(prop, "Data Depth",
"Bit depth for writing all scalar (including vector) "
"lower values reduce file size");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
prop = RNA_def_property(srna, "collision_extents", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "border_collisions");
RNA_def_property_enum_items(prop, smoke_domain_colli_items);
@ -601,6 +638,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Threshold",
"Maximum amount of fluid cell can contain before it is considered empty");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "cache_file_format");
RNA_def_property_enum_items(prop, cache_file_type_items);
RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)

View File

@ -54,6 +54,7 @@ set(SRC
bpy_app_handlers.c
bpy_app_ocio.c
bpy_app_oiio.c
bpy_app_openvdb.c
bpy_app_sdl.c
bpy_app_translations.c
bpy_driver.c
@ -84,6 +85,7 @@ set(SRC
bpy_app_handlers.h
bpy_app_ocio.h
bpy_app_oiio.h
bpy_app_openvdb.h
bpy_app_sdl.h
bpy_app_translations.h
bpy_driver.h
@ -267,6 +269,13 @@ if(WITH_OPENCOLORIO)
add_definitions(-DWITH_OCIO)
endif()
if(WITH_OPENVDB)
add_definitions(-DWITH_OPENVDB)
list(APPEND INC
../../../../intern/openvdb
)
endif()
if(WITH_OPENIMAGEIO)
add_definitions(-DWITH_OPENIMAGEIO)
list(APPEND INC

View File

@ -36,6 +36,7 @@
#include "bpy_app_ffmpeg.h"
#include "bpy_app_ocio.h"
#include "bpy_app_oiio.h"
#include "bpy_app_openvdb.h"
#include "bpy_app_sdl.h"
#include "bpy_app_build_options.h"
@ -106,6 +107,7 @@ static PyStructSequence_Field app_info_fields[] = {
{(char *)"ffmpeg", (char *)"FFmpeg library information backend"},
{(char *)"ocio", (char *)"OpenColorIO library information backend"},
{(char *)"oiio", (char *)"OpenImageIO library information backend"},
{(char *)"openvdb", (char *)"OpenVDB library information backend"},
{(char *)"sdl", (char *)"SDL library information backend"},
{(char *)"build_options", (char *)"A set containing most important enabled optional build features"},
{(char *)"handlers", (char *)"Application handler callbacks"},
@ -183,6 +185,7 @@ static PyObject *make_app_info(void)
SetObjItem(BPY_app_ffmpeg_struct());
SetObjItem(BPY_app_ocio_struct());
SetObjItem(BPY_app_oiio_struct());
SetObjItem(BPY_app_openvdb_struct());
SetObjItem(BPY_app_sdl_struct());
SetObjItem(BPY_app_build_options_struct());
SetObjItem(BPY_app_handlers_struct());

View File

@ -69,6 +69,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"opencolorio", NULL},
{(char *)"player", NULL},
{(char *)"openmp", NULL},
{(char *)"openvdb", NULL},
{NULL}
};
@ -303,6 +304,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
#ifdef WITH_OPENVDB
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
#undef SetObjIncref
return builtopts_info;

View File

@ -0,0 +1,117 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/python/intern/bpy_app_openvdb.c
* \ingroup pythonintern
*/
#include <Python.h>
#include "BLI_utildefines.h"
#include "bpy_app_openvdb.h"
#ifdef WITH_OPENVDB
# include "openvdb_capi.h"
#endif
static PyTypeObject BlenderAppOVDBType;
static PyStructSequence_Field app_openvdb_info_fields[] = {
{(char *)"supported", (char *)("Boolean, True when Blender is built with OpenVDB support")},
{(char *)("version"), (char *)("The OpenVDB version as a tuple of 3 numbers")},
{(char *)("version_string"), (char *)("The OpenVDB version formatted as a string")},
{NULL}
};
static PyStructSequence_Desc app_openvdb_info_desc = {
(char *)"bpy.app.openvdb", /* name */
(char *)"This module contains information about OpenVDB blender is linked against", /* doc */
app_openvdb_info_fields, /* fields */
ARRAY_SIZE(app_openvdb_info_fields) - 1
};
static PyObject *make_openvdb_info(void)
{
PyObject *openvdb_info;
int pos = 0;
#ifdef WITH_OPENVDB
int curversion;
#endif
openvdb_info = PyStructSequence_New(&BlenderAppOVDBType);
if (openvdb_info == NULL) {
return NULL;
}
#ifndef WITH_OPENVDB
#define SetStrItem(str) \
PyStructSequence_SET_ITEM(openvdb_info, pos++, PyUnicode_FromString(str))
#endif
#define SetObjItem(obj) \
PyStructSequence_SET_ITEM(openvdb_info, pos++, obj)
#ifdef WITH_OPENVDB
curversion = OpenVDB_getVersionHex();
SetObjItem(PyBool_FromLong(1));
SetObjItem(Py_BuildValue("(iii)",
curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d",
curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
#else
SetObjItem(PyBool_FromLong(0));
SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
SetStrItem("Unknown");
#endif
if (PyErr_Occurred()) {
Py_CLEAR(openvdb_info);
return NULL;
}
#undef SetStrItem
#undef SetObjItem
return openvdb_info;
}
PyObject *BPY_app_openvdb_struct(void)
{
PyObject *ret;
PyStructSequence_InitType(&BlenderAppOVDBType, &app_openvdb_info_desc);
ret = make_openvdb_info();
/* prevent user from creating new instances */
BlenderAppOVDBType.tp_init = NULL;
BlenderAppOVDBType.tp_new = NULL;
BlenderAppOVDBType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
return ret;
}

View File

@ -0,0 +1,38 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/python/intern/bpy_app_openvdb.h
* \ingroup pythonintern
*/
#ifndef __BPY_APP_OPENVDB_H__
#define __BPY_APP_OPENVDB_H__
PyObject *BPY_app_openvdb_struct(void);
#endif /* __BPY_APP_OPENVDB_H__ */

View File

@ -218,6 +218,10 @@ endif()
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
if(WITH_OPENVDB)
list(APPEND BLENDER_SORTED_LIBS bf_intern_openvdb)
endif()
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
set(REMLIB ${SORTLIB})
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})