diff options
author | Geraldine Chua <chua.gsk@gmail.com> | 2018-07-10 10:49:51 +0300 |
---|---|---|
committer | Geraldine Chua <chua.gsk@gmail.com> | 2018-07-10 10:49:51 +0300 |
commit | 7fc47f83fc90edfb5404f468124afee605f81fe0 (patch) | |
tree | 58ecf47a54ac68d76e2bbcf5179f331f302230ab /intern/cycles/render | |
parent | 028f648753c893639f5c1732360e4cf6eb551e71 (diff) |
Initial commit for Cycles OpenVDB import.
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/CMakeLists.txt | 6 | ||||
-rw-r--r-- | intern/cycles/render/image.cpp | 144 | ||||
-rw-r--r-- | intern/cycles/render/image.h | 14 | ||||
-rw-r--r-- | intern/cycles/render/mesh_volume.cpp | 174 | ||||
-rw-r--r-- | intern/cycles/render/mesh_volume.h | 96 | ||||
-rw-r--r-- | intern/cycles/render/openvdb.cpp | 235 | ||||
-rw-r--r-- | intern/cycles/render/openvdb.h | 49 |
7 files changed, 596 insertions, 122 deletions
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index b7248354abd..601e6431123 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -51,6 +51,7 @@ set(SRC_HEADERS integrator.h light.h mesh.h + mesh_volume.h nodes.h object.h osl.h @@ -65,6 +66,11 @@ set(SRC_HEADERS tile.h ) +if(WITH_OPENVDB) + list(APPEND SRC openvdb.cpp) + list(APPEND SRC_HEADERS openvdb.h) +endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}") include_directories(${INC}) diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index e0337bfab42..70345ca543a 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -29,6 +29,10 @@ #include <OSL/oslexec.h> #endif +#ifdef WITH_OPENVDB +#include "render/openvdb.h" +#endif + CCL_NAMESPACE_BEGIN /* Some helpers to silence warning in templated function. */ @@ -104,6 +108,26 @@ bool ImageManager::get_image_metadata(const string& filename, if(builtin_data) { if(builtin_image_info_cb) { builtin_image_info_cb(filename, builtin_data, metadata); + +#ifdef WITH_OPENVDB + /* Metadata for external OpenVDB volumes. */ + if(!metadata.openvdb_filepath.empty()) { + if(!path_exists(metadata.openvdb_filepath)) { + VLOG(1) << "File '" << filename << "' does not exist."; + return false; + } + if(path_is_directory(metadata.openvdb_filepath)) { + VLOG(1) << "File '" << filename << "' is a directory, can't use as OpenVDB."; + return false; + } + int3 res = get_openvdb_resolution(metadata.openvdb_filepath); + metadata.width = res.x; + metadata.height = res.y; + metadata.depth = res.z; + metadata.is_float = true; + metadata.is_half = false; + } +#endif } else { return false; @@ -343,6 +367,7 @@ int ImageManager::add_image(const string& filename, img->make_sparse = make_sparse; img->isovalue = isovalue; img->mem = NULL; + img->openvdb_filepath = metadata.openvdb_filepath; images[type][slot] = img; @@ -730,7 +755,7 @@ void ImageManager::file_load_failed(device_vector<DeviceType> *tex_img, } template<typename DeviceType> -void ImageManager::file_make_image_sparse(Device *device, +bool ImageManager::file_make_image_sparse(Device *device, Image *img, device_vector<DeviceType> *tex_img) { @@ -764,7 +789,7 @@ void ImageManager::file_make_image_sparse(Device *device, VLOG(1) << "Could not make sparse grid for " << path_filename(img->filename) << " (" << img->mem_name << ")" << ", no active tiles"; - return; + return false; } size_t memory_usage = grid_info.size() * sizeof(int) + voxel_count * sizeof(DeviceType); @@ -775,7 +800,7 @@ void ImageManager::file_make_image_sparse(Device *device, << string_human_readable_size(tex_img->memory_size()) << " to " << string_human_readable_size(memory_usage) << ", not using sparse grid"; - return; + return false; } VLOG(1) << "Memory usage of '" @@ -808,6 +833,8 @@ void ImageManager::file_make_image_sparse(Device *device, tex_img->real_width = real_width; tex_img->real_height = real_height; tex_img->real_depth = real_depth; + + return true; } template<TypeDesc::BASETYPE FileFormat, @@ -823,6 +850,8 @@ void ImageManager::load_image(Device *device, img->mem_name.c_str(), MEM_TEXTURE); + bool is_sparse = false; + if(!file_load_image<FileFormat, StorageType, DeviceType>(img, type, texture_limit, @@ -832,17 +861,110 @@ void ImageManager::load_image(Device *device, file_load_failed<StorageType, DeviceType>(tex_img, type); } else if(img->make_sparse) { - file_make_image_sparse<DeviceType>(device, img, tex_img); + is_sparse = file_make_image_sparse<DeviceType>(device, img, tex_img); } img->mem = tex_img; img->mem->interpolation = img->interpolation; img->mem->extension = img->extension; + img->mem->grid_type = is_sparse ? IMAGE_GRID_TYPE_SPARSE : IMAGE_GRID_TYPE_DEFAULT; thread_scoped_lock device_lock(device_mutex); tex_img->copy_to_device(); } +#ifdef WITH_OPENVDB +template<typename StorageType, + typename DeviceType> +void ImageManager::load_openvdb_image(Device *device, + Image *img, + ImageDataType type, + int texture_limit) +{ + VLOG(1) << "Loading " << img->openvdb_filepath << ", Grid: " << img->filename; + + int3 resolution = get_openvdb_resolution(img->openvdb_filepath); + + if(device->info.type == DEVICE_CPU && 0) { + device_memory *tex_vdb = NULL; + { + thread_scoped_lock device_lock(device_mutex); + tex_vdb = file_load_openvdb(device, + img->openvdb_filepath, + img->filename, + resolution, + img->mem_name, + img->interpolation, + img->extension, + type == IMAGE_DATA_TYPE_FLOAT4, + texture_limit); + } + + if(tex_vdb) { + img->mem = tex_vdb; + } + else { + VLOG(1) << "Failed to load " + << path_filename(img->filename) << " (" << img->mem_name << ")"; + + device_vector<DeviceType> *tex_img = + new device_vector<DeviceType>(device, + img->mem_name.c_str(), + MEM_TEXTURE); + + file_load_failed<StorageType, DeviceType>(tex_img, type); + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + img->mem->grid_type = IMAGE_GRID_TYPE_DEFAULT; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + } + else { + device_vector<DeviceType> *tex_img = + new device_vector<DeviceType>(device, + img->mem_name.c_str(), + MEM_TEXTURE); + bool is_sparse = false; + + /* All pre-checks should happen BEFORE alloc. */ + if(!openvdb_has_grid(img->openvdb_filepath, img->filename)) { + VLOG(1) << "Failed to load " + << path_filename(img->filename) << " (" << img->mem_name << ")"; + + file_load_failed<StorageType, DeviceType>(tex_img, type); + } + else { + DeviceType *texture_pixels; + { + thread_scoped_lock device_lock(device_mutex); + texture_pixels = (DeviceType*)tex_img->alloc(resolution.x, + resolution.y, + resolution.z); + } + + file_load_openvdb_dense(img->openvdb_filepath, img->filename, + resolution, texture_limit, texture_pixels); + + if(img->make_sparse) { + is_sparse = file_make_image_sparse<DeviceType>(device, img, tex_img); + } + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + img->mem->grid_type = is_sparse ? IMAGE_GRID_TYPE_SPARSE : IMAGE_GRID_TYPE_DEFAULT; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } +} +#endif + void ImageManager::device_load_image(Device *device, Scene *scene, ImageDataType type, @@ -880,10 +1002,20 @@ void ImageManager::device_load_image(Device *device, /* Create new texture. */ switch(type) { case IMAGE_DATA_TYPE_FLOAT4: - load_image<TypeDesc::FLOAT, float, float4>(device, img, type, texture_limit); +#ifdef WITH_OPENVDB + if(!img->openvdb_filepath.empty()) + load_openvdb_image<float, float4>(device, img, type, texture_limit); + else +#endif + load_image<TypeDesc::FLOAT, float, float4>(device, img, type, texture_limit); break; case IMAGE_DATA_TYPE_FLOAT: - load_image<TypeDesc::FLOAT, float, float>(device, img, type, texture_limit); +#ifdef WITH_OPENVDB + if(!img->openvdb_filepath.empty()) + load_openvdb_image<float, float>(device, img, type, texture_limit); + else +#endif + load_image<TypeDesc::FLOAT, float, float>(device, img, type, texture_limit); break; case IMAGE_DATA_TYPE_BYTE4: load_image<TypeDesc::UINT8, uchar, uchar4>(device, img, type, texture_limit); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 8739c8f7793..b21428cf27b 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -38,6 +38,7 @@ public: int channels; size_t width, height, depth; bool builtin_free_cache; + string openvdb_filepath; /* Automatically set. */ ImageDataType type; @@ -127,6 +128,8 @@ public: device_memory *mem; int users; + + string openvdb_filepath; }; private: @@ -161,7 +164,7 @@ private: ImageDataType type); template<typename DeviceType> - void file_make_image_sparse(Device *device, + bool file_make_image_sparse(Device *device, Image *img, device_vector<DeviceType> *tex_dense); @@ -173,6 +176,15 @@ private: ImageDataType type, int texture_limit); +#ifdef WITH_OPENVDB + template<typename StorageType, + typename DeviceType> + void load_openvdb_image(Device *device, + Image *img, + ImageDataType type, + int texture_limit); +#endif + int max_flattened_slot(ImageDataType type); int type_index_to_flattened_slot(int slot, ImageDataType type); int flattened_slot_to_type_index(int flat_slot, ImageDataType *type); diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp index 5ce8198b9d6..51132431411 100644 --- a/intern/cycles/render/mesh_volume.cpp +++ b/intern/cycles/render/mesh_volume.cpp @@ -15,23 +15,20 @@ */ #include "render/mesh.h" +#include "render/mesh_volume.h" #include "render/attribute.h" +#ifdef WITH_OPENVDB +#include "render/openvdb.h" +#endif #include "render/scene.h" #include "util/util_foreach.h" #include "util/util_logging.h" #include "util/util_progress.h" #include "util/util_sparse_grid.h" -#include "util/util_types.h" CCL_NAMESPACE_BEGIN -struct QuadData { - int v0, v1, v2, v3; - - float3 normal; -}; - enum { QUAD_X_MIN = 0, QUAD_X_MAX = 1, @@ -90,70 +87,8 @@ static void create_quad(int3 corners[8], vector<int3> &vertices, vector<QuadData vertices.push_back(corners[quads_indices[face_index][3]]); } -struct VolumeParams { - int3 resolution; - float3 cell_size; - float3 start_point; - int pad_size; -}; - static const int CUBE_SIZE = 8; -/* Create a mesh from a volume. - * - * The way the algorithm works is as follows: - * - * - the coordinates of active voxels from a dense volume (or 3d image) are - * gathered inside an auxialliary volume. - * - each set of coordinates of an CUBE_SIZE cube are mapped to the same - * coordinate of the auxilliary volume. - * - quads are created between active and non-active voxels in the auxialliary - * volume to generate a tight mesh around the volume. - */ -class VolumeMeshBuilder { - /* Auxilliary volume that is used to check if a node already added. */ - vector<char> grid; - - /* The resolution of the auxilliary volume, set to be equal to 1/CUBE_SIZE - * of the original volume on each axis. */ - int3 res; - - size_t number_of_nodes; - - /* Offset due to padding in the original grid. Padding will transform the - * coordinates of the original grid from 0...res to -padding...res+padding, - * so some coordinates are negative, and we need to properly account for - * them. */ - int3 pad_offset; - - VolumeParams *params; - -public: - VolumeMeshBuilder(VolumeParams *volume_params); - - void add_node(int x, int y, int z); - - void add_node_with_padding(int x, int y, int z); - - void create_mesh(vector<float3> &vertices, - vector<int> &indices, - vector<float3> &face_normals); - -private: - void generate_vertices_and_quads(vector<int3> &vertices_is, - vector<QuadData> &quads); - - void deduplicate_vertices(vector<int3> &vertices, - vector<QuadData> &quads); - - void convert_object_space(const vector<int3> &vertices, - vector<float3> &out_vertices); - - void convert_quads_to_tris(const vector<QuadData> &quads, - vector<int> &tris, - vector<float3> &face_normals); -}; - VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params) { params = volume_params; @@ -378,8 +313,8 @@ void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads, /* ************************************************************************** */ struct VoxelAttributeGrid { - float *data; - int *grid_info = NULL; + void *data; + int *grid_info; int channels; }; @@ -395,6 +330,8 @@ void MeshManager::create_volume_mesh(Scene *scene, /* Compute volume parameters. */ VolumeParams volume_params; volume_params.resolution = make_int3(0, 0, 0); + bool is_openvdb = false; + int grid_mem = -1; foreach(Attribute& attr, mesh->attributes.attributes) { if(attr.element != ATTR_ELEMENT_VOXEL) { @@ -409,19 +346,21 @@ void MeshManager::create_volume_mesh(Scene *scene, image_memory->real_depth); if(volume_params.resolution == make_int3(0, 0, 0)) { + /* First volume grid. */ volume_params.resolution = resolution; + grid_mem = image_memory->memory_size(); } else if(volume_params.resolution != resolution) { VLOG(1) << "Can't create volume mesh, all voxel grid resolutions must be equal\n"; return; } + is_openvdb = (image_memory->grid_type == IMAGE_GRID_TYPE_OPENVDB); + VoxelAttributeGrid voxel_grid; - voxel_grid.data = static_cast<float*>(image_memory->host_pointer); + voxel_grid.data = image_memory->host_pointer; voxel_grid.channels = image_memory->data_elements; - if(grid_info) { - voxel_grid.grid_info = static_cast<int*>(grid_info->host_pointer); - } + voxel_grid.grid_info = grid_info ? static_cast<int*>(grid_info->host_pointer) : NULL; voxel_grids.push_back(voxel_grid); } @@ -484,47 +423,54 @@ void MeshManager::create_volume_mesh(Scene *scene, VolumeMeshBuilder builder(&volume_params); const float isovalue = mesh->volume_isovalue; - for(int z = 0; z < resolution.z; ++z) { - for(int y = 0; y < resolution.y; ++y) { - for(int x = 0; x < resolution.x; ++x) { - for(size_t i = 0; i < voxel_grids.size(); ++i) { - const VoxelAttributeGrid &voxel_grid = voxel_grids[i]; - const int channels = voxel_grid.channels; - const int *grid_info = voxel_grid.grid_info; - int voxel_index; - - if(grid_info) { - if(!using_cuda) { - voxel_index = compute_index(grid_info, x, y, z, - tiled_res.x, - tiled_res.y, - tiled_res.z, - last_tile_res.x, - last_tile_res.y); + for(size_t i = 0; i < voxel_grids.size(); ++i) { + const VoxelAttributeGrid &voxel_grid = voxel_grids[i]; + const int channels = voxel_grid.channels; + + if(is_openvdb) { +#ifdef WITH_OPENVDB + if(channels > 1) { + build_openvdb_mesh_vec(&builder, voxel_grid.data, resolution, isovalue); + } + else { + build_openvdb_mesh_fl(&builder, voxel_grid.data, resolution, isovalue); + } +#else + assert(0); +#endif + } + else { + const int *grid_info = voxel_grid.grid_info; + float *data = static_cast<float*>(voxel_grid.data); + + for(int z = 0; z < resolution.z; ++z) { + for(int y = 0; y < resolution.y; ++y) { + for(int x = 0; x < resolution.x; ++x) { + int voxel_index; + + if(grid_info) { + voxel_index = using_cuda ? + compute_index_cuda(grid_info, x, y, z, + resolution.x, resolution.y, resolution.z, + tiled_res.x, tiled_res.y, tiled_res.z) : + compute_index(grid_info, x, y, z, + tiled_res.x, tiled_res.y, tiled_res.z, + last_tile_res.x, last_tile_res.y); + + if(voxel_index < 0) { + continue; + } } else { - voxel_index = compute_index_cuda(grid_info, - x, y, z, - resolution.x, - resolution.y, - resolution.z, - tiled_res.x, - tiled_res.y, - tiled_res.z); + voxel_index = compute_index(x, y, z, resolution); } - if(voxel_index < 0) { - continue; - } - } - else { - voxel_index = compute_index(x, y, z, resolution); - } - voxel_index *= channels; - for(int c = 0; c < channels; c++) { - if(voxel_grid.data[voxel_index + c] >= isovalue) { - builder.add_node_with_padding(x, y, z); - break; + voxel_index *= channels; + for(int c = 0; c < channels; c++) { + if(data[voxel_index + c] >= isovalue) { + builder.add_node_with_padding(x, y, z); + break; + } } } } @@ -562,9 +508,7 @@ void MeshManager::create_volume_mesh(Scene *scene, << ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0) << "Mb."; - VLOG(1) << "Memory usage volume grid: " - << (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0) - << "Mb."; + VLOG(1) << "Memory usage volume grid: " << grid_mem / (1024.0 * 1024.0) << "Mb."; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh_volume.h b/intern/cycles/render/mesh_volume.h new file mode 100644 index 00000000000..77ed03b5303 --- /dev/null +++ b/intern/cycles/render/mesh_volume.h @@ -0,0 +1,96 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MESH_VOLUME_H__ +#define __MESH_VOLUME_H__ + +#include "util/util_types.h" +#include "util/util_vector.h" + +CCL_NAMESPACE_BEGIN + +struct QuadData { + int v0, v1, v2, v3; + + float3 normal; +}; + +struct VolumeParams { + int3 resolution; + float3 cell_size; + float3 start_point; + int pad_size; +}; + +/* Create a mesh from a volume. + * + * The way the algorithm works is as follows: + * + * - the coordinates of active voxels from a dense volume (or 3d image) are + * gathered inside an auxialliary volume. + * - each set of coordinates of an CUBE_SIZE cube are mapped to the same + * coordinate of the auxilliary volume. + * - quads are created between active and non-active voxels in the auxialliary + * volume to generate a tight mesh around the volume. + */ +class VolumeMeshBuilder { + /* Auxilliary volume that is used to check if a node already added. */ + vector<char> grid; + + /* The resolution of the auxilliary volume, set to be equal to 1/CUBE_SIZE + * of the original volume on each axis. */ + int3 res; + + size_t number_of_nodes; + + /* Offset due to padding in the original grid. Padding will transform the + * coordinates of the original grid from 0...res to -padding...res+padding, + * so some coordinates are negative, and we need to properly account for + * them. */ + int3 pad_offset; + + VolumeParams *params; + +public: + VolumeMeshBuilder(VolumeParams *volume_params); + + void add_node(int x, int y, int z); + + void add_node_with_padding(int x, int y, int z); + + void create_mesh(vector<float3> &vertices, + vector<int> &indices, + vector<float3> &face_normals); + +private: + void generate_vertices_and_quads(vector<int3> &vertices_is, + vector<QuadData> &quads); + + void deduplicate_vertices(vector<int3> &vertices, + vector<QuadData> &quads); + + void convert_object_space(const vector<int3> &vertices, + vector<float3> &out_vertices); + + void convert_quads_to_tris(const vector<QuadData> &quads, + vector<int> &tris, + vector<float3> &face_normals); +}; + +CCL_NAMESPACE_END + +#endif /* __MESH_VOLUME_H__ */ + diff --git a/intern/cycles/render/openvdb.cpp b/intern/cycles/render/openvdb.cpp new file mode 100644 index 00000000000..39992520e94 --- /dev/null +++ b/intern/cycles/render/openvdb.cpp @@ -0,0 +1,235 @@ + +#include <openvdb/openvdb.h> +#include "intern/openvdb_reader.h" +#include "openvdb_capi.h" +#include "render/openvdb.h" + +#include "util/util_logging.h" +#include "util/util_path.h" + +#include "device/device_memory_openvdb.h" + +/* Functions that directly use the OpenVDB library throughout render. */ + +struct OpenVDBReader; + +CCL_NAMESPACE_BEGIN + +static struct OpenVDBReader *get_reader(const string& filepath, + const string& grid_name) +{ + /* Logging is done when metadata is retrieved. */ + if(!path_exists(filepath) || path_is_directory(filepath)) { + return NULL; + } + + struct OpenVDBReader *reader = OpenVDBReader_create(); + OpenVDBReader_open(reader, filepath.c_str()); + + /* If grid name is provided, we also check it's validity here. */ + if(!grid_name.empty()) { + if (!OpenVDBReader_has_grid(reader, grid_name.c_str())) { + VLOG(1) << filepath << " does not have grid " << grid_name; + OpenVDBReader_free(reader); + return NULL; + } + } + + return reader; +} + +static void OpenVDB_import_grid_vector_fl4(OpenVDBReader *reader, + const openvdb::Name &name, + float4 *data, + const int3& resolution) + +{ + using namespace openvdb; + + 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 < resolution.z; ++z) { + for (y = 0; y < resolution.y; ++y) { + for (x = 0; x < resolution.x; ++x, index += 4) { + math::Vec3s value = acc.getValue(xyz); + (*data)[index + 0] = value.x(); + (*data)[index + 1] = value.y(); + (*data)[index + 2] = value.z(); + (*data)[index + 3] = 1.0f; + } + } + } +} + +bool openvdb_has_grid(const string& filepath, const string& grid_name) +{ + return get_reader(filepath, grid_name); +} + +int3 get_openvdb_resolution(const string& filepath) +{ + struct OpenVDBReader *reader = get_reader(filepath, string()); + if(!reader) { + return make_int3(0, 0, 0); + } + + int res[3]; + OpenVDBReader_get_simple_bounds(reader, res); + + OpenVDBReader_free(reader); + + return make_int3(res[0], res[1], res[2]); +} + +/* For now, since there is no official OpenVDB interpolation implementations + * for CUDA or OpenCL, OpenVDB grids can only be saved for CPU rendering. + * Otherwise, we convert the OpenVDB grids to dense arrays. */ + +/* to-do (gschua): handle texture limits. */ + +/* Thread must be locked before file_load_openvdb_cpu() is called. */ +device_memory *file_load_openvdb(Device *device, + const string& filepath, + const string& grid_name, + const int3& resolution, + const string& mem_name, + const InterpolationType& interpolation, + const ExtensionType& extension, + const bool& is_vec, + const int& /*texture_limit*/) +{ + using namespace openvdb; + + struct OpenVDBReader *reader = get_reader(filepath, grid_name); + if(!reader) { + return NULL; + } + + if(is_vec) { + Vec3SGrid::Ptr grid = gridPtrCast<Vec3SGrid>(reader->getGrid(grid_name)); + Vec3SGrid::ConstAccessor accessor = grid->getConstAccessor(); + + device_openvdb<Vec3SGrid, float4> *tex_img = + new device_openvdb<Vec3SGrid, float4>(device, + mem_name.c_str(), + MEM_TEXTURE, + grid, + accessor, + resolution); + tex_img->interpolation = interpolation; + tex_img->extension = extension; + tex_img->grid_type = IMAGE_GRID_TYPE_OPENVDB; + tex_img->copy_to_device(); + + OpenVDBReader_free(reader); + return tex_img; + } + else { + FloatGrid::Ptr grid = gridPtrCast<FloatGrid>(reader->getGrid(grid_name)); + FloatGrid::ConstAccessor accessor = grid->getConstAccessor(); + + device_openvdb<FloatGrid, float> *tex_img = + new device_openvdb<FloatGrid, float>(device, + mem_name.c_str(), + MEM_TEXTURE, + grid, + accessor, + resolution); + + tex_img->interpolation = interpolation; + tex_img->extension = extension; + tex_img->grid_type = IMAGE_GRID_TYPE_OPENVDB; + tex_img->copy_to_device(); + + OpenVDBReader_free(reader); + return tex_img; + } +} + +bool file_load_openvdb_dense(const string& filepath, + const string& grid_name, + const int3& resolution, + const int& /*texture_limit*/, + float *data) +{ + struct OpenVDBReader *reader = get_reader(filepath, grid_name); + if(!reader) { + return false; + } + + int res[3] = {resolution.x, resolution.y, resolution.z}; + OpenVDB_import_grid_fl(reader, grid_name.c_str(), &data, res); + + OpenVDBReader_free(reader); + + return true; +} + +bool file_load_openvdb_dense(const string& filepath, + const string& grid_name, + const int3& resolution, + const int& /*texture_limit*/, + float4 *data) +{ + struct OpenVDBReader *reader = get_reader(filepath, grid_name); + if(!reader) { + return false; + } + + OpenVDB_import_grid_vector_fl4(reader, grid_name, data, resolution); + + OpenVDBReader_free(reader); + + return true; +} + +void build_openvdb_mesh_fl(VolumeMeshBuilder *builder, + void *v_accessor, + const int3 resolution, + const float isovalue) +{ + using namespace openvdb; + + FloatGrid::ConstAccessor *acc = static_cast<FloatGrid::ConstAccessor*>(v_accessor); + math::Coord xyz; + int &x = xyz[0], &y = xyz[1], &z = xyz[2]; + + for (z = 0; z < resolution.z; ++z) { + for (y = 0; y < resolution.y; ++y) { + for (x = 0; x < resolution.x; ++x) { + if(acc->getValue(xyz) >= isovalue) { + builder->add_node_with_padding(x, y, z); + } + } + } + } +} + +void build_openvdb_mesh_vec(VolumeMeshBuilder *builder, + void *v_accessor, + const int3 resolution, + const float isovalue) +{ + using namespace openvdb; + + Vec3SGrid::ConstAccessor *acc = static_cast<Vec3SGrid::ConstAccessor*>(v_accessor); + math::Coord xyz; + int &x = xyz[0], &y = xyz[1], &z = xyz[2]; + + for (z = 0; z < resolution.z; ++z) { + for (y = 0; y < resolution.y; ++y) { + for (x = 0; x < resolution.x; ++x) { + math::Vec3s val = acc->getValue(xyz); + if(val.x() >= isovalue || val.y() >= isovalue || val.z() >= isovalue) { + builder->add_node_with_padding(x, y, z); + } + } + } + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/openvdb.h b/intern/cycles/render/openvdb.h new file mode 100644 index 00000000000..b3d2ad2412f --- /dev/null +++ b/intern/cycles/render/openvdb.h @@ -0,0 +1,49 @@ +#ifndef __IMAGE_OPENVDB_H__ +#define __IMAGE_OPENVDB_H__ + +#include "device/device.h" +#include "render/mesh_volume.h" + +#include "util/util_types.h" +#include "util/util_string.h" + +CCL_NAMESPACE_BEGIN + +bool openvdb_has_grid(const string& filepath, const string& grid_name); +int3 get_openvdb_resolution(const string& filepath); + +device_memory *file_load_openvdb(Device *device, + const string& filepath, + const string& grid_name, + const int3& resolution, + const string& mem_name, + const InterpolationType& interpolation, + const ExtensionType& extension, + const bool& is_vec, + const int& /*texture_limit*/); + +bool file_load_openvdb_dense(const string& filepath, + const string& grid_name, + const int3& resolution, + const int& /*texture_limit*/, + float *data); + +bool file_load_openvdb_dense(const string& filepath, + const string& grid_name, + const int3& resolution, + const int& /*texture_limit*/, + float4 *data); + +void build_openvdb_mesh_fl(VolumeMeshBuilder *builder, + void *v_accessor, + const int3 resolution, + const float isovalue); + +void build_openvdb_mesh_vec(VolumeMeshBuilder *builder, + void *v_accessor, + const int3 resolution, + const float isovalue); + +CCL_NAMESPACE_END + +#endif /* __IMAGE_OPENVDB_H__ */ |