Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2016-11-13 23:42:35 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2016-11-13 23:42:35 +0300
commit28f4388c2ee815998141f0e4a5a671dec27354e3 (patch)
treec986f848cde3dec945302943ba1bc47bd07fe6da
parenta7461419d88da1b8aaba17cce96959b33c2c83a9 (diff)
parent099f7dc9ddb2be02cd7235d74b2c4c49aeb27d56 (diff)
Merge branch 'cvdb_ray_isect' into openvdb
-rw-r--r--intern/cycles/app/cycles_xml.cpp8
-rw-r--r--intern/cycles/blender/CMakeLists.txt1
-rw-r--r--intern/cycles/blender/blender_mesh.cpp2
-rw-r--r--intern/cycles/blender/blender_object.cpp41
-rw-r--r--intern/cycles/blender/blender_sync.cpp6
-rw-r--r--intern/cycles/blender/blender_sync.h5
-rw-r--r--intern/cycles/blender/blender_util.h20
-rw-r--r--intern/cycles/blender/blender_volume.cpp201
-rw-r--r--intern/cycles/device/CMakeLists.txt1
-rw-r--r--intern/cycles/device/device.h5
-rw-r--r--intern/cycles/device/device_cpu.cpp33
-rw-r--r--intern/cycles/kernel/CMakeLists.txt12
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume.h18
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume_all.h27
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume.h18
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume_all.h27
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h4
-rw-r--r--intern/cycles/kernel/geom/geom_volume.h10
-rw-r--r--intern/cycles/kernel/kernel_compat_cpu.h5
-rw-r--r--intern/cycles/kernel/kernel_globals.h13
-rw-r--r--intern/cycles/kernel/kernel_shader.h13
-rw-r--r--intern/cycles/kernel/kernel_textures.h3
-rw-r--r--intern/cycles/kernel/kernel_types.h5
-rw-r--r--intern/cycles/kernel/kernel_volume.h58
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel.cpp4
-rw-r--r--intern/cycles/kernel/openvdb/vdb_globals.h45
-rw-r--r--intern/cycles/kernel/openvdb/vdb_intern.h48
-rw-r--r--intern/cycles/kernel/openvdb/vdb_thread.cpp216
-rw-r--r--intern/cycles/kernel/openvdb/vdb_thread.h49
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp1
-rw-r--r--intern/cycles/render/attribute.cpp10
-rw-r--r--intern/cycles/render/nodes.cpp20
-rw-r--r--intern/cycles/render/nodes.h2
-rw-r--r--intern/cycles/render/scene.cpp3
-rw-r--r--intern/cycles/render/scene.h6
-rw-r--r--intern/cycles/render/session.cpp9
-rw-r--r--intern/cycles/render/shader.cpp18
-rw-r--r--intern/cycles/render/volume.cpp375
-rw-r--r--intern/cycles/render/volume.h50
-rw-r--r--intern/cycles/util/util_task.cpp8
-rw-r--r--intern/cycles/util/util_task.h4
-rw-r--r--intern/cycles/util/util_thread.h5
-rw-r--r--intern/cycles/util/util_volume.cpp153
-rw-r--r--intern/cycles/util/util_volume.h329
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h1
-rw-r--r--source/blender/blenkernel/intern/pointcache.c2
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h2
-rw-r--r--source/blender/makesrna/intern/makesrna.c1
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c15
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)