diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2016-11-13 23:42:35 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2016-11-13 23:42:35 +0300 |
commit | 28f4388c2ee815998141f0e4a5a671dec27354e3 (patch) | |
tree | c986f848cde3dec945302943ba1bc47bd07fe6da | |
parent | a7461419d88da1b8aaba17cce96959b33c2c83a9 (diff) | |
parent | 099f7dc9ddb2be02cd7235d74b2c4c49aeb27d56 (diff) |
Merge branch 'cvdb_ray_isect' into openvdb
49 files changed, 1289 insertions, 623 deletions
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index e2197a33e63..f118815099a 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -234,14 +234,6 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) { ustring node_name(node.name()); - if(node_name == "connect") { - else if(string_iequals(node.name(), "openvdb")) { - OpenVDBNode *vdbnode = new OpenVDBNode(); - xml_read_string(&vdbnode->filename, node, "src"); - vdbnode->filename = path_join(state.base, vdbnode->filename); - - snode = vdbnode; - } /* connect nodes */ vector<string> from_tokens, to_tokens; diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index a79deca53e1..3612456f34d 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -33,6 +33,7 @@ set(SRC blender_shader.cpp blender_sync.cpp blender_texture.cpp + blender_volume.cpp CCL_api.h blender_sync.h diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index fab03c7659b..b95365ddf22 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -971,7 +971,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, else create_mesh(scene, mesh, b_mesh, used_shaders, false); - create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); + //create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); } if(render_layer.use_hair && mesh->subdivision_type == Mesh::SUBDIVISION_NONE) diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 0d961c5bf88..cf81c22a856 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -24,6 +24,7 @@ #include "nodes.h" #include "particles.h" #include "shader.h" +#include "volume.h" #include "blender_sync.h" #include "blender_util.h" @@ -73,6 +74,32 @@ bool BlenderSync::object_is_light(BL::Object& b_ob) return (b_ob_data && b_ob_data.is_a(&RNA_Lamp)); } +bool BlenderSync::object_has_sparse_volume(BL::Object& b_ob) +{ + BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); + + if(!b_domain) { + return false; + } + + BL::PointCache b_ptcache = b_domain.point_cache(); + + if (!b_ptcache.is_baked()) { + return false; + } + + if (b_domain.cache_file_format() != BL::SmokeDomainSettings::cache_file_format_OPENVDB) { + return false; + } + + char filename[1024]; + SmokeDomainSettings_cache_filename_get(&b_domain.ptr, filename); + + printf("filename (blender sync): %s\n", filename); + + return strcmp(filename, ""); +} + static uint object_ray_visibility(BL::Object& b_ob) { PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility"); @@ -358,8 +385,15 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0; - /* mesh sync */ - object->mesh = sync_mesh(b_ob, object_updated, hide_tris); + if(object_has_sparse_volume(b_ob)) { + //object->mesh = NULL; + printf("object has sparse volume\n"); + sync_volume(b_ob); + } + /*else*/ { + /* mesh sync */ + object->mesh = sync_mesh(b_ob, object_updated, hide_tris); + } /* special case not tracked by object update flags */ @@ -542,6 +576,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) mesh_map.pre_sync(); object_map.pre_sync(); particle_system_map.pre_sync(); + volume_map.pre_sync(); motion_times.clear(); } else { @@ -676,6 +711,8 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) scene->object_manager->tag_update(scene); if(particle_system_map.post_sync()) scene->particle_system_manager->tag_update(scene); + if(volume_map.post_sync()) + scene->volume_manager->tag_update(scene); } if(motion) diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 4ca202ac40d..f99a4889d34 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -57,6 +57,7 @@ BlenderSync::BlenderSync(BL::RenderEngine& b_engine, mesh_map(&scene->meshes), light_map(&scene->lights), particle_system_map(&scene->particle_systems), + volume_map(&scene->volumes), world_map(NULL), world_recalc(false), scene(scene), @@ -150,6 +151,10 @@ bool BlenderSync::sync_recalc() for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) particle_system_map.set_recalc(*b_ob); } + + if(b_ob->is_updated()) { + volume_map.set_recalc(*b_ob); + } } BL::BlendData::meshes_iterator b_mesh; @@ -184,6 +189,7 @@ bool BlenderSync::sync_recalc() light_map.has_recalc() || mesh_map.has_recalc() || particle_system_map.has_recalc() || + volume_map.has_recalc() || BlendDataObjects_is_updated_get(&b_data.ptr) || world_recalc; diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 9a01b4f2b6e..812c5199b09 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -45,6 +45,7 @@ class Scene; class Shader; class ShaderGraph; class ShaderNode; +class Volume; class BlenderSync { public: @@ -115,6 +116,7 @@ private: BL::Object& b_ob, bool motion, int time_index = 0); + Volume *sync_volume(BL::Object& b_ob); Object *sync_object(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject& b_dupli_ob, @@ -152,6 +154,7 @@ private: bool BKE_object_is_modified(BL::Object& b_ob); bool object_is_mesh(BL::Object& b_ob); bool object_is_light(BL::Object& b_ob); + bool object_has_sparse_volume(BL::Object& b_ob); /* variables */ BL::RenderEngine b_engine; @@ -163,8 +166,10 @@ private: id_map<void*, Mesh> mesh_map; id_map<ObjectKey, Light> light_map; id_map<ParticleSystemKey, ParticleSystem> particle_system_map; + id_map<VolumeKey, Volume> volume_map; set<Mesh*> mesh_synced; set<Mesh*> mesh_motion_synced; + set<Volume*> volume_synced; set<float> motion_times; void *world_map; bool world_recalc; diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index f17a61f0ac8..c729f5f2a35 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -781,6 +781,26 @@ struct ParticleSystemKey { } }; +/* Volume Key */ + +/* XXX For now we just use Object ID as a volume key; + * Volumes may become a true ID block in Blender later, + * or the key can be augmented to distinguish multiple volumes inside the same object. + */ +struct VolumeKey { + void *ob; + + VolumeKey(void *ob_) + : ob(ob_) + { + } + + bool operator<(const VolumeKey& k) const + { + return ob < k.ob; + } +}; + CCL_NAMESPACE_END #endif /* __BLENDER_UTIL_H__ */ diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp new file mode 100644 index 00000000000..5c25668db6b --- /dev/null +++ b/intern/cycles/blender/blender_volume.cpp @@ -0,0 +1,201 @@ +/* + * Copyright 2011-2016 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. + */ + +#include "blender_sync.h" + +#include "attribute.h" +#include "../render/volume.h" + +#include "util_foreach.h" + +#include <openvdb/openvdb.h> + +CCL_NAMESPACE_BEGIN + +static Attribute *get_openvdb_attribute(Volume *volume, const string& filename, const ustring& name) +{ + Attribute *attr = NULL; + + openvdb::initialize(); + + openvdb::io::File file(filename); + file.open(); + + openvdb::GridBase::ConstPtr grid = file.readGrid(name.string()); + + openvdb::Name value_type = grid->valueType(); + + if(value_type == "float") { + attr = volume->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL); + fprintf(stderr, "Adding volume attribute: %s\n", name.string().c_str()); + } + else if(value_type == "vec3s") { + if (grid->getMetadata< openvdb::TypedMetadata<bool> >("is_color")) { + attr = volume->attributes.add(name, TypeDesc::TypeColor, ATTR_ELEMENT_VOXEL); + fprintf(stderr, "Adding volume attribute: %s\n", name.string().c_str()); + } + else { + attr = volume->attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_VOXEL); + fprintf(stderr, "Adding volume attribute: %s\n", name.string().c_str()); + } + } + else { + fprintf(stderr, "Skipping volume attribute: %s\n", name.string().c_str()); + } + + return attr; +} + +static void create_volume_attribute(BL::Object& b_ob, + Volume *volume, + VolumeManager *volume_manager, + const ustring& name, + float /*frame*/) +{ + BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); + + if(!b_domain) { + fprintf(stderr, "No domain found!\n"); + return; + } + + char filename[1024]; + SmokeDomainSettings_cache_filename_get(&b_domain.ptr, filename); + + Attribute *attr = get_openvdb_attribute(volume, filename, name); + VoxelAttribute *volume_data = attr->data_voxel(); + int slot = volume_manager->add_volume(volume, filename, name.string()); + + if (!volume_data) { + fprintf(stderr, "Failed to create volume data!\n"); + } + + // TODO(kevin): add volume fields to the Volume* +// volume_data->manager = volume_manager; + volume_data->slot = slot; +} + +static void create_volume_attributes(Scene *scene, + BL::Object& b_ob, + Volume *volume, + float frame) +{ + foreach(Shader *shader, volume->used_shaders) { + fprintf(stderr, "Number of attribute requests: %lu\n", shader->attributes.requests.size()); + + foreach(AttributeRequest req, shader->attributes.requests) { + ustring name; + + if (req.std == ATTR_STD_VOLUME_DENSITY) { + name = ustring(Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)); + } + else if (req.std == ATTR_STD_VOLUME_FLAME) { + name = ustring(Attribute::standard_name(ATTR_STD_VOLUME_FLAME)); + } + else if (req.std == ATTR_STD_VOLUME_COLOR) { + name = ustring(Attribute::standard_name(ATTR_STD_VOLUME_COLOR)); + } + else if (req.std == ATTR_STD_VOLUME_VELOCITY) { + name = ustring(Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)); + } + else if (req.std == ATTR_STD_VOLUME_HEAT) { + name = ustring(Attribute::standard_name(ATTR_STD_VOLUME_HEAT)); + } + else if (req.name != "") { + name = req.name; + } + else { + continue; + } + + create_volume_attribute(b_ob, volume, scene->volume_manager, name, frame); + } + } +} + +Volume *BlenderSync::sync_volume(BL::Object &b_ob) +{ + BL::ID key = b_ob; + BL::Material material_override = render_layer.material_override; + + /* find shader indices */ + vector<Shader*> used_shaders; + BL::ID b_ob_data = b_ob.data(); + + fprintf(stderr, "%s: before material assignment\n", __func__); + + BL::Object::material_slots_iterator slot; + for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { + if(material_override) { + find_shader(material_override, used_shaders, scene->default_volume); + } + else { + BL::ID b_material(slot->material()); + find_shader(b_material, used_shaders, scene->default_volume); + } + } + + if(used_shaders.size() == 0) { + if(material_override) + find_shader(material_override, used_shaders, scene->default_volume); + else + used_shaders.push_back(scene->default_volume); + } + + fprintf(stderr, "%s: after material assignment\n", __func__); + + Volume *volume; + + if(!volume_map.sync(&volume, key)) { + /* test if shaders changed, these can be object level so mesh + * does not get tagged for recalc */ + if(volume->used_shaders != used_shaders); + else { + /* even if not tagged for recalc, we may need to sync anyway + * because the shader needs different volume attributes */ + bool attribute_recalc = false; + + foreach(Shader *shader, volume->used_shaders) + if(shader->need_update_attributes) + attribute_recalc = true; + + if(!attribute_recalc) + return volume; + } + } + + /* ensure we only sync instanced meshes once */ + if(volume_synced.find(volume) != volume_synced.end()) + return volume; + + volume_synced.insert(volume); + + volume->used_shaders = used_shaders; + volume->name = ustring(b_ob_data.name().c_str()); + + fprintf(stderr, "Number of shaders: %lu\n", volume->used_shaders.size()); + + create_volume_attributes(scene, b_ob, volume, b_scene.frame_current()); + + /* tag update */ + bool rebuild = false; + + volume->tag_update(scene, rebuild); + + return volume; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt index 966ff5e52ba..091bb767162 100644 --- a/intern/cycles/device/CMakeLists.txt +++ b/intern/cycles/device/CMakeLists.txt @@ -4,6 +4,7 @@ set(INC ../graph ../kernel ../kernel/svm + ../kernel/openvdb ../kernel/osl ../util ../render diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 77dc1fa9713..d990218a931 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -34,6 +34,8 @@ CCL_NAMESPACE_BEGIN class Progress; class RenderTile; +struct OpenVDBGlobals; + /* Device Types */ enum DeviceType { @@ -249,6 +251,9 @@ public: /* open shading language, only for CPU device */ virtual void *osl_memory() { return NULL; } + /* OpenVDB data */ + virtual OpenVDBGlobals *vdb_memory() { return NULL; } + /* load/compile kernels, must be called before adding tasks */ virtual bool load_kernels( const DeviceRequestedFeatures& /*requested_features*/) diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index aed86d8d853..fe870b1587f 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -35,6 +35,11 @@ #include "osl_shader.h" #include "osl_globals.h" +#ifdef WITH_OPENVDB +#include "vdb_globals.h" +#include "vdb_thread.h" +#endif + #include "buffers.h" #include "util_debug.h" @@ -57,7 +62,11 @@ public: #ifdef WITH_OSL OSLGlobals osl_globals; #endif - + +#ifdef WITH_OPENVDB + OpenVDBGlobals vdb_globals; +#endif + CPUDevice(DeviceInfo& info, Stats &stats, bool background) : Device(info, stats, background) { @@ -189,6 +198,15 @@ public: #endif } + OpenVDBGlobals *vdb_memory() + { +#ifdef WITH_OPENVDB + return &vdb_globals; +#else + return NULL; +#endif + } + void thread_run(DeviceTask *task) { if(task->type == DeviceTask::PATH_TRACE) @@ -385,6 +403,10 @@ public: #ifdef WITH_OSL OSLShader::thread_init(&kg, &kernel_globals, &osl_globals); #endif +#ifdef WITH_OPENVDB + vdb_thread_init(&kg, &kernel_globals, &vdb_globals); +#endif + void(*shader_kernel)(KernelGlobals*, uint4*, float4*, float*, int, int, int, int, int); #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 @@ -443,6 +465,9 @@ public: #ifdef WITH_OSL OSLShader::thread_free(&kg); #endif +#ifdef WITH_OPENVDB + vdb_thread_free(&kg); +#endif } int get_split_task_count(DeviceTask& task) @@ -491,6 +516,9 @@ protected: #ifdef WITH_OSL OSLShader::thread_init(&kg, &kernel_globals, &osl_globals); #endif +#ifdef WITH_OPENVDB + vdb_thread_init(&kg, &kernel_globals, &vdb_globals); +#endif return kg; } @@ -509,6 +537,9 @@ protected: #ifdef WITH_OSL OSLShader::thread_free(kg); #endif +#ifdef WITH_OPENVDB + vdb_thread_free(kg); +#endif } }; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 7a9b8280ca9..2c95825435d 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -302,6 +302,18 @@ if(WITH_CYCLES_OSL) add_subdirectory(shaders) endif() +# OpenVDB module + +list(APPEND SRC + openvdb/vdb_thread.cpp + ) + +list(APPEND SRC_HEADERS + openvdb/vdb_globals.h + openvdb/vdb_thread.h + openvdb/vdb_intern.h + ) + # CPU module include_directories(${INC}) diff --git a/intern/cycles/kernel/bvh/bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h index 107373c17dc..f6db399080b 100644 --- a/intern/cycles/kernel/bvh/bvh_volume.h +++ b/intern/cycles/kernel/bvh/bvh_volume.h @@ -100,6 +100,24 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); +#if 1 + /* try to intersect with VDB volumes */ + int num_volumes = kernel_data.tables.num_volumes; + + for(int i = 0; i < num_volumes; i++) { + float t; + + if(vdb_volume_intersect(kg->vdb_tdata, i, ray, &t)) { + isect->type = PRIMITIVE_VOLUME; + isect->prim = i; + isect->t = t; + isect->u = 1.0f; + isect->v = 1.0f; + return true; + } + } +#endif + /* traversal loop */ do { do { diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h index 529848ebe7b..04fe6e02b15 100644 --- a/intern/cycles/kernel/bvh/bvh_volume_all.h +++ b/intern/cycles/kernel/bvh/bvh_volume_all.h @@ -101,6 +101,33 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); #endif /* __KERNEL_SSE2__ */ +#if 1 + /* try to intersect with VDB volumes */ + int num_volumes = kernel_data.tables.num_volumes; + + for(int i = 0; i < num_volumes; i++) { + float t; + + if(vdb_volume_intersect(kg->vdb_tdata, i, ray, &t)) { + isect_array->type = PRIMITIVE_VOLUME; + isect_array->prim = i; + isect_array->t = t; + isect_array->u = 1.0f; + isect_array->v = 1.0f; + isect_array++; + num_hits++; + + if(num_hits == max_hits) { + return num_hits; + } + } + } + + if(num_hits > 0) { + return num_hits; + } +#endif + IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); diff --git a/intern/cycles/kernel/bvh/qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h index 424710b69f2..989873b549b 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume.h +++ b/intern/cycles/kernel/bvh/qbvh_volume.h @@ -94,6 +94,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); +#if 1 + /* try to intersect with VDB volumes */ + int num_volumes = kernel_data.tables.num_volumes; + + for(int i = 0; i < num_volumes; i++) { + float t; + + if(vdb_volume_intersect(kg->vdb_tdata, i, ray, &t)) { + isect->type = PRIMITIVE_VOLUME; + isect->prim = i; + isect->t = t; + isect->u = 1.0f; + isect->v = 1.0f; + return true; + } + } +#endif + /* Traversal loop. */ do { do { diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index eb48af6fc68..87bbca5d85c 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -98,6 +98,33 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); +#if 1 + /* try to intersect with VDB volumes */ + int num_volumes = kernel_data.tables.num_volumes; + + for(int i = 0; i < num_volumes; i++) { + float t; + + if(vdb_volume_intersect(kg->vdb_tdata, i, ray, &t)) { + isect_array->type = PRIMITIVE_VOLUME; + isect_array->prim = i; + isect_array->t = t; + isect_array->u = 1.0f; + isect_array->v = 1.0f; + isect_array++; + num_hits++; + + if(num_hits == max_hits) { + return num_hits; + } + } + } + + if(num_hits > 0) { + return num_hits; + } +#endif + /* Traversal loop. */ do { do { diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h index 4384c2093e9..dbf0b804b5d 100644 --- a/intern/cycles/kernel/geom/geom_primitive.h +++ b/intern/cycles/kernel/geom/geom_primitive.h @@ -40,7 +40,7 @@ ccl_device_inline float primitive_attribute_float(KernelGlobals *kg, } #endif #ifdef __VOLUME__ - else if(ccl_fetch(sd, object) != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) { + else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_VOLUME) { return volume_attribute_float(kg, sd, desc, dx, dy); } #endif @@ -68,7 +68,7 @@ ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg, } #endif #ifdef __VOLUME__ - else if(ccl_fetch(sd, object) != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) { + else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_VOLUME) { return volume_attribute_float3(kg, sd, desc, dx, dy); } #endif diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h index 03724c955be..8274d19aba2 100644 --- a/intern/cycles/kernel/geom/geom_volume.h +++ b/intern/cycles/kernel/geom/geom_volume.h @@ -77,10 +77,12 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P.x, P.y, P.z); #else float4 r; - if(sd->flag & SD_VOLUME_CUBIC) - r = kernel_tex_image_interp_3d_ex(desc.offset, P.x, P.y, P.z, INTERPOLATION_CUBIC); - else - r = kernel_tex_image_interp_3d(desc.offset, P.x, P.y, P.z); +// if(sd->flag & SD_VOLUME_CUBIC) +// r = kernel_tex_image_interp_3d_ex(desc.offset, P.x, P.y, P.z, INTERPOLATION_CUBIC); +// else +// r = kernel_tex_image_interp_3d(desc.offset, P.x, P.y, P.z); + + return kernel_tex_voxel_float(desc.offset, P.x, P.y, P.z, OPENVDB_SAMPLE_POINT); #endif if(dx) *dx = 0.0f; diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h index d8256cdebf5..d51a0c59fa4 100644 --- a/intern/cycles/kernel/kernel_compat_cpu.h +++ b/intern/cycles/kernel/kernel_compat_cpu.h @@ -525,12 +525,11 @@ typedef texture_image<half4> texture_image_half4; #define kernel_tex_fetch_ssef(tex, index) (kg->tex.fetch_ssef(index)) #define kernel_tex_fetch_ssei(tex, index) (kg->tex.fetch_ssei(index)) #define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size)) - #define kernel_tex_image_interp(tex,x,y) kernel_tex_image_interp_impl(kg,tex,x,y) #define kernel_tex_image_interp_3d(tex, x, y, z) kernel_tex_image_interp_3d_impl(kg,tex,x,y,z) #define kernel_tex_image_interp_3d_ex(tex, x, y, z, interpolation) kernel_tex_image_interp_3d_ex_impl(kg,tex, x, y, z, interpolation) -#define kernel_tex_voxel_float(tex, x, y, z, sampling) (kg->float_volumes[tex]->sample(x, y, z, sampling)) -#define kernel_tex_voxel_float3(tex, x, y, z, sampling) (kg->float3_volumes[tex]->sample(x, y, z, sampling)) +#define kernel_tex_voxel_float(tex, x, y, z, sampling) (vdb_volume_sample_scalar(kg->vdb, kg->vdb_tdata, tex, x, y, z, sampling)) +#define kernel_tex_voxel_float3(tex, x, y, z, sampling) (vdb_volume_sample_vector(kg->vdb, kg->vdb_tdata, tex, x, y, z, sampling)) #define kernel_data (kg->__data) diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index d8c4b7c71e4..74357bd96fc 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -31,6 +31,11 @@ struct OSLThreadData; struct OSLShadingSystem; # endif +# ifdef WITH_OPENVDB +struct OpenVDBGlobals; +struct OpenVDBThreadData; +# endif + struct Intersection; struct VolumeStep; @@ -44,9 +49,6 @@ typedef struct KernelGlobals { texture_image_uchar texture_byte_images[TEX_NUM_BYTE_CPU]; texture_image_half texture_half_images[TEX_NUM_HALF_CPU]; - float_volume *float_volumes[MAX_VOLUME]; - float3_volume *float3_volumes[MAX_VOLUME]; - # define KERNEL_TEX(type, ttype, name) ttype name; # define KERNEL_IMAGE_TEX(type, ttype, name) # include "kernel_textures.h" @@ -69,6 +71,11 @@ typedef struct KernelGlobals { /* Storage for decoupled volume steps. */ VolumeStep *decoupled_volume_steps[2]; int decoupled_volume_steps_index; + +# ifdef WITH_OPENVDB + OpenVDBGlobals *vdb; + OpenVDBThreadData *vdb_tdata; +# endif } KernelGlobals; #endif /* __KERNEL_CPU__ */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index a8070a133de..652612c19db 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -67,7 +67,13 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg, ccl_fetch(sd, time) = ray->time; #endif - ccl_fetch(sd, prim) = kernel_tex_fetch(__prim_index, isect->prim); + if(ccl_fetch(sd, type) & PRIMITIVE_VOLUME) { + ccl_fetch(sd, prim) = isect->prim; + } + else { + ccl_fetch(sd, prim) = kernel_tex_fetch(__prim_index, isect->prim); + } + ccl_fetch(sd, ray_length) = isect->t; #ifdef __UV__ @@ -104,6 +110,9 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg, triangle_dPdudv(kg, ccl_fetch(sd, prim), &ccl_fetch(sd, dPdu), &ccl_fetch(sd, dPdv)); #endif } + else if(ccl_fetch(sd, type) & PRIMITIVE_VOLUME) { + ccl_fetch(sd, shader) = kernel_tex_fetch(__vol_shader, ccl_fetch(sd, prim)); + } else { /* motion triangle */ motion_triangle_shader_setup(kg, sd, isect, ray, false); @@ -432,7 +441,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s sd->object = PRIM_NONE; /* todo: fill this for texture coordinates */ #endif sd->prim = PRIM_NONE; - sd->type = PRIMITIVE_NONE; + sd->type = PRIMITIVE_VOLUME; #ifdef __UV__ sd->u = 0.0f; diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 8d5bb75a428..65aeea18336 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -77,6 +77,9 @@ KERNEL_TEX(float, texture_float, __lookup_table) /* sobol */ KERNEL_TEX(uint, texture_uint, __sobol_directions) +/* volume */ +KERNEL_TEX(uint, texture_uint, __vol_shader) + #ifdef __KERNEL_CUDA__ # if __CUDA_ARCH__ < 300 /* full-float image */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 8220934312b..96f2dd1be2c 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -557,11 +557,13 @@ typedef enum PrimitiveType { PRIMITIVE_MOTION_CURVE = 8, /* Lamp primitive is not included below on purpose, since it is no real traceable primitive */ PRIMITIVE_LAMP = 16, + PRIMITIVE_VOLUME = 32, PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE|PRIMITIVE_MOTION_TRIANGLE), PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE|PRIMITIVE_MOTION_CURVE), PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE|PRIMITIVE_MOTION_CURVE), - PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE|PRIMITIVE_ALL_CURVE), + PRIMITIVE_ALL_VOLUME = (PRIMITIVE_VOLUME), + PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE|PRIMITIVE_ALL_CURVE|PRIMITIVE_ALL_VOLUME), /* Total number of different primitives. * NOTE: This is an actual value, not a bitflag. @@ -845,6 +847,7 @@ typedef ccl_addr_space struct ShaderData { typedef struct VolumeStack { int object; int shader; + int volume; } VolumeStack; #endif diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index f0e9b68a9a4..e973afe79eb 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "openvdb/vdb_thread.h" + CCL_NAMESPACE_BEGIN /* Events for probalistic scattering */ @@ -220,24 +222,33 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, PathState float3 sum = make_float3(0.0f, 0.0f, 0.0f); #ifdef __OPENVDB__ - int vdb_index = kernel_data.tables.density_index; - bool has_vdb_volume = kernel_data.tables.num_volumes > 0; +// int density_index = kernel_data.tables.density_index; + int num_volumes = kernel_data.tables.num_volumes; + bool has_vdb_volume = num_volumes > 0; float t1 = 0.0f; + int v = 0; + + float isec_t = 0.0f; + for(; v < num_volumes; v++) { + if(vdb_volume_intersect(kg->vdb_tdata, v, ray, &isec_t)) { + break; + } + } - if(has_vdb_volume && vdb_index >= 0 && kg->float_volumes[vdb_index]->has_uniform_voxels()) { + if(has_vdb_volume && v < num_volumes && vdb_volume_scalar_has_uniform_voxels(kg->vdb, v)) { /* TODO(kevin): this call should be moved out of here, all it does is * checking if we have an intersection with the boundbox of the volumue * which in most cases corresponds to the boundbox of the object that has * this volume. Also it initializes the rays for the ray marching. */ - if(!kg->float_volumes[vdb_index]->intersect(ray, NULL)) { - return; - } + //if(!vdb_volume_intersect(kg->vdb_tdata, density_index, ray, NULL)) { + // return; + //} /* t and t1 represent the entry and exit points for each leaf node or tile * containing active voxels. If we don't have any active node in the current * ray path (i.e. empty space) the ray march loop is not executed, * otherwise we loop through all leaves until the end of the volume. */ - while(kg->float_volumes[vdb_index]->march(&t, &t1)) { + while(vdb_volume_march(kg->vdb_tdata, v, &t, &t1)) { int i = 0; /* Perform small steps through the current leaf or tile. */ @@ -619,24 +630,33 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( bool path_missed = true; #ifdef __OPENVDB__ +// int density_index = kernel_data.tables.density_index; + int num_volumes = kernel_data.tables.num_volumes; + bool has_vdb_volume = num_volumes > 0; float t1 = 0.0f; - int vdb_index = kernel_data.tables.density_index; - bool has_vdb_volume = kernel_data.tables.num_volumes > 0; + int i; - if(has_vdb_volume && vdb_index >= 0 && kg->float_volumes[vdb_index]->has_uniform_voxels()) { + for(i = 0; i < num_volumes; i++) { + float isec_t = 0.0f; + if(vdb_volume_intersect(kg->vdb_tdata, i, ray, &isec_t)) { + break; + } + } + + if(has_vdb_volume /*&& i >= 0*/ && vdb_volume_scalar_has_uniform_voxels(kg->vdb, i)) { /* TODO(kevin): this call should be moved out of here, all it does is * checking if we have an intersection with the boundbox of the volumue * which in most cases corresponds to the boundbox of the object that has * this volume. Also it initializes the rays for the ray marching. */ - if(!kg->float_volumes[vdb_index]->intersect(ray, NULL)) { - return VOLUME_PATH_MISSED; - } + //if(!vdb_volume_intersect(kg->vdb_tdata, density_index, ray, NULL)) { + // return VOLUME_PATH_MISSED; + //} /* t and t1 represent the entry and exit points for each leaf node or tile * containing active voxels. If we don't have any active node in the current * ray path (i.e. empty space) the ray march loop is not executed, * otherwise we loop through all leaves until the end of the volume. */ - while(kg->float_volumes[vdb_index]->march(&t, &t1)) { + while(vdb_volume_march(kg->vdb_tdata, i, &t, &t1)) { path_missed = false; /* Perform small steps through the current leaf or tile. */ @@ -800,16 +820,17 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta VolumeStep *step = segment->steps; #ifdef __OPENVDB__ - int vdb_index = kernel_data.tables.density_index; + int density_index = kernel_data.tables.density_index; bool has_vdb_volume = kernel_data.tables.num_volumes > 0; float t1 = 0.0f; - if(has_vdb_volume && kg->float_volumes[vdb_index]->has_uniform_voxels()) { + if(has_vdb_volume && vdb_volume_scalar_has_uniform_voxels(kg->vdb, density_index)) { /* TODO(kevin): this call should be moved out of here, all it does is * checking if we have an intersection with the boundbox of the volumue * which in most cases corresponds to the boundbox of the object that has * this volume. Also it initializes the rays for the ray marching. */ - if(!kg->float_volumes[vdb_index]->intersect(ray, NULL)) { + float isect_t = 0.0f; + if(!vdb_volume_intersect(kg->vdb_tdata, density_index, ray, &isect_t)) { return; } @@ -817,7 +838,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta * containing active voxels. If we don't have any active node in the current * ray path (i.e. empty space) the ray march loop is not executed, * otherwise we loop through all leaves until the end of the volume. */ - while(kg->float_volumes[vdb_index]->march(&t, &t1)) { + while(vdb_volume_march(kg->vdb_tdata, density_index, &t, &t1)) { /* Perform small steps through the current leaf or tile. */ for(float new_t = step_size * ceilf(t / step_size); new_t <= t1; new_t += step_size, step++) { @@ -1339,6 +1360,7 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg, if(need_add) { stack[stack_index].object = stack_sd->object; stack[stack_index].shader = stack_sd->shader; + stack[stack_index].volume = stack_sd->prim; ++stack_index; } } diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp index b530e980fe6..72dbbd9a416 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp @@ -68,10 +68,6 @@ void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t s { if(strcmp(name, "__data") == 0) memcpy(&kg->__data, host, size); - else if(strcmp(name, "__float_volume") == 0) - kg->float_volumes[size] = (float_volume *)host; - else if(strcmp(name, "__float3_volume") == 0) - kg->float3_volumes[size] = (float3_volume *)host; else assert(0); } diff --git a/intern/cycles/kernel/openvdb/vdb_globals.h b/intern/cycles/kernel/openvdb/vdb_globals.h new file mode 100644 index 00000000000..771c7f833e5 --- /dev/null +++ b/intern/cycles/kernel/openvdb/vdb_globals.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016 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 __VDB_GLOBALS_H__ +#define __VDB_GLOBALS_H__ + +#include "vdb_intern.h" + +CCL_NAMESPACE_BEGIN + +typedef openvdb::math::Ray<float> vdb_ray_t; +typedef openvdb::math::Transform vdb_transform_t; + +struct OpenVDBGlobals { + typedef openvdb::FloatGrid scalar_grid_t; + typedef openvdb::Vec3SGrid vector_grid_t; + typedef openvdb::tools::VolumeRayIntersector<scalar_grid_t, scalar_grid_t::TreeType::RootNodeType::ChildNodeType::LEVEL, vdb_ray_t> scalar_isector_t; + typedef openvdb::tools::VolumeRayIntersector<vector_grid_t, vector_grid_t::TreeType::RootNodeType::ChildNodeType::LEVEL, vdb_ray_t> vector_isector_t; + + vector<const scalar_grid_t *> scalar_grids; + vector<const vector_grid_t *> vector_grids; + /* Main intersectors, which initialize the voxels' bounding box + * so the ones for the various threads do not do this, + * rather they are generated from a copy of these + */ + vector<scalar_isector_t *> scalar_main_isectors; + vector<vector_isector_t *> vector_main_isectors; +}; + +CCL_NAMESPACE_END + +#endif /* __VDB_GLOBALS_H__ */ diff --git a/intern/cycles/kernel/openvdb/vdb_intern.h b/intern/cycles/kernel/openvdb/vdb_intern.h new file mode 100644 index 00000000000..71d6b81e0ff --- /dev/null +++ b/intern/cycles/kernel/openvdb/vdb_intern.h @@ -0,0 +1,48 @@ +/* + * Copyright 2016 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 __VDB_INTERN_H__ +#define __VDB_INTERN_H__ + +/* They are too many implicit float conversions happening in OpenVDB, disabling + * errors for now (kevin) */ +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-conversion" +# pragma GCC diagnostic ignored "-Wdouble-promotion" +#endif + +#include <openvdb/openvdb.h> +#include <openvdb/tools/Interpolation.h> +#include <openvdb/tools/RayIntersector.h> + +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif + +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +#if defined(HAS_CPP11_FEATURES) +using std::isfinite; +#else +using boost::math::isfinite; +#endif + +CCL_NAMESPACE_END + +#endif /* __VDB_INTERN_H__ */ diff --git a/intern/cycles/kernel/openvdb/vdb_thread.cpp b/intern/cycles/kernel/openvdb/vdb_thread.cpp new file mode 100644 index 00000000000..5a65dc94737 --- /dev/null +++ b/intern/cycles/kernel/openvdb/vdb_thread.cpp @@ -0,0 +1,216 @@ +/* + * Copyright 2016 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. + */ + +#include "kernel_compat_cpu.h" +#include "kernel_types.h" +#include "kernel_globals.h" + +#include "vdb_globals.h" +#include "vdb_intern.h" +#include "vdb_thread.h" + +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +/* Manage thread-local data associated with volumes */ + +struct OpenVDBScalarThreadData { + typedef openvdb::FloatGrid grid_t; + typedef openvdb::FloatGrid::ConstAccessor accessor_t; + typedef openvdb::tools::GridSampler<accessor_t, openvdb::tools::PointSampler> point_sampler_t; + typedef openvdb::tools::GridSampler<accessor_t, openvdb::tools::BoxSampler> box_sampler_t; + typedef openvdb::tools::VolumeRayIntersector<grid_t, grid_t::TreeType::RootNodeType::ChildNodeType::LEVEL, vdb_ray_t> isector_t; + + void init(const grid_t &grid, const isector_t &main_isector) + { + accessor = new accessor_t(grid.getConstAccessor()); + point_sampler = new point_sampler_t(*accessor, grid.transform()); + box_sampler = new box_sampler_t(*accessor, grid.transform()); + isector = new isector_t(main_isector); + } + + void free() + { + delete accessor; + delete point_sampler; + delete box_sampler; + delete isector; + } + + accessor_t *accessor; + point_sampler_t *point_sampler; + box_sampler_t *box_sampler; + isector_t *isector; +}; + +struct OpenVDBVectorThreadData { + typedef openvdb::Vec3SGrid grid_t; + typedef openvdb::Vec3SGrid::ConstAccessor accessor_t; + typedef openvdb::tools::GridSampler<accessor_t, openvdb::tools::PointSampler> point_sampler_t; + typedef openvdb::tools::GridSampler<accessor_t, openvdb::tools::BoxSampler> box_sampler_t; + typedef openvdb::tools::GridSampler<accessor_t, openvdb::tools::StaggeredPointSampler> stag_point_sampler_t; + typedef openvdb::tools::GridSampler<accessor_t, openvdb::tools::StaggeredBoxSampler> stag_box_sampler_t; + + typedef openvdb::tools::VolumeRayIntersector<grid_t, grid_t::TreeType::RootNodeType::ChildNodeType::LEVEL, vdb_ray_t> isector_t; + + void init (const grid_t &grid, const isector_t &main_isector) + { + accessor = new accessor_t(grid.getConstAccessor()); + point_sampler = new point_sampler_t(*accessor, grid.transform()); + box_sampler = new box_sampler_t(*accessor, grid.transform()); + stag_point_sampler = new stag_point_sampler_t(*accessor, grid.transform()); + stag_box_sampler = new stag_box_sampler_t(*accessor, grid.transform()); + isector = new isector_t(main_isector); + } + + void free() + { + delete accessor; + delete point_sampler; + delete box_sampler; + delete stag_point_sampler; + delete stag_box_sampler; + delete isector; + } + + accessor_t *accessor; + point_sampler_t *point_sampler; + box_sampler_t *box_sampler; + stag_point_sampler_t *stag_point_sampler; + stag_box_sampler_t *stag_box_sampler; + isector_t *isector; +}; + +struct OpenVDBThreadData { + std::vector<OpenVDBScalarThreadData> scalar_data; + std::vector<OpenVDBVectorThreadData> vector_data; +}; + +void vdb_thread_init(KernelGlobals *kg, const KernelGlobals *kernel_globals, OpenVDBGlobals *vdb_globals) +{ + kg->vdb = vdb_globals; + + OpenVDBThreadData *tdata = new OpenVDBThreadData; + + tdata->scalar_data.resize(vdb_globals->scalar_grids.size()); + tdata->vector_data.resize(vdb_globals->vector_grids.size()); + for (size_t i = 0; i < vdb_globals->scalar_grids.size(); ++i) { + tdata->scalar_data[i].init(*vdb_globals->scalar_grids[i], *vdb_globals->scalar_main_isectors[i]); + } + for (size_t i = 0; i < vdb_globals->vector_grids.size(); ++i) { + tdata->vector_data[i].init(*vdb_globals->vector_grids[i], *vdb_globals->vector_main_isectors[i]); + } + kg->vdb_tdata = tdata; +} + +void vdb_thread_free(KernelGlobals *kg) +{ + OpenVDBThreadData *tdata = kg->vdb_tdata; + kg->vdb_tdata = NULL; + + for (size_t i = 0; i < tdata->scalar_data.size(); ++i) { + tdata->scalar_data[i].free(); + } + for (size_t i = 0; i < tdata->vector_data.size(); ++i) { + tdata->vector_data[i].free(); + } + delete tdata; +} + +bool vdb_volume_scalar_has_uniform_voxels(OpenVDBGlobals *vdb, int vdb_index) +{ + return vdb->scalar_grids[vdb_index]->hasUniformVoxels(); +} + +bool vdb_volume_vector_has_uniform_voxels(OpenVDBGlobals *vdb, int vdb_index) +{ + return vdb->vector_grids[vdb_index]->hasUniformVoxels(); +} + +float vdb_volume_sample_scalar(OpenVDBGlobals */*vdb*/, OpenVDBThreadData *vdb_thread, int vdb_index, + float x, float y, float z, int sampling) +{ + OpenVDBScalarThreadData &data = vdb_thread->scalar_data[vdb_index]; + + if (sampling == OPENVDB_SAMPLE_POINT) + return data.point_sampler->wsSample(openvdb::Vec3d(x, y, z)); + else + return data.box_sampler->wsSample(openvdb::Vec3d(x, y, z)); +} + +float3 vdb_volume_sample_vector(OpenVDBGlobals *vdb, OpenVDBThreadData *vdb_thread, int vdb_index, + float x, float y, float z, int sampling) +{ + bool staggered = (vdb->vector_grids[vdb_index]->getGridClass() == openvdb::GRID_STAGGERED); + OpenVDBVectorThreadData &data = vdb_thread->vector_data[vdb_index]; + openvdb::Vec3s r; + + if (staggered) { + if (sampling == OPENVDB_SAMPLE_POINT) + r = data.stag_point_sampler->wsSample(openvdb::Vec3d(x, y, z)); + else + r = data.stag_box_sampler->wsSample(openvdb::Vec3d(x, y, z)); + } + else { + if (sampling == OPENVDB_SAMPLE_POINT) + r = data.point_sampler->wsSample(openvdb::Vec3d(x, y, z)); + else + r = data.box_sampler->wsSample(openvdb::Vec3d(x, y, z)); + } + + return make_float3(r.x(), r.y(), r.z()); +} + +bool vdb_volume_intersect(OpenVDBThreadData *vdb_thread, int vdb_index, + const Ray *ray, float *isect) +{ + OpenVDBScalarThreadData &data = vdb_thread->scalar_data[vdb_index]; + + vdb_ray_t::Vec3Type P(ray->P.x, ray->P.y, ray->P.z); + vdb_ray_t::Vec3Type D(ray->D.x, ray->D.y, ray->D.z); + D.normalize(); + + vdb_ray_t vdb_ray(P, D, 1e-5f, ray->t); + + if(data.isector->setWorldRay(vdb_ray)) { + // TODO(kevin): is this correct? + *isect = static_cast<float>(vdb_ray.t1()); + + return true; + } + + return false; +} + +bool vdb_volume_march(OpenVDBThreadData *vdb_thread, int vdb_index, + float *t0, float *t1) +{ + OpenVDBScalarThreadData &data = vdb_thread->scalar_data[vdb_index]; + + float vdb_t0(*t0), vdb_t1(*t1); + + if(data.isector->march(vdb_t0, vdb_t1)) { + *t0 = data.isector->getWorldTime(vdb_t0); + *t1 = data.isector->getWorldTime(vdb_t1); + + return true; + } + + return false; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/openvdb/vdb_thread.h b/intern/cycles/kernel/openvdb/vdb_thread.h new file mode 100644 index 00000000000..26ef8f194c5 --- /dev/null +++ b/intern/cycles/kernel/openvdb/vdb_thread.h @@ -0,0 +1,49 @@ +/* + * Copyright 2016 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 __VDB_THREAD_H__ +#define __VDB_THREAD_H__ + +CCL_NAMESPACE_BEGIN + +struct Intersection; +struct KernelGlobals; +struct OpenVDBGlobals; +struct OpenVDBThreadData; +struct Ray; + +void vdb_thread_init(KernelGlobals *kg, const KernelGlobals *kernel_globals, OpenVDBGlobals *vdb_globals); +void vdb_thread_free(KernelGlobals *kg); + +enum OpenVDB_SampleType { + OPENVDB_SAMPLE_POINT = 0, + OPENVDB_SAMPLE_BOX = 1, +}; + +bool vdb_volume_scalar_has_uniform_voxels(OpenVDBGlobals *vdb, int vdb_index); +bool vdb_volume_vector_has_uniform_voxels(OpenVDBGlobals *vdb, int vdb_index); +float vdb_volume_sample_scalar(OpenVDBGlobals *vdb, OpenVDBThreadData *vdb_thread, int vdb_index, + float x, float y, float z, int sampling); +float3 vdb_volume_sample_vector(OpenVDBGlobals *vdb, OpenVDBThreadData *vdb_thread, int vdb_index, + float x, float y, float z, int sampling); +bool vdb_volume_intersect(OpenVDBThreadData *vdb_thread, int vdb_index, + const Ray *ray, float *isect); +bool vdb_volume_march(OpenVDBThreadData *vdb_thread, int vdb_index, + float *t0, float *t1); + +CCL_NAMESPACE_END + +#endif /* __VDB_THREAD_H__ */ diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index f56ae9f7b8c..bc093272eca 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -41,6 +41,7 @@ #include "kernel_differential.h" #include "kernel_montecarlo.h" #include "kernel_camera.h" + #include "kernels/cpu/kernel_cpu_image.h" /* Note: "util_foreach.h" needs to be included after "kernel_compat_cpu.h", as diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index c0d429a583c..12fa58a84e2 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -33,7 +33,8 @@ Attribute::~Attribute() VoxelAttribute *voxel_data = data_voxel(); if(voxel_data && voxel_data->slot != -1) { - voxel_data->manager->remove_image(voxel_data->slot); + if (voxel_data->manager) + voxel_data->manager->remove_image(voxel_data->slot); } } } @@ -344,10 +345,13 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme /* this is weak .. */ if(triangle_mesh) attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false); - if(curve_mesh) + else if(curve_mesh) attr->resize(curve_mesh, ATTR_PRIM_CURVE, false); - if(subd_mesh) + else if(subd_mesh) attr->resize(subd_mesh, ATTR_PRIM_SUBD, false); + else if(element == ATTR_ELEMENT_VOXEL) { + attr->resize(1); + } return attr; } diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 790547ea567..3045800591b 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -5375,15 +5375,20 @@ NODE_DEFINE(OpenVDBNode) { NodeType* type = NodeType::add("openvdb", create, NodeType::SHADER); + SOCKET_STRING(filename, "Filename", ustring("")); + + static NodeEnum sampling_enum; + sampling_enum.insert("point", OPENVDB_SAMPLE_POINT); + sampling_enum.insert("box", OPENVDB_SAMPLE_BOX); + SOCKET_ENUM(sampling, "Sampling", sampling_enum, OPENVDB_SAMPLE_POINT); + return type; } OpenVDBNode::OpenVDBNode() : ShaderNode(node_type) { - filename = ""; volume_manager = NULL; - sampling = OPENVDB_SAMPLE_POINT; } void OpenVDBNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -5408,9 +5413,9 @@ void OpenVDBNode::compile(SVMCompiler& compiler) type = NODE_VDB_FLOAT3; } - grid_slot = volume_manager->add_volume(filename.string(), - output_sockets[i].name.string(), - sampling, type); +// grid_slot = volume_manager->add_volume(filename.string(), +// output_names[i].string(), +// sampling, type); if(grid_slot == -1) { continue; @@ -5423,6 +5428,11 @@ void OpenVDBNode::compile(SVMCompiler& compiler) } } +void OpenVDBNode::add_output(ustring name, SocketType::Type socket_type) +{ + const_cast<NodeType*>(type)->register_output(name, name, socket_type); +} + void OpenVDBNode::compile(OSLCompiler& /*compiler*/) { } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 73c02bbb3ba..a16c7ff2efc 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -986,6 +986,8 @@ public: void attributes(Shader *shader, AttributeRequestSet *attributes); bool has_spatial_varying() { return true; } + void add_output(ustring name, SocketType::Type type); + ustring filename; VolumeManager *volume_manager; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index cb057beb40a..bfe7fd8990d 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -85,12 +85,15 @@ void Scene::free_memory(bool final) delete l; foreach(ParticleSystem *p, particle_systems) delete p; + foreach(Volume *v, volumes) + delete v; shaders.clear(); meshes.clear(); objects.clear(); lights.clear(); particle_systems.clear(); + volumes.clear(); if(device) { camera->device_free(device, &dscene, this); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 3ac7b3b1c40..e631e7a1360 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -54,6 +54,7 @@ class ShaderManager; class Progress; class BakeManager; class BakeData; +class Volume; class VolumeManager; /* Scene Device Data */ @@ -128,6 +129,9 @@ public: device_vector<float> tex_image_float_packed; device_vector<uint4> tex_image_packed_info; + /* volume */ + device_vector<uint> vol_shader; + KernelData data; }; @@ -183,6 +187,7 @@ public: vector<Shader*> shaders; vector<Light*> lights; vector<ParticleSystem*> particle_systems; + vector<Volume*> volumes; /* data managers */ ImageManager *image_manager; @@ -200,6 +205,7 @@ public: Shader *default_light; Shader *default_background; Shader *default_empty; + Shader *default_volume; /* device */ Device *device; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 9d8c9fed7af..6ea902f4431 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -630,11 +630,12 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.use_camera_motion = scene->camera->use_motion; foreach(Object *object, scene->objects) { Mesh *mesh = object->mesh; - if(mesh->num_curves()) { - requested_features.use_hair = true; + if(mesh) { + if(mesh->num_curves()) { + requested_features.use_hair = true; + } } - requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur; - requested_features.use_camera_motion |= mesh->use_motion_blur; + requested_features.use_object_motion |= object->use_motion; #ifdef WITH_OPENSUBDIV if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { requested_features.use_patch_evaluation = true; diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 06b6dd969d8..e47bfe71ef9 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -377,6 +377,7 @@ void ShaderManager::device_update_shaders_used(Scene *scene) scene->default_light->used = true; scene->default_background->used = true; scene->default_empty->used = true; + scene->default_volume->used = true; if(scene->background->shader) scene->background->shader->used = true; @@ -553,6 +554,23 @@ void ShaderManager::add_default(Scene *scene) scene->shaders.push_back(shader); scene->default_empty = shader; } + + /* default empty */ + { + ShaderGraph *graph = new ShaderGraph(); + + ScatterVolumeNode *scatter = new ScatterVolumeNode(); + scatter->input("Density")->set(1.0); + graph->add(scatter); + + graph->connect(scatter->output("Volume"), graph->output()->input("Volume")); + + Shader *shader = new Shader(); + shader->name = "default_volume"; + shader->graph = graph; + scene->shaders.push_back(shader); + scene->default_volume = shader; + } } void ShaderManager::get_requested_graph_features(ShaderGraph *graph, diff --git a/intern/cycles/render/volume.cpp b/intern/cycles/render/volume.cpp index 8d305c27c5d..c8b4fe6379c 100644 --- a/intern/cycles/render/volume.cpp +++ b/intern/cycles/render/volume.cpp @@ -14,46 +14,43 @@ * limitations under the License. */ -#include "volume.h" #include "scene.h" +#include "volume.h" + +#include "util_foreach.h" #include "util_logging.h" #include "util_progress.h" #include "util_task.h" +#include "../kernel/openvdb/vdb_globals.h" + CCL_NAMESPACE_BEGIN #define MAX_VOLUME 1024 +void Volume::tag_update(Scene *scene, bool /*rebuild*/) +{ + scene->volume_manager->need_update = true; +} + +/* ------------------------------------------------------------------------- */ + VolumeManager::VolumeManager() { #ifdef WITH_OPENVDB openvdb::initialize(); - scalar_grids.reserve(64); - vector_grids.reserve(64); current_grids.reserve(64); - float_volumes.reserve(64); - float3_volumes.reserve(64); #endif need_update = true; + num_float_volume = 0; + num_float3_volume = 0; } VolumeManager::~VolumeManager() { -#ifdef WITH_OPENVDB - for(size_t i = 0; i < float_volumes.size(); ++i) { - delete float_volumes[i]; - } - - for(size_t i = 0; i < float3_volumes.size(); ++i) { - delete float3_volumes[i]; - } - - scalar_grids.clear(); - vector_grids.clear(); current_grids.clear(); -#endif } static inline void catch_exceptions() @@ -68,6 +65,7 @@ static inline void catch_exceptions() #endif } +#if 0 int VolumeManager::add_volume(const string& filename, const string& name, int sampling, int grid_type) { size_t slot = -1; @@ -93,7 +91,39 @@ int VolumeManager::add_volume(const string& filename, const string& name, int sa return slot; } +#endif +int VolumeManager::add_volume(Volume *volume, const std::string &filename, const std::string &name) +{ + size_t slot = -1; + + if((slot = find_existing_slot(volume, filename, name)) != -1) { + return slot; + } + + if((num_float_volume + num_float3_volume + 1) > MAX_VOLUME) { + printf("VolumeManager::add_volume: volume limit reached %d!\n", MAX_VOLUME); + return -1; + } + + try { + if(is_openvdb_file(filename)) { + slot = add_openvdb_volume(volume, filename, name); + } + + add_grid_description(volume, filename, name, slot); + + volumes.push_back(volume); + } + catch(...) { + catch_exceptions(); + slot = -1; + } + + return slot; +} + +#if 0 int VolumeManager::find_existing_slot(const string& filename, const string& name, int sampling, int grid_type) { for(size_t i = 0; i < current_grids.size(); ++i) { @@ -104,16 +134,6 @@ int VolumeManager::find_existing_slot(const string& filename, const string& name return grid.slot; } else { - /* sampling was changed, remove the volume */ - if(grid_type == NODE_VDB_FLOAT) { - delete float_volumes[grid.slot]; - float_volumes[grid.slot] = NULL; - } - else { - delete float3_volumes[grid.slot]; - float3_volumes[grid.slot] = NULL; - } - /* remove the grid description too */ std::swap(current_grids[i], current_grids.back()); current_grids.pop_back(); @@ -124,6 +144,22 @@ int VolumeManager::find_existing_slot(const string& filename, const string& name return -1; } +#endif + +int VolumeManager::find_existing_slot(Volume *volume, const std::string &filename, const std::string &name) +{ + for(size_t i = 0; i < current_grids.size(); ++i) { + GridDescription grid = current_grids[i]; + + if(grid.volume == volume) { + if(grid.filename == filename && grid.name == name) { + return grid.slot; + } + } + } + + return -1; +} int VolumeManager::find_density_slot() { @@ -136,8 +172,12 @@ int VolumeManager::find_density_slot() } /* try using the first scalar float grid instead */ - if(!float_volumes.empty()) { - return 0; + for (size_t i = 0; i < volumes.size(); ++i) { + Volume *volume = volumes[i]; + + if (!volume->scalar_grids.empty()) { + return 0; + } } return -1; @@ -172,6 +212,7 @@ size_t find_empty_slot(Container container) return slot; } +#if 0 size_t VolumeManager::add_openvdb_volume(const std::string& filename, const std::string& name, int /*sampling*/, int grid_type) { size_t slot = -1; @@ -188,38 +229,69 @@ size_t VolumeManager::add_openvdb_volume(const std::string& filename, const std: if(grid->getGridClass() == GRID_LEVEL_SET) return -1; if(grid_type == NODE_VDB_FLOAT) { - slot = find_empty_slot(float_volumes); + slot = find_empty_slot(scalar_grids); + if (slot == -1) + return -1; + + scalar_grids.insert(scalar_grids.begin() + slot, gridPtrCast<FloatGrid>(grid)); + } + else if(grid_type == NODE_VDB_FLOAT3) { + slot = find_empty_slot(vector_grids); + if (slot == -1) + return -1; + + vector_grids.insert(vector_grids.begin() + slot, gridPtrCast<Vec3SGrid>(grid)); + } +#else + (void)filename; + (void)name; + (void)grid_type; +#endif - if(slot == -1) return -1; + return slot; +} +#endif - FloatGrid::Ptr fgrid = gridPtrCast<FloatGrid>(grid); +size_t VolumeManager::add_openvdb_volume(Volume *volume, const std::string &filename, const std::string &name) +{ + size_t slot = -1; - vdb_float_volume *volume = new vdb_float_volume(fgrid); - volume->create_threads_utils(TaskScheduler::thread_ids()); - float_volumes.insert(float_volumes.begin() + slot, volume); - scalar_grids.push_back(fgrid); - } - else if(grid_type == NODE_VDB_FLOAT3) { - slot = find_empty_slot(float3_volumes); +#ifdef WITH_OPENVDB + openvdb::io::File file(filename); + file.open(); + + if(!file.hasGrid(name)) return -1; + + openvdb::GridBase::Ptr grid = file.readGrid(name); + if(grid->getGridClass() == openvdb::GRID_LEVEL_SET) return -1; - if(slot == -1) return -1; + if(grid->isType<openvdb::FloatGrid>()) { + openvdb::FloatGrid::Ptr fgrid = openvdb::gridPtrCast<openvdb::FloatGrid>(grid); + volume->scalar_grids.push_back(fgrid); - Vec3SGrid::Ptr vgrid = gridPtrCast<Vec3SGrid>(grid); + /* XXX Ray intersectors only support uniform grids. + * Can we make this transparent somehow? - lukas + */ + assert(fgrid->hasUniformVoxels()); - vdb_float3_volume *volume = new vdb_float3_volume(vgrid); - volume->create_threads_utils(TaskScheduler::thread_ids()); - float3_volumes.insert(float3_volumes.begin() + slot, volume); - vector_grids.push_back(vgrid); + slot = num_float_volume++; + } + else if(grid->isType<openvdb::Vec3SGrid>()) { + openvdb::Vec3SGrid::Ptr vgrid = openvdb::gridPtrCast<openvdb::Vec3SGrid>(grid); + volume->vector_grids.push_back(vgrid); + + slot = num_float3_volume++; } #else + (void)volume; (void)filename; (void)name; - (void)grid_type; #endif return slot; } +#if 0 void VolumeManager::add_grid_description(const string& filename, const string& name, int sampling, int slot) { GridDescription descr; @@ -230,8 +302,129 @@ void VolumeManager::add_grid_description(const string& filename, const string& n current_grids.push_back(descr); } +#endif + +void VolumeManager::add_grid_description(Volume *volume, const std::string &filename, const std::string &name, int slot) +{ + GridDescription descr; + descr.filename = filename; + descr.name = name; + descr.volume = volume; + descr.slot = slot; + + current_grids.push_back(descr); +} + +static void update_attribute_element_offset(Attribute *vattr, + TypeDesc& type, + int& offset, + AttributeElement& element) +{ + if(vattr) { + /* store element and type */ + element = vattr->element; + type = vattr->type; + + /* store slot in offset value */ + VoxelAttribute *voxel_data = vattr->data_voxel(); + offset = voxel_data->slot; + } + else { + /* attribute not found */ + element = ATTR_ELEMENT_NONE; + offset = 0; + } +} -void VolumeManager::device_update(Device *device, DeviceScene *dscene, Scene */*scene*/, Progress& progress) +void VolumeManager::device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +{ + progress.set_status("Updating Volume", "Computing attributes"); + + /* gather per volume requested attributes. as volumes may have multiple + * shaders assigned, this merges the requested attributes that have + * been set per shader by the shader manager */ + vector<AttributeRequestSet> volume_attributes(volumes.size()); + + for(size_t i = 0; i < volumes.size(); i++) { + Volume *volume = volumes[i]; + + foreach(Shader *shader, volume->used_shaders) { + volume_attributes[i].add(shader->attributes); + } + } + + for(size_t i = 0; i < volumes.size(); i++) { + Volume *volume = volumes[i]; + AttributeRequestSet& attributes = volume_attributes[i]; + + /* todo: we now store std and name attributes from requests even if + * they actually refer to the same mesh attributes, optimize */ + foreach(AttributeRequest& req, attributes.requests) { + Attribute *vattr = volume->attributes.find(req); + + update_attribute_element_offset(vattr, + req.triangle_type, + req.triangle_desc.offset, + req.triangle_desc.element); + + if(progress.get_cancel()) return; + } + } + + update_svm_attributes(device, dscene, scene, volume_attributes); +} + +void VolumeManager::update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes) +{ + /* compute array stride */ + int attr_map_stride = 0; + + for(size_t i = 0; i < volumes.size(); i++) { + attr_map_stride = max(attr_map_stride, (mesh_attributes[i].size() + 1)); + } + + if(attr_map_stride == 0) { + return; + } + + /* create attribute map */ + uint4 *attr_map = dscene->attributes_map.resize(attr_map_stride*volumes.size()); + memset(attr_map, 0, dscene->attributes_map.size()*sizeof(uint)); + + for(size_t i = 0; i < volumes.size(); i++) { + AttributeRequestSet& attributes = mesh_attributes[i]; + + /* set object attributes */ + int index = i*attr_map_stride; + + foreach(AttributeRequest& req, attributes.requests) { + uint id = scene->shader_manager->get_attribute_id(req.name); + + attr_map[index].x = id; + attr_map[index].y = req.triangle_desc.element; + attr_map[index].z = as_uint(req.triangle_desc.offset); + + if(req.triangle_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + + index++; + } + + /* terminator */ + attr_map[index].x = ATTR_STD_NONE; + attr_map[index].y = 0; + attr_map[index].z = 0; + attr_map[index].w = 0; + + index++; + } + + device->tex_alloc("__attributes_map", dscene->attributes_map); +} + +void VolumeManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) { if(!need_update) { return; @@ -240,45 +433,93 @@ void VolumeManager::device_update(Device *device, DeviceScene *dscene, Scene */* device_free(device, dscene); progress.set_status("Updating OpenVDB volumes", "Sending volumes to device."); - for(size_t i = 0; i < float_volumes.size(); ++i) { - if(!float_volumes[i]) { - continue; + uint *vol_shader = dscene->vol_shader.resize(num_float_volume + num_float3_volume); + int s = 0; + + for (size_t i = 0; i < volumes.size(); ++i) { + Volume *volume = volumes[i]; + + for(size_t i = 0; i < volume->scalar_grids.size(); ++i) { + if(!volume->scalar_grids[i]) { + continue; + } + + vol_shader[s++] = scene->shader_manager->get_shader_id(volume->used_shaders[0], false); + } + + for(size_t i = 0; i < volume->vector_grids.size(); ++i) { + if(!volume->vector_grids[i]) { + continue; + } + + vol_shader[s++] = scene->shader_manager->get_shader_id(volume->used_shaders[0], false); + } + + if(progress.get_cancel()) { + return; } - device->const_copy_to("__float_volume", float_volumes[i], i); } - for(size_t i = 0; i < float3_volumes.size(); ++i) { - if(!float3_volumes[i]) { - continue; + device->tex_alloc("__vol_shader", dscene->vol_shader); + +#ifdef WITH_OPENVDB + typedef typename OpenVDBGlobals::scalar_grid_t scalar_grid_t; + typedef typename OpenVDBGlobals::vector_grid_t vector_grid_t; + typedef typename OpenVDBGlobals::scalar_isector_t scalar_isector_t; + typedef typename OpenVDBGlobals::vector_isector_t vector_isector_t; + OpenVDBGlobals *vdb = device->vdb_memory(); + + vdb->scalar_grids.reserve(num_float_volume); + vdb->vector_grids.reserve(num_float3_volume); + vdb->scalar_main_isectors.reserve(num_float_volume); + vdb->vector_main_isectors.reserve(num_float3_volume); + for (size_t i = 0; i < volumes.size(); ++i) { + Volume *volume = volumes[i]; + + for (size_t k = 0; k < volume->scalar_grids.size(); ++k) { + scalar_grid_t *grid = volume->scalar_grids[k].get(); + vdb->scalar_grids.push_back(grid); + vdb->scalar_main_isectors.push_back(new scalar_isector_t(*grid)); + VLOG(1) << grid->getName().c_str() << " memory usage: " << grid->memUsage() / 1024.0f << " kilobytes.\n"; + } + for (size_t k = 0; k < volume->vector_grids.size(); ++k) { + vector_grid_t *grid = volume->vector_grids[k].get(); + vdb->vector_grids.push_back(grid); + vdb->vector_main_isectors.push_back(new vector_isector_t(*grid)); + VLOG(1) << grid->getName().c_str() << " memory usage: " << grid->memUsage() / 1024.0f << " kilobytes.\n"; } - device->const_copy_to("__float3_volume", float3_volumes[i], i); } +#endif if(progress.get_cancel()) { return; } - dscene->data.tables.num_volumes = float_volumes.size() + float3_volumes.size(); - dscene->data.tables.density_index = find_density_slot(); + dscene->data.tables.num_volumes = num_float_volume/* + float3_volumes.size()*/; + dscene->data.tables.density_index = 0; - VLOG(1) << "Volume allocate: __float_volume, " << float_volumes.size() * sizeof(float_volume) << " bytes"; - VLOG(1) << "Volume allocate: __float3_volume, " << float3_volumes.size() * sizeof(float3_volume) << " bytes"; + need_update = false; +} +void VolumeManager::device_free(Device *device, DeviceScene *dscene) +{ #ifdef WITH_OPENVDB - for(size_t i = 0; i < scalar_grids.size(); ++i) { - VLOG(1) << scalar_grids[i]->getName().c_str() << " memory usage: " << scalar_grids[i]->memUsage() / 1024.0f << " kilobytes.\n"; + OpenVDBGlobals *vdb = device->vdb_memory(); + for (size_t i = 0; i < vdb->scalar_main_isectors.size(); ++i) { + delete vdb->scalar_main_isectors[i]; } - - for(size_t i = 0; i < vector_grids.size(); ++i) { - VLOG(1) << vector_grids[i]->getName().c_str() << " memory usage: " << vector_grids[i]->memUsage() / 1024.0f << " kilobytes.\n"; + for (size_t i = 0; i < vdb->vector_main_isectors.size(); ++i) { + delete vdb->vector_main_isectors[i]; } #endif - - need_update = false; + + device->tex_free(dscene->vol_shader); + dscene->vol_shader.clear(); } -void VolumeManager::device_free(Device */*device*/, DeviceScene */*dscene*/) +void VolumeManager::tag_update(Scene */*scene*/) { + need_update = true; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/volume.h b/intern/cycles/render/volume.h index 665e0bcc4ea..537896591fd 100644 --- a/intern/cycles/render/volume.h +++ b/intern/cycles/render/volume.h @@ -17,19 +17,43 @@ #ifndef __VOLUMEMANAGER_H__ #define __VOLUMEMANAGER_H__ +#include "attribute.h" + #include "util_string.h" #include "util_types.h" #include "util_volume.h" +#ifdef WITH_OPENVDB +#include <openvdb/openvdb.h> +#include <openvdb/tools/Interpolation.h> +#include <openvdb/tools/RayIntersector.h> +#endif + CCL_NAMESPACE_BEGIN class Device; class DeviceScene; class Progress; class Scene; +class Shader; + +class Volume { +public: + vector<Shader*> used_shaders; + AttributeSet attributes; + string name; + +#ifdef WITH_OPENVDB + vector<openvdb::FloatGrid::Ptr> scalar_grids; + vector<openvdb::Vec3SGrid::Ptr> vector_grids; +#endif + + void tag_update(Scene *scene, bool rebuild); +}; class VolumeManager { struct GridDescription { + Volume *volume; string filename; string name; int sampling; @@ -37,34 +61,46 @@ class VolumeManager { }; vector<GridDescription> current_grids; - -#ifdef WITH_OPENVDB - vector<openvdb::FloatGrid::Ptr> scalar_grids; - vector<openvdb::Vec3SGrid::Ptr> vector_grids; -#endif + int num_float_volume; + int num_float3_volume; void delete_volume(int grid_type, int sampling, size_t slot); +#if 0 void add_grid_description(const string& filename, const string& name, int sampling, int slot); +#endif + void add_grid_description(Volume *volume, const string& filename, const string& name, int slot); +#if 0 int find_existing_slot(const string& filename, const string& name, int sampling, int grid_type); +#endif + int find_existing_slot(Volume *volume, const string& filename, const string& name); bool is_openvdb_file(const string& filename) const; +#if 0 size_t add_openvdb_volume(const string& filename, const string& name, int sampling, int grid_type); +#endif + size_t add_openvdb_volume(Volume *volume, const string& filename, const string& name); public: VolumeManager(); ~VolumeManager(); +#if 0 int add_volume(const string& filename, const string& name, int sampling, int grid_type); +#endif + int add_volume(Volume *volume, const string& filename, const string& name); int find_density_slot(); void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes); void device_free(Device *device, DeviceScene *dscene); + void tag_update(Scene *scene); + bool need_update; - vector<float_volume*> float_volumes; - vector<float3_volume*> float3_volumes; + vector<Volume*> volumes; }; CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp index 2e92916d659..352ba81c95a 100644 --- a/intern/cycles/util/util_task.cpp +++ b/intern/cycles/util/util_task.cpp @@ -180,7 +180,6 @@ void TaskPool::num_increase() thread_mutex TaskScheduler::mutex; int TaskScheduler::users = 0; vector<thread*> TaskScheduler::threads; -vector<pthread_t> TaskScheduler::threads_ids; bool TaskScheduler::do_exit = false; list<TaskScheduler::Entry> TaskScheduler::queue; @@ -204,7 +203,6 @@ void TaskScheduler::init(int num_threads) /* launch threads that will be waiting for work */ threads.resize(num_threads); - threads_ids.resize(num_threads); int num_groups = system_cpu_group_count(); int thread_index = 0; @@ -223,7 +221,6 @@ void TaskScheduler::init(int num_threads) threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run, thread_index + 1), group); - threads_ids[thread_index] = threads[thread_index]->id(); } } } @@ -339,11 +336,6 @@ void TaskScheduler::clear(TaskPool *pool) pool->num_decrease(done); } -vector<pthread_t> TaskScheduler::thread_ids() -{ - return threads_ids; -} - /* Dedicated Task Pool */ DedicatedTaskPool::DedicatedTaskPool() diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h index 528602fc332..0b82f14f66f 100644 --- a/intern/cycles/util/util_task.h +++ b/intern/cycles/util/util_task.h @@ -132,9 +132,6 @@ public: /* number of threads that can work on task */ static int num_threads() { return threads.size(); } - /* ids of all threads managed by the scheduler */ - static vector<pthread_t> thread_ids(); - /* test if any session is using the scheduler */ static bool active() { return users != 0; } @@ -149,7 +146,6 @@ protected: static thread_mutex mutex; static int users; static vector<thread*> threads; - static vector<pthread_t> threads_ids; static bool do_exit; static list<Entry> queue; diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h index 5d0020aeea2..427c633d2ce 100644 --- a/intern/cycles/util/util_thread.h +++ b/intern/cycles/util/util_thread.h @@ -58,11 +58,6 @@ public: static void *run(void *arg); bool join(); - pthread_t id() const - { - return pthread_id_; - } - protected: function<void(void)> run_cb_; pthread_t pthread_id_; diff --git a/intern/cycles/util/util_volume.cpp b/intern/cycles/util/util_volume.cpp index f48b983a8d4..d2f02071ab6 100644 --- a/intern/cycles/util/util_volume.cpp +++ b/intern/cycles/util/util_volume.cpp @@ -16,155 +16,4 @@ #include "util_volume.h" -#if defined(HAS_CPP11_FEATURES) && defined(_MSC_VER) - -namespace std { - -bool operator==(const pthread_t &lhs, const pthread_t &rhs) -{ - return lhs.p == rhs.p; -} - -} /* namespace std */ - -#endif - -CCL_NAMESPACE_BEGIN - -template <typename T> -void release_map_memory(unordered_map<pthread_t, T> &map) -{ - typename unordered_map<pthread_t, T>::iterator iter; - - for(iter = map.begin(); iter != map.end(); ++iter) { - delete iter->second; - } -} - -template <typename IsectorType> -void create_isectors_threads(unordered_map<pthread_t, IsectorType *> &isect_map, - const vector<pthread_t> &thread_ids, - const IsectorType &main_isect) -{ - release_map_memory(isect_map); - - pthread_t my_thread = pthread_self(); - - for (size_t i = 0; i < thread_ids.size(); ++i) { - if (isect_map.find(thread_ids[i]) == isect_map.end()) { - isect_map[thread_ids[i]] = new IsectorType(main_isect); - } - } - - if (isect_map.find(my_thread) == isect_map.end()) { - isect_map[my_thread] = new IsectorType(main_isect); - } -} - -template <typename SamplerType, typename AccessorType> -void create_samplers_threads(unordered_map<pthread_t, SamplerType *> &sampler_map, - vector<AccessorType *> &accessors, - const vector<pthread_t> &thread_ids, - const openvdb::math::Transform *transform, - const AccessorType &main_accessor) -{ - release_map_memory(sampler_map); - - pthread_t my_thread = pthread_self(); - - for (size_t i = 0; i < thread_ids.size(); ++i) { - AccessorType *accessor = new AccessorType(main_accessor); - accessors.push_back(accessor); - - if (sampler_map.find(thread_ids[i]) == sampler_map.end()) { - sampler_map[thread_ids[i]] = new SamplerType(*accessor, *transform); - } - } - - if (sampler_map.find(my_thread) == sampler_map.end()) { - AccessorType *accessor = new AccessorType(main_accessor); - accessors.push_back(accessor); - sampler_map[my_thread] = new SamplerType(*accessor, *transform); - } -} - -/* ********** OpenVDB floating pointing scalar volume ************ */ - -vdb_float_volume::vdb_float_volume(openvdb::FloatGrid::Ptr grid) - : transform(&grid->transform()) - , uniform_voxels(grid->hasUniformVoxels()) - , main_isector(uniform_voxels ? new isector_t(*grid, 1) : NULL) -{ - accessor = new openvdb::FloatGrid::ConstAccessor(grid->getConstAccessor()); -} - -vdb_float_volume::~vdb_float_volume() -{ - release_map_memory(point_samplers); - release_map_memory(box_samplers); - - if(uniform_voxels) { - delete main_isector; - release_map_memory(isectors); - } - - delete accessor; - - for(size_t i = 0; i < accessors.size(); ++i) { - delete accessors[i]; - } -} - -void vdb_float_volume::create_threads_utils(const vector<pthread_t> &thread_ids) -{ - if (uniform_voxels) { - create_isectors_threads(isectors, thread_ids, *main_isector); - } - - create_samplers_threads(point_samplers, accessors, thread_ids, transform, *accessor); - create_samplers_threads(box_samplers, accessors, thread_ids, transform, *accessor); -} - -/* ********** OpenVDB vector volume ************ */ - -vdb_float3_volume::vdb_float3_volume(openvdb::Vec3SGrid::Ptr grid) - : transform(&grid->transform()) - , uniform_voxels(grid->hasUniformVoxels()) - , staggered(grid->getGridClass() == openvdb::GRID_STAGGERED) - , main_isector(uniform_voxels ? new isector_t(*grid, 1) : NULL) -{ - accessor = new openvdb::Vec3SGrid::ConstAccessor(grid->getConstAccessor()); -} - -vdb_float3_volume::~vdb_float3_volume() -{ - release_map_memory(point_samplers); - release_map_memory(box_samplers); - release_map_memory(stag_point_samplers); - release_map_memory(stag_box_samplers); - - if(uniform_voxels) { - delete main_isector; - release_map_memory(isectors); - } - - delete accessor; - - for(size_t i = 0; i < accessors.size(); ++i) { - delete accessors[i]; - } -} - -void vdb_float3_volume::create_threads_utils(const vector<pthread_t> &thread_ids) -{ - if (uniform_voxels) { - create_isectors_threads(isectors, thread_ids, *main_isector); - } - - create_samplers_threads(point_samplers, accessors, thread_ids, transform, *accessor); - create_samplers_threads(box_samplers, accessors, thread_ids, transform, *accessor); - create_samplers_threads(stag_point_samplers, accessors, thread_ids, transform, *accessor); - create_samplers_threads(stag_box_samplers, accessors, thread_ids, transform, *accessor); -} - -CCL_NAMESPACE_END +#include <cstdio> diff --git a/intern/cycles/util/util_volume.h b/intern/cycles/util/util_volume.h index 4a6aafe4963..1621d84b828 100644 --- a/intern/cycles/util/util_volume.h +++ b/intern/cycles/util/util_volume.h @@ -21,348 +21,41 @@ #include "../kernel/kernel_types.h" +#ifdef WITH_OPENVDB +#include "../kernel/openvdb/vdb_thread.h" +#endif + CCL_NAMESPACE_BEGIN +#if 0 +struct KernelGlobals; struct Ray; struct Intersection; -enum { - OPENVDB_SAMPLE_POINT = 0, - OPENVDB_SAMPLE_BOX = 1, -}; - class float_volume { public: virtual ~float_volume() {} +#if 0 virtual float sample(float x, float y, float z, int sampling) = 0; - virtual bool intersect(const Ray *ray, Intersection *isect) = 0; + virtual bool intersect(const Ray *ray, float *isect_t) = 0; virtual bool march(float *t0, float *t1) = 0; virtual bool has_uniform_voxels() = 0; +#endif }; class float3_volume { public: virtual ~float3_volume() {} +#if 0 virtual float3 sample(float x, float y, float z, int sampling) = 0; - virtual bool intersect(const Ray *ray, Intersection *isect) = 0; + virtual bool intersect(const Ray *ray, float *isect_t) = 0; virtual bool march(float *t0, float *t1) = 0; virtual bool has_uniform_voxels() = 0; -}; - -CCL_NAMESPACE_END - -#ifdef WITH_OPENVDB - -/* They are too many implicit float conversions happening in OpenVDB, disabling - * errors for now (kevin) */ -#ifdef __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wfloat-conversion" -# pragma GCC diagnostic ignored "-Wdouble-promotion" -#endif - -#include <openvdb/openvdb.h> -#include <openvdb/tools/Interpolation.h> -#include <openvdb/tools/RayIntersector.h> - -#ifdef __GNUC__ -# pragma GCC diagnostic pop #endif - -#include "util_map.h" -#include "util_thread.h" -#include "util_vector.h" - -#if defined(HAS_CPP11_FEATURES) && defined(_MSC_VER) - -namespace std { - -template<> -struct hash<pthread_t> { - size_t operator()(const pthread_t &pt) const - { - return std::hash<void *>()(pt.p) ^ (std::hash<unsigned int>()(pt.x) << 1); - } }; - -bool operator==(const pthread_t &lhs, const pthread_t &rhs); - -} /* namespace std */ - #endif -CCL_NAMESPACE_BEGIN - -#if defined(HAS_CPP11_FEATURES) -using std::isfinite; -#else -using boost::math::isfinite; -#endif - -typedef openvdb::math::Ray<float> vdb_ray_t; - -class vdb_float_volume : public float_volume { - typedef openvdb::tools::GridSampler<openvdb::FloatGrid::ConstAccessor, openvdb::tools::PointSampler> point_sampler_t; - typedef openvdb::tools::GridSampler<openvdb::FloatGrid::ConstAccessor, openvdb::tools::BoxSampler> box_sampler_t; - typedef openvdb::tools::VolumeRayIntersector<openvdb::FloatGrid, - openvdb::FloatTree::RootNodeType::ChildNodeType::LEVEL, - vdb_ray_t> isector_t; - - /* mainly used to ensure thread safety for the accessors */ - typedef unordered_map<pthread_t, isector_t *> isect_map; - typedef unordered_map<pthread_t, point_sampler_t *> point_map; - typedef unordered_map<pthread_t, box_sampler_t *> box_map; - isect_map isectors; - point_map point_samplers; - box_map box_samplers; - - vector<openvdb::FloatGrid::ConstAccessor *> accessors; - - openvdb::FloatGrid::ConstAccessor *accessor; - openvdb::math::Transform *transform; - - /* only grids with uniform voxels can be used with VolumeRayIntersector, so - * we keep track of this for ray marching */ - bool uniform_voxels; - - /* Main intersector, its purpose is to initialize the voxels' bounding box - * so the ones for the various threads do not do this, rather they are - * generated from a copy of it */ - isector_t *main_isector; - -public: - vdb_float_volume(openvdb::FloatGrid::Ptr grid); - ~vdb_float_volume(); - - void create_threads_utils(const vector<pthread_t> &thread_ids); - - ccl_always_inline float sample(float x, float y, float z, int sampling) - { - pthread_t thread = pthread_self(); - - if(sampling == OPENVDB_SAMPLE_POINT) { - point_map::iterator iter = point_samplers.find(thread); - assert(iter != point_samplers.end()); - point_sampler_t *sampler = iter->second; - - return sampler->wsSample(openvdb::Vec3d(x, y, z)); - } - else { - box_map::iterator iter = box_samplers.find(thread); - assert(iter != box_samplers.end()); - box_sampler_t *sampler = iter->second; - - return sampler->wsSample(openvdb::Vec3d(x, y, z)); - } - } - - ccl_always_inline bool intersect(const Ray *ray, Intersection */*isect*/) - { - pthread_t thread = pthread_self(); - isect_map::iterator iter = isectors.find(thread); - assert(iter != isectors.end()); - isector_t *vdb_isect = iter->second; - - vdb_ray_t::Vec3Type P(ray->P.x, ray->P.y, ray->P.z); - vdb_ray_t::Vec3Type D(ray->D.x, ray->D.y, ray->D.z); - D.normalize(); - - vdb_ray_t vdb_ray(P, D, 1e-5f, ray->t); - - if(vdb_isect->setWorldRay(vdb_ray)) { - // TODO -// isect->t = vdb_ray.t1(); // (kevin) is this correct? -// isect->u = isect->v = 1.0f; -// isect->type = ; -// isect->shad = shader; -// isect->norm = ; -// isect->prim = 0; -// isect->object = 0; - - return true; - } - - return false; - } - - ccl_always_inline bool march(float *t0, float *t1) - { - pthread_t thread = pthread_self(); - isect_map::iterator iter = isectors.find(thread); - isector_t *vdb_isect = iter->second; - - float vdb_t0(*t0), vdb_t1(*t1); - - if(vdb_isect->march(vdb_t0, vdb_t1)) { - *t0 = vdb_isect->getWorldTime(vdb_t0); - *t1 = vdb_isect->getWorldTime(vdb_t1); - - return true; - } - - return false; - } - - ccl_always_inline bool has_uniform_voxels() - { - return uniform_voxels; - } -}; - -/* Same as above, except for vector grids, including staggered grids */ -class vdb_float3_volume : public float3_volume { - typedef openvdb::tools::GridSampler<openvdb::Vec3SGrid::ConstAccessor, openvdb::tools::PointSampler> point_sampler_t; - typedef openvdb::tools::GridSampler<openvdb::Vec3SGrid::ConstAccessor, openvdb::tools::BoxSampler> box_sampler_t; - typedef openvdb::tools::GridSampler<openvdb::Vec3SGrid::ConstAccessor, openvdb::tools::StaggeredPointSampler> stag_point_sampler_t; - typedef openvdb::tools::GridSampler<openvdb::Vec3SGrid::ConstAccessor, openvdb::tools::StaggeredBoxSampler> stag_box_sampler_t; - - typedef openvdb::tools::VolumeRayIntersector<openvdb::Vec3SGrid, - openvdb::FloatTree::RootNodeType::ChildNodeType::LEVEL, - vdb_ray_t> isector_t; - - /* mainly used to ensure thread safety for the accessors */ - typedef unordered_map<pthread_t, isector_t *> isect_map; - typedef unordered_map<pthread_t, point_sampler_t *> point_map; - typedef unordered_map<pthread_t, box_sampler_t *> box_map; - typedef unordered_map<pthread_t, stag_point_sampler_t *> stag_point_map; - typedef unordered_map<pthread_t, stag_box_sampler_t *> stag_box_map; - isect_map isectors; - point_map point_samplers; - box_map box_samplers; - stag_point_map stag_point_samplers; - stag_box_map stag_box_samplers; - - vector<openvdb::Vec3SGrid::ConstAccessor *> accessors; - - openvdb::Vec3SGrid::ConstAccessor *accessor; - openvdb::math::Transform *transform; - - /* only grids with uniform voxels can be used with VolumeRayIntersector, so - * we keep track of this for ray marching */ - bool uniform_voxels; - bool staggered; - - /* Main intersector, its purpose is to initialize the voxels' bounding box - * so the ones for the various threads do not do this, rather they are - * generated from a copy of it. */ - isector_t *main_isector; - -public: - vdb_float3_volume(openvdb::Vec3SGrid::Ptr grid); - ~vdb_float3_volume(); - - void create_threads_utils(const vector<pthread_t> &thread_ids); - - ccl_always_inline float3 sample_staggered(float x, float y, float z, int sampling) - { - openvdb::Vec3s r; - pthread_t thread = pthread_self(); - - if(sampling == OPENVDB_SAMPLE_POINT) { - stag_point_map::iterator iter = stag_point_samplers.find(thread); - assert(iter != stag_point_samplers.end()); - stag_point_sampler_t *sampler = iter->second; - - r = sampler->wsSample(openvdb::Vec3d(x, y, z)); - } - else { - stag_box_map::iterator iter = stag_box_samplers.find(thread); - assert(iter != stag_box_samplers.end()); - stag_box_sampler_t *sampler = iter->second; - - r = sampler->wsSample(openvdb::Vec3d(x, y, z)); - } - - return make_float3(r.x(), r.y(), r.z()); - } - - ccl_always_inline float3 sample_ex(float x, float y, float z, int sampling) - { - openvdb::Vec3s r; - pthread_t thread = pthread_self(); - - if(sampling == OPENVDB_SAMPLE_POINT) { - point_map::iterator iter = point_samplers.find(thread); - assert(iter != point_samplers.end()); - point_sampler_t *sampler = iter->second; - - r = sampler->wsSample(openvdb::Vec3d(x, y, z)); - } - else { - box_map::iterator iter = box_samplers.find(thread); - assert(iter != box_samplers.end()); - box_sampler_t *sampler = iter->second; - - r = sampler->wsSample(openvdb::Vec3d(x, y, z)); - } - - return make_float3(r.x(), r.y(), r.z()); - } - - ccl_always_inline float3 sample(float x, float y, float z, int sampling) - { - if(staggered) - return sample_staggered(x, y, z, sampling); - else - return sample_ex(x, y, z, sampling); - } - - ccl_always_inline bool intersect(const Ray *ray, Intersection */*isect*/) - { - pthread_t thread = pthread_self(); - isect_map::iterator iter = isectors.find(thread); - assert(iter != isectors.end()); - isector_t *vdb_isect = iter->second; - - vdb_ray_t::Vec3Type P(ray->P.x, ray->P.y, ray->P.z); - vdb_ray_t::Vec3Type D(ray->D.x, ray->D.y, ray->D.z); - D.normalize(); - - vdb_ray_t vdb_ray(P, D, 1e-5f, ray->t); - - if(vdb_isect->setWorldRay(vdb_ray)) { - // TODO -// isect->t = vdb_ray.t1(); // (kevin) is this correct? -// isect->u = isect->v = 1.0f; -// isect->type = ; -// isect->shad = shader; -// isect->norm = ; -// isect->prim = 0; -// isect->object = 0; - - return true; - } - - return false; - } - - ccl_always_inline bool march(float *t0, float *t1) - { - pthread_t thread = pthread_self(); - isect_map::iterator iter = isectors.find(thread); - isector_t *vdb_isect = iter->second; - - float vdb_t0(*t0), vdb_t1(*t1); - - if(vdb_isect->march(vdb_t0, vdb_t1)) { - *t0 = vdb_isect->getWorldTime(vdb_t0); - *t1 = vdb_isect->getWorldTime(vdb_t1); - - return true; - } - - return false; - } - - ccl_always_inline bool has_uniform_voxels() - { - return uniform_voxels; - } -}; - CCL_NAMESPACE_END -#endif /* WITH_OPENVDB */ - #endif /* __UTIL_VOLUME_H__ */ diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 02f6c435ee2..8cab33582fb 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -280,6 +280,7 @@ void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct /***************** Global funcs ****************************/ void BKE_ptcache_remove(void); +int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext); /************ ID specific functions ************************/ void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra); diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 30eb8dcb287..6da69b129be 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1814,7 +1814,7 @@ static int ptcache_path(PTCacheID *pid, char *filename) return BLI_add_slash(filename); /* new strlen() */ } -static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext) +int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext) { int len=0; char *idname; diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index ba7f73c2f63..8f197c8c42c 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -196,6 +196,8 @@ typedef struct SmokeDomainSettings { float vector_scale; char vector_draw_type; char pad2[3]; + + char cache_filename[1024]; } SmokeDomainSettings; diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 569c1ee5f3f..9809625ec50 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3505,6 +3505,7 @@ static void rna_generate_header(BlenderRNA *UNUSED(brna), FILE *f) static const char *cpp_classes = "" "\n" +"#include <cstdlib>\n" "#include <string>\n" "#include <string.h> /* for memcpy */\n" "\n" diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index b4ba306df3f..ce18c86b8d0 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -383,6 +383,15 @@ static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value) rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name)); } +static void rna_SmokeModifier_cache_filename_get(PointerRNA *ptr, char *filename) +{ + SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; + PTCacheID pid; + + BKE_ptcache_id_from_smoke(&pid, ptr->id.data, sds->smd); + ptcache_filename(&pid, filename, sds->smd->time, 1, 1); +} + #else static void rna_def_smoke_domain_settings(BlenderRNA *brna) @@ -805,6 +814,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3); RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "cache_filename", PROP_STRING, PROP_NONE); + RNA_def_property_string_maxlength(prop, 1024); + RNA_def_property_string_funcs(prop, "rna_SmokeModifier_cache_filename_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Filename", "Path to the .blend file"); } static void rna_def_smoke_flow_settings(BlenderRNA *brna) |