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
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/CMakeLists.txt4
-rw-r--r--intern/SConscript2
-rw-r--r--intern/audaspace/intern/AUD_Sequencer.cpp3
-rw-r--r--intern/audaspace/intern/AUD_Sequencer.h2
-rw-r--r--intern/audaspace/intern/AUD_SequencerReader.cpp5
-rw-r--r--intern/cycles/CMakeLists.txt9
-rw-r--r--intern/cycles/SConscript4
-rw-r--r--intern/cycles/app/CMakeLists.txt23
-rw-r--r--intern/cycles/app/cycles_alembic.cpp426
-rw-r--r--intern/cycles/app/cycles_alembic.h36
-rw-r--r--intern/cycles/app/cycles_standalone.cpp54
-rw-r--r--intern/cycles/app/cycles_xml.cpp32
-rw-r--r--intern/cycles/blender/CMakeLists.txt2
-rw-r--r--intern/cycles/blender/addon/properties.py25
-rw-r--r--intern/cycles/blender/addon/ui.py22
-rw-r--r--intern/cycles/blender/blender_curves.cpp717
-rw-r--r--intern/cycles/blender/blender_mesh.cpp120
-rw-r--r--intern/cycles/blender/blender_object.cpp98
-rw-r--r--intern/cycles/blender/blender_session.cpp49
-rw-r--r--intern/cycles/blender/blender_session.h2
-rw-r--r--intern/cycles/blender/blender_shader.cpp57
-rw-r--r--intern/cycles/blender/blender_sync.cpp2
-rw-r--r--intern/cycles/blender/blender_sync.h21
-rw-r--r--intern/cycles/blender/blender_texture.cpp116
-rw-r--r--intern/cycles/blender/blender_texture.h31
-rw-r--r--intern/cycles/blender/blender_util.h42
-rw-r--r--intern/cycles/bvh/bvh.cpp34
-rw-r--r--intern/cycles/bvh/bvh_params.h4
-rw-r--r--intern/cycles/cmake/external_libs.cmake2
-rw-r--r--intern/cycles/kernel/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h64
-rw-r--r--intern/cycles/kernel/geom/geom_volume.h20
-rw-r--r--intern/cycles/kernel/kernel_compat_cpu.h4
-rw-r--r--intern/cycles/kernel/kernel_globals.h4
-rw-r--r--intern/cycles/kernel/kernel_types.h9
-rw-r--r--intern/cycles/kernel/kernel_volume.h367
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel.cpp4
-rw-r--r--intern/cycles/kernel/svm/svm.h10
-rw-r--r--intern/cycles/kernel/svm/svm_openvdb.h55
-rw-r--r--intern/cycles/kernel/svm/svm_types.h14
-rw-r--r--intern/cycles/kernel/svm/svm_voxel.h61
-rw-r--r--intern/cycles/render/CMakeLists.txt8
-rw-r--r--intern/cycles/render/attribute.h1
-rw-r--r--intern/cycles/render/mesh.cpp20
-rw-r--r--intern/cycles/render/mesh.h5
-rw-r--r--intern/cycles/render/nodes.cpp180
-rw-r--r--intern/cycles/render/nodes.h40
-rw-r--r--intern/cycles/render/openvdb.cpp276
-rw-r--r--intern/cycles/render/openvdb.h72
-rw-r--r--intern/cycles/render/scene.cpp16
-rw-r--r--intern/cycles/render/scene.h10
-rw-r--r--intern/cycles/render/session.cpp4
-rw-r--r--intern/cycles/render/session.h1
-rw-r--r--intern/cycles/render/svm.cpp5
-rw-r--r--intern/cycles/render/svm.h4
-rw-r--r--intern/cycles/util/CMakeLists.txt7
-rw-r--r--intern/cycles/util/util_openvdb.h415
-rw-r--r--intern/openvdb/CMakeLists.txt61
-rw-r--r--intern/openvdb/SConscript53
-rw-r--r--intern/openvdb/intern/openvdb_dense_convert.cpp263
-rw-r--r--intern/openvdb/intern/openvdb_dense_convert.h140
-rw-r--r--intern/openvdb/intern/openvdb_primitive.cpp92
-rw-r--r--intern/openvdb/intern/openvdb_primitive.h47
-rw-r--r--intern/openvdb/intern/openvdb_reader.cpp107
-rw-r--r--intern/openvdb/intern/openvdb_reader.h51
-rw-r--r--intern/openvdb/intern/openvdb_render.cpp136
-rw-r--r--intern/openvdb/intern/openvdb_render.h15
-rw-r--r--intern/openvdb/intern/openvdb_writer.cpp93
-rw-r--r--intern/openvdb/intern/openvdb_writer.h55
-rw-r--r--intern/openvdb/openvdb_capi.cpp248
-rw-r--r--intern/openvdb/openvdb_capi.h131
-rw-r--r--intern/openvdb/openvdb_util.cpp80
-rw-r--r--intern/openvdb/openvdb_util.h31
-rw-r--r--intern/smoke/extern/smoke_API.h3
-rw-r--r--intern/smoke/intern/WTURBULENCE.cpp100
-rw-r--r--intern/smoke/intern/WTURBULENCE.h7
-rw-r--r--intern/smoke/intern/smoke_API.cpp11
77 files changed, 4876 insertions, 470 deletions
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index 74048c2a4cc..cf7f913d675 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -82,3 +82,7 @@ if(WIN32)
add_subdirectory(utfconv)
endif()
+if(WITH_OPENVDB)
+ add_subdirectory(openvdb)
+endif()
+
diff --git a/intern/SConscript b/intern/SConscript
index c0dafe37855..d416cab8aa2 100644
--- a/intern/SConscript
+++ b/intern/SConscript
@@ -63,3 +63,5 @@ if env['WITH_BF_BULLET']:
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-mingw', 'linuxcross', 'win64-vc'):
SConscript(['utfconv/SConscript'])
+if env['WITH_BF_OPENVDB']:
+ SConscript (['openvdb/SConscript'])
diff --git a/intern/audaspace/intern/AUD_Sequencer.cpp b/intern/audaspace/intern/AUD_Sequencer.cpp
index ddcf97e2ea1..a5b70232068 100644
--- a/intern/audaspace/intern/AUD_Sequencer.cpp
+++ b/intern/audaspace/intern/AUD_Sequencer.cpp
@@ -44,7 +44,8 @@ AUD_Sequencer::AUD_Sequencer(AUD_Specs specs, float fps, bool muted) :
m_distance_model(AUD_DISTANCE_MODEL_INVERSE_CLAMPED),
m_volume(1, 1.0f),
m_location(3),
- m_orientation(4)
+ m_orientation(4),
+ m_recursive(false)
{
AUD_Quaternion q;
m_orientation.write(q.get());
diff --git a/intern/audaspace/intern/AUD_Sequencer.h b/intern/audaspace/intern/AUD_Sequencer.h
index 1066eeae8e3..ef68efbbafc 100644
--- a/intern/audaspace/intern/AUD_Sequencer.h
+++ b/intern/audaspace/intern/AUD_Sequencer.h
@@ -201,6 +201,8 @@ public:
* \param entry The entry to remove.
*/
void remove(boost::shared_ptr<AUD_SequencerEntry> entry);
+
+ bool m_recursive;
};
#endif //__AUD_SEQUENCER_H__
diff --git a/intern/audaspace/intern/AUD_SequencerReader.cpp b/intern/audaspace/intern/AUD_SequencerReader.cpp
index aef93cd3896..b893b132fa3 100644
--- a/intern/audaspace/intern/AUD_SequencerReader.cpp
+++ b/intern/audaspace/intern/AUD_SequencerReader.cpp
@@ -78,6 +78,9 @@ AUD_Specs AUD_SequencerReader::getSpecs() const
void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
{
+ if (m_sequence->m_recursive)
+ return;
+
AUD_MutexLock lock(*m_sequence);
if(m_sequence->m_status != m_status)
@@ -192,7 +195,9 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
v2 -= v;
m_device.setListenerVelocity(v2 * m_sequence->m_fps);
+ m_sequence->m_recursive = true;
m_device.read(reinterpret_cast<data_t*>(buffer + specs.channels * pos), len);
+ m_sequence->m_recursive = false;
pos += len;
time += float(len) / float(specs.rate);
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index ed6961f49e0..6c1264ff594 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -146,6 +146,15 @@ if(WITH_CYCLES_OSL)
)
endif()
+if(WITH_OPENVDB)
+ add_definitions(-DWITH_OPENVDB)
+ add_definitions(-DOPENVDB_USE_BLOSC)
+ add_definitions(-DDWREAL_IS_DOUBLE=0)
+ include_directories(
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+endif()
+
add_definitions(
-DWITH_OPENCL
-DWITH_CUDA
diff --git a/intern/cycles/SConscript b/intern/cycles/SConscript
index 99df8c299fc..68eccf96a45 100644
--- a/intern/cycles/SConscript
+++ b/intern/cycles/SConscript
@@ -67,6 +67,10 @@ if env['WITH_BF_CYCLES_OSL']:
defs.append('OSL_STATIC_LIBRARY')
incs.append(cycles['BF_OSL_INC'])
+if env['WITH_BF_OPENVDB']:
+ defs.append('WITH_OPENVDB')
+ incs.append(env['BF_OPENVDB_INC'])
+
if env['WITH_BF_CYCLES_DEBUG']:
defs.append('WITH_CYCLES_DEBUG')
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index b000266cac2..b9a2abf1c9a 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -96,6 +96,12 @@ macro(cycles_target_link_libraries target)
${CMAKE_DL_LIBS}
${PLATFORM_LINKLIBS}
)
+ if(WITH_ALEMBIC)
+ target_link_libraries(
+ ${target}
+ ${ALEMBIC_LIBRARIES}
+ )
+ endif()
endmacro()
# Application build targets
@@ -106,6 +112,23 @@ if(WITH_CYCLES_STANDALONE)
cycles_xml.cpp
cycles_xml.h
)
+
+ if(WITH_ALEMBIC)
+ list(APPEND SRC
+ cycles_alembic.cpp
+ cycles_alembic.h
+ )
+ add_definitions(-DWITH_ALEMBIC)
+ include_directories(
+ SYSTEM
+ ${ALEMBIC_INCLUDE_DIRS}
+ )
+ endif()
+
+ if(WITH_HDF5)
+ add_definitions(-DWITH_HDF5)
+ endif()
+
add_executable(cycles ${SRC})
cycles_target_link_libraries(cycles)
diff --git a/intern/cycles/app/cycles_alembic.cpp b/intern/cycles/app/cycles_alembic.cpp
new file mode 100644
index 00000000000..3a1e6a6bcaa
--- /dev/null
+++ b/intern/cycles/app/cycles_alembic.cpp
@@ -0,0 +1,426 @@
+/*
+ * Copyright 2015 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 <stdio.h>
+
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+
+#include <Alembic/AbcCoreOgawa/ReadWrite.h>
+#ifdef WITH_HDF5
+#include <Alembic/AbcCoreHDF5/ReadWrite.h>
+#endif
+#include <Alembic/Abc/IArchive.h>
+#include <Alembic/Abc/IObject.h>
+#include <Alembic/Abc/ISampleSelector.h>
+#include <Alembic/Abc/ICompoundProperty.h>
+#include <Alembic/Abc/IScalarProperty.h>
+#include <Alembic/Abc/IArrayProperty.h>
+#include <Alembic/Abc/ArchiveInfo.h>
+#include <Alembic/AbcGeom/IPolyMesh.h>
+
+#include "camera.h"
+#include "film.h"
+#include "graph.h"
+#include "integrator.h"
+#include "light.h"
+#include "mesh.h"
+#include "nodes.h"
+#include "object.h"
+#include "shader.h"
+#include "scene.h"
+
+#include "subd_mesh.h"
+#include "subd_patch.h"
+#include "subd_split.h"
+
+#include "util_debug.h"
+#include "util_foreach.h"
+#include "util_path.h"
+#include "util_transform.h"
+#include "util_xml.h"
+
+#include "cycles_alembic.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace Alembic;
+using namespace Abc;
+using namespace AbcGeom;
+
+#define ABC_SAFE_CALL_BEGIN \
+ try {
+
+#define ABC_SAFE_CALL_END \
+ } \
+ catch (Alembic::Util::Exception e) { \
+ printf("%s", e.what()); \
+ }
+
+
+/* File */
+
+static const std::string g_sep(";");
+
+static void visitProperties(std::stringstream &ss, ICompoundProperty, std::string &);
+
+template <class PROP>
+static void visitSimpleArrayProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
+{
+ std::string ptype = "ArrayProperty ";
+ size_t asize = 0;
+
+ AbcA::ArraySamplePtr samp;
+ index_t maxSamples = iProp.getNumSamples();
+ for (index_t i = 0 ; i < maxSamples; ++i) {
+ iProp.get(samp, ISampleSelector( i ));
+ asize = samp->size();
+ };
+
+ std::string mdstring = "interpretation=";
+ mdstring += iProp.getMetaData().get("interpretation");
+
+ std::stringstream dtype;
+ dtype << "datatype=";
+ dtype << iProp.getDataType();
+
+ std::stringstream asizestr;
+ asizestr << ";arraysize=";
+ asizestr << asize;
+
+ mdstring += g_sep;
+
+ mdstring += dtype.str();
+
+ mdstring += asizestr.str();
+
+ ss << iIndent << " " << ptype << "name=" << iProp.getName()
+ << g_sep << mdstring << g_sep << "numsamps="
+ << iProp.getNumSamples() << std::endl;
+}
+
+template <class PROP>
+static void visitSimpleScalarProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
+{
+ std::string ptype = "ScalarProperty ";
+ size_t asize = 0;
+
+ const AbcA::DataType &dt = iProp.getDataType();
+ const Alembic::Util ::uint8_t extent = dt.getExtent();
+ Alembic::Util::Dimensions dims(extent);
+ AbcA::ArraySamplePtr samp = AbcA::AllocateArraySample( dt, dims );
+ index_t maxSamples = iProp.getNumSamples();
+ for (index_t i = 0 ; i < maxSamples; ++i) {
+ iProp.get(const_cast<void*>(samp->getData()), ISampleSelector( i ));
+ asize = samp->size();
+ };
+
+ std::string mdstring = "interpretation=";
+ mdstring += iProp.getMetaData().get("interpretation");
+
+ std::stringstream dtype;
+ dtype << "datatype=";
+ dtype << dt;
+
+ std::stringstream asizestr;
+ asizestr << ";arraysize=";
+ asizestr << asize;
+
+ mdstring += g_sep;
+
+ mdstring += dtype.str();
+
+ mdstring += asizestr.str();
+
+ ss << iIndent << " " << ptype << "name=" << iProp.getName()
+ << g_sep << mdstring << g_sep << "numsamps="
+ << iProp.getNumSamples() << std::endl;
+}
+
+static void visitCompoundProperty(std::stringstream &ss, ICompoundProperty iProp, std::string &ioIndent)
+{
+ std::string oldIndent = ioIndent;
+ ioIndent += " ";
+
+ std::string interp = "schema=";
+ interp += iProp.getMetaData().get("schema");
+
+ ss << ioIndent << "CompoundProperty " << "name=" << iProp.getName()
+ << g_sep << interp << std::endl;
+
+ visitProperties(ss, iProp, ioIndent);
+
+ ioIndent = oldIndent;
+}
+
+static void visitProperties(std::stringstream &ss, ICompoundProperty iParent, std::string &ioIndent )
+{
+ std::string oldIndent = ioIndent;
+ for (size_t i = 0 ; i < iParent.getNumProperties() ; i++) {
+ PropertyHeader header = iParent.getPropertyHeader(i);
+
+ if (header.isCompound()) {
+ visitCompoundProperty(ss, ICompoundProperty(iParent, header.getName()), ioIndent);
+ }
+ else if (header.isScalar()) {
+ visitSimpleScalarProperty(ss, IScalarProperty(iParent, header.getName()), ioIndent);
+ }
+ else {
+ assert(header.isArray());
+ visitSimpleArrayProperty(ss, IArrayProperty(iParent, header.getName()), ioIndent);
+ }
+ }
+
+ ioIndent = oldIndent;
+}
+
+static void visitObject(std::stringstream &ss, IObject iObj, std::string iIndent, AbcArchiveInfoLevel info_level)
+{
+ // Object has a name, a full name, some meta data,
+ // and then it has a compound property full of properties.
+ std::string path = iObj.getFullName();
+
+ if (iObj.isInstanceRoot()) {
+ if (path != "/") {
+ ss << "Object " << "name=" << path
+ << " [Instance " << iObj.instanceSourcePath() << "]"
+ << std::endl;
+ }
+ }
+ else if (iObj.isInstanceDescendant()) {
+ /* skip non-root instances to avoid repetition */
+ return;
+ }
+ else {
+ if (path != "/") {
+ ss << "Object " << "name=" << path << std::endl;
+ }
+
+ if (info_level >= ABC_INFO_PROPERTIES) {
+ // Get the properties.
+ ICompoundProperty props = iObj.getProperties();
+ visitProperties(ss, props, iIndent);
+ }
+
+ // now the child objects
+ for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
+ visitObject(ss, IObject(iObj, iObj.getChildHeader(i).getName()), iIndent, info_level);
+ }
+ }
+}
+
+static std::string abc_archive_info(IArchive &archive, AbcArchiveInfoLevel info_level)
+{
+ std::stringstream ss;
+
+ ss << "Alembic Archive Info for "
+ << Alembic::AbcCoreAbstract::GetLibraryVersion()
+ << std::endl;;
+
+ std::string appName;
+ std::string libraryVersionString;
+ Alembic::Util::uint32_t libraryVersion;
+ std::string whenWritten;
+ std::string userDescription;
+ GetArchiveInfo(archive,
+ appName,
+ libraryVersionString,
+ libraryVersion,
+ whenWritten,
+ userDescription);
+
+ if (appName != "") {
+ ss << " file written by: " << appName << std::endl;
+ ss << " using Alembic : " << libraryVersionString << std::endl;
+ ss << " written on : " << whenWritten << std::endl;
+ ss << " user description : " << userDescription << std::endl;
+ ss << std::endl;
+ }
+ else {
+// ss << argv[1] << std::endl;
+ ss << " (file doesn't have any ArchiveInfo)"
+ << std::endl;
+ ss << std::endl;
+ }
+
+ if (info_level >= ABC_INFO_OBJECTS)
+ visitObject(ss, archive.getTop(), "", info_level);
+
+ return ss.str();
+}
+
+/* ========================================================================= */
+
+struct AbcReadState {
+ Scene *scene; /* scene pointer */
+ float time;
+ Transform tfm; /* current transform state */
+ bool smooth; /* smooth normal state */
+ int shader; /* current shader */
+ string base; /* base path to current file*/
+ float dicing_rate; /* current dicing rate */
+ Mesh::DisplacementMethod displacement_method;
+};
+
+static ISampleSelector get_sample_selector(const AbcReadState &state)
+{
+ return ISampleSelector(state.time, ISampleSelector::kFloorIndex);
+}
+
+static Mesh *add_mesh(Scene *scene, const Transform& tfm)
+{
+ /* create mesh */
+ Mesh *mesh = new Mesh();
+ scene->meshes.push_back(mesh);
+
+ /* create object*/
+ Object *object = new Object();
+ object->mesh = mesh;
+ object->tfm = tfm;
+ scene->objects.push_back(object);
+
+ return mesh;
+}
+
+static void read_mesh(const AbcReadState &state, IPolyMesh object)
+{
+ /* add mesh */
+ Mesh *mesh = add_mesh(state.scene, state.tfm);
+ mesh->used_shaders.push_back(state.shader);
+
+ /* read state */
+ int shader = state.shader;
+ bool smooth = state.smooth;
+
+ mesh->displacement_method = state.displacement_method;
+
+ ISampleSelector ss = get_sample_selector(state);
+ IPolyMeshSchema schema = object.getSchema();
+
+ IPolyMeshSchema::Sample sample;
+ schema.get(sample, ss);
+
+ int totverts = sample.getPositions()->size();
+ int totfaces = sample.getFaceCounts()->size();
+ const V3f *P = sample.getPositions()->get();
+ const int32_t *verts = sample.getFaceIndices()->get();
+ const int32_t *nverts = sample.getFaceCounts()->get();
+
+ /* create vertices */
+ mesh->verts.reserve(totverts);
+ for(int i = 0; i < totverts; i++) {
+ mesh->verts.push_back(make_float3(P[i].x, P[i].y, P[i].z));
+ }
+
+ /* create triangles */
+ int index_offset = 0;
+
+ for(int i = 0; i < totfaces; i++) {
+ int n = nverts[i];
+ /* XXX TODO only supports tris and quads atm,
+ * need a proper tessellation algorithm in cycles.
+ */
+ if (n > 4) {
+ printf("%d-sided face found, only triangles and quads are supported currently", n);
+ n = 4;
+ }
+
+ for(int j = 0; j < n-2; j++) {
+ int v0 = verts[index_offset];
+ int v1 = verts[index_offset + j + 1];
+ int v2 = verts[index_offset + j + 2];
+
+ assert(v0 < (int)totverts);
+ assert(v1 < (int)totverts);
+ assert(v2 < (int)totverts);
+
+ mesh->add_triangle(v0, v1, v2, shader, smooth);
+ }
+
+ index_offset += n;
+ }
+
+ /* temporary for test compatibility */
+ mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
+}
+
+static void read_object(const AbcReadState &state, IObject object)
+{
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ IObject child = object.getChild(i);
+ const MetaData &metadata = child.getMetaData();
+
+ if (IPolyMeshSchema::matches(metadata)) {
+ read_mesh(state, IPolyMesh(child, kWrapExisting));
+ }
+ else {
+ read_object(state, child);
+ }
+ }
+}
+
+static void read_archive(Scene *scene, IArchive archive, const char *filepath)
+{
+ AbcReadState state;
+
+ state.scene = scene;
+ state.time = 0.0f; // TODO
+ state.tfm = transform_identity();
+ state.shader = scene->default_surface;
+ state.smooth = false;
+ state.dicing_rate = 0.1f;
+ state.base = path_dirname(filepath);
+
+ read_object(state, archive.getTop());
+
+ scene->params.bvh_type = SceneParams::BVH_STATIC;
+}
+
+void abc_read_ogawa_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level)
+{
+ IArchive archive;
+ ABC_SAFE_CALL_BEGIN
+ archive = IArchive(AbcCoreOgawa::ReadArchive(), filepath, ErrorHandler::kThrowPolicy);
+ ABC_SAFE_CALL_END
+
+ if (archive) {
+ if (info_level >= ABC_INFO_BASIC)
+ printf("%s", abc_archive_info(archive, info_level).c_str());
+
+ read_archive(scene, archive, filepath);
+ }
+}
+
+void abc_read_hdf5_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level)
+{
+#ifdef WITH_HDF5
+ IArchive archive;
+ ABC_SAFE_CALL_BEGIN
+ archive = IArchive(AbcCoreHDF5::ReadArchive(), filepath, ErrorHandler::kThrowPolicy);
+ ABC_SAFE_CALL_END
+
+ if (archive) {
+ if (info_level >= ABC_INFO_BASIC)
+ printf("%s", abc_archive_info(archive, info_level).c_str());
+
+ read_archive(scene, archive, filepath);
+ }
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/app/cycles_alembic.h b/intern/cycles/app/cycles_alembic.h
new file mode 100644
index 00000000000..df17f8b8fbe
--- /dev/null
+++ b/intern/cycles/app/cycles_alembic.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 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 __CYCLES_ALEMBIC_H__
+#define __CYCLES_ALEMBIC_H__
+
+CCL_NAMESPACE_BEGIN
+
+class Scene;
+
+enum AbcArchiveInfoLevel {
+ ABC_INFO_NONE = 0,
+ ABC_INFO_BASIC,
+ ABC_INFO_OBJECTS,
+ ABC_INFO_PROPERTIES,
+};
+
+void abc_read_ogawa_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level = ABC_INFO_NONE);
+void abc_read_hdf5_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level = ABC_INFO_NONE);
+
+CCL_NAMESPACE_END
+
+#endif /* __CYCLES_XML_H__ */
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index b0d49d6ee72..3980ca547c2 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -38,13 +38,23 @@
#endif
#include "cycles_xml.h"
+#ifdef WITH_ALEMBIC
+#include "cycles_alembic.h"
+#endif
CCL_NAMESPACE_BEGIN
+enum FileType {
+ FILETYPE_XML = 0,
+ FILETYPE_ABC_HDF5,
+ FILETYPE_ABC_OGAWA,
+};
+
struct Options {
Session *session;
Scene *scene;
string filepath;
+ FileType filetype;
int width, height;
SceneParams scene_params;
SessionParams session_params;
@@ -121,8 +131,22 @@ static void scene_init()
{
options.scene = new Scene(options.scene_params, options.session_params.device);
- /* Read XML */
- xml_read_file(options.scene, options.filepath.c_str());
+ /* Read file */
+ switch (options.filetype) {
+ case FILETYPE_XML:
+ xml_read_file(options.scene, options.filepath.c_str());
+ break;
+#ifdef WITH_ALEMBIC
+ case FILETYPE_ABC_OGAWA:
+ abc_read_ogawa_file(options.scene, options.filepath.c_str());
+ break;
+ case FILETYPE_ABC_HDF5:
+ abc_read_hdf5_file(options.scene, options.filepath.c_str());
+ break;
+#endif
+ default:
+ return;
+ }
/* Camera width/height override? */
if(!(options.width == 0 || options.height == 0)) {
@@ -356,6 +380,16 @@ static void options_parse(int argc, const char **argv)
/* shading system */
string ssname = "svm";
+ /* input file type */
+ string filetypes = "auto, xml";
+#ifdef WITH_ALEMBIC
+ filetypes += ", alembic_ogawa";
+#ifdef WITH_HDF5
+ filetypes += ", alembic_hdf5";
+#endif
+#endif
+ string filetype = "auto";
+
/* parse options */
ArgParse ap;
bool help = false, debug = false;
@@ -371,6 +405,7 @@ static void options_parse(int argc, const char **argv)
"--quiet", &options.quiet, "In background mode, don't print progress messages",
"--samples %d", &options.session_params.samples, "Number of samples to render",
"--output %s", &options.session_params.output_path, "File path to write output image",
+ "--filetype %s", &filetype, ("File type: " + filetypes).c_str(),
"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
"--width %d", &options.width, "Window width in pixel",
"--height %d", &options.height, "Window height in pixel",
@@ -416,6 +451,21 @@ static void options_parse(int argc, const char **argv)
else if(ssname == "svm")
options.scene_params.shadingsystem = SHADINGSYSTEM_SVM;
+ if(filetype == "auto") {
+ string extension = options.filepath.substr(options.filepath.find_last_of(".") + 1);
+
+ if (extension == "xml")
+ options.filetype = FILETYPE_XML;
+ else if (extension == "abc")
+ options.filetype = FILETYPE_ABC_OGAWA;
+ }
+ else if(filetype == "xml")
+ options.filetype = FILETYPE_XML;
+ else if(filetype == "alembic_ogawa")
+ options.filetype = FILETYPE_ABC_OGAWA;
+ else if(filetype == "alembic_hdf5")
+ options.filetype = FILETYPE_ABC_HDF5;
+
#ifndef WITH_CYCLES_STANDALONE_GUI
options.session_params.background = true;
#endif
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index edea8cd0ec4..77b0a6454ce 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -43,6 +43,9 @@
#include "util_xml.h"
#include "cycles_xml.h"
+#ifdef WITH_ALEMBIC
+#include "cycles_alembic.h"
+#endif
CCL_NAMESPACE_BEGIN
@@ -735,6 +738,13 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
xml_read_enum(&vtransform->convert_to, VectorTransformNode::convert_space_enum, node, "convert_to");
snode = vtransform;
}
+ 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;
+ }
else if(string_iequals(node.name(), "connect")) {
/* connect nodes */
vector<string> from_tokens, to_tokens;
@@ -1188,6 +1198,25 @@ static void xml_read_state(XMLReadState& state, pugi::xml_node node)
state.displacement_method = Mesh::DISPLACE_BOTH;
}
+/* Alembic */
+static void xml_read_alembic(const XMLReadState& state, pugi::xml_node node)
+{
+#ifdef WITH_ALEMBIC
+ string filepath;
+
+ if(xml_read_string(&filepath, node, "file")) {
+ filepath = path_join(state.base, filepath);
+
+ if(xml_equal_string(node, "type", "hdf5"))
+ abc_read_hdf5_file(state.scene, filepath.c_str(), ABC_INFO_BASIC);
+ else if(xml_equal_string(node, "type", "ogawa"))
+ abc_read_ogawa_file(state.scene, filepath.c_str(), ABC_INFO_BASIC);
+ else
+ abc_read_ogawa_file(state.scene, filepath.c_str(), ABC_INFO_BASIC); /* default */
+ }
+#endif
+}
+
/* Scene */
static void xml_read_include(const XMLReadState& state, const string& src);
@@ -1237,6 +1266,9 @@ static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
if(xml_read_string(&src, node, "src"))
xml_read_include(state, src);
}
+ else if(string_iequals(node.name(), "alembic")) {
+ xml_read_alembic(state, node);
+ }
else
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
}
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index fff9ed20bba..c6a2b919486 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -31,10 +31,12 @@ set(SRC
blender_session.cpp
blender_shader.cpp
blender_sync.cpp
+ blender_texture.cpp
CCL_api.h
blender_sync.h
blender_session.h
+ blender_texture.h
blender_util.h
)
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 16a807b3af5..0daf6784798 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -463,6 +463,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Use BVH spatial splits: longer builder time, faster render",
default=False,
)
+ cls.debug_use_triangle_storage = BoolProperty(
+ name="Use Triangle Storage",
+ description="use special storage with aligned triangle coordinates for faster "
+ "intesection check in expense of higher memory usage",
+ default=True,
+ )
cls.use_cache = BoolProperty(
name="Cache BVH",
description="Cache last built BVH to disk for faster re-render if no geometry changed",
@@ -511,6 +517,19 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
),
)
+ cls.use_camera_cull = BoolProperty(
+ name="Use Camera Cull",
+ description="Allow objects to be culled based on the camera frustum",
+ default=False,
+ )
+
+ cls.camera_cull_margin = FloatProperty(
+ name="Camera Cull Margin",
+ description="Margin for the camera space culling",
+ default=0.1,
+ min=0.0, max=5.0
+ )
+
@classmethod
def unregister(cls):
del bpy.types.Scene.cycles
@@ -890,6 +909,12 @@ class CyclesObjectBlurSettings(bpy.types.PropertyGroup):
default=1,
)
+ cls.use_camera_cull = BoolProperty(
+ name="Use Camera Cull",
+ description="Allow this object and it's duplicators to be culled by camera space culling",
+ default=False,
+ )
+
@classmethod
def unregister(cls):
del bpy.types.Object.cycles
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index f6ff86ac30e..7fcb99d9e15 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -322,6 +322,11 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
subsub.enabled = not rd.use_border
subsub.prop(rd, "use_save_buffers")
+ sub.prop(cscene, "use_camera_cull")
+ subsub = col.column()
+ subsub.active = cscene.use_camera_cull
+ subsub.prop(cscene, "camera_cull_margin")
+
col = split.column(align=True)
col.label(text="Viewport:")
@@ -339,6 +344,7 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
col.label(text="Acceleration structure:")
col.prop(cscene, "debug_use_spatial_splits")
+ col.prop(cscene, "debug_use_triangle_storage")
class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
@@ -687,8 +693,8 @@ class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
sub.prop(cob, "motion_steps", text="Steps")
-class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
- bl_label = "Ray Visibility"
+class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel):
+ bl_label = "Cycles Settings"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@@ -703,8 +709,10 @@ class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
layout = self.layout
ob = context.object
+ cob = ob.cycles
visibility = ob.cycles_visibility
+ layout.label(text="Ray Visibility:")
flow = layout.column_flow()
flow.prop(visibility, "camera")
@@ -716,6 +724,9 @@ class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
if ob.type != 'LAMP':
flow.prop(visibility, "shadow")
+ layout.label(text="Performance:")
+ layout.prop(cob, "use_camera_cull")
+
class CYCLES_OT_use_shading_nodes(Operator):
"""Enable nodes on a material, world or lamp"""
@@ -1225,7 +1236,8 @@ class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
node = context.texture_node
- return node and CyclesButtonsPanel.poll(context)
+ # TODO(sergey): perform a faster/nicer check?
+ return node and hasattr(node, 'texture_mapping') and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
@@ -1449,7 +1461,8 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
- rd = context.scene.render
+ scene = context.scene
+ rd = scene.render
layout.active = rd.use_simplify
split = layout.split()
@@ -1529,6 +1542,7 @@ def get_panels():
"DATA_PT_curve_texture_space",
"DATA_PT_mball_texture_space",
"DATA_PT_vertex_groups",
+ "DATA_PT_face_maps",
"DATA_PT_shape_keys",
"DATA_PT_uv_texture",
"DATA_PT_vertex_colors",
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index dba801fc4df..4ed0b910f35 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -37,15 +37,14 @@ void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, floa
void interp_weights(float t, float data[4]);
float shaperadius(float shape, float root, float tip, float time);
void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData);
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num);
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num);
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background);
void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData);
void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
float3 RotCam, bool is_ortho);
void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution);
void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata);
+void ExportCurveUV(Mesh *mesh, ParticleCurveData *CData, ustring name, bool active_render, int primitive, int vert_offset, int resol);
void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata);
+void ExportCurveVcol(Mesh *mesh, ParticleCurveData *CData, ustring name, int primitive, int vert_offset, int resol);
ParticleCurveData::ParticleCurveData()
{
@@ -119,206 +118,330 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl
curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
}
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
+static void ObtainCacheParticleData(Mesh *mesh, BL::Object b_ob, BL::ParticleSystem b_psys, const Transform &itfm,
+ ParticleCurveData *CData, bool background)
{
- int curvenum = 0;
- int keyno = 0;
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
+ int shader = mesh->used_shaders[mi];
+ int draw_step = background ? b_part.render_step() : b_part.draw_step();
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if(b_part.child_type() == 0)
+ totcurves += totparts;
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
+ if(totcurves == 0)
+ return;
- Transform tfm = get_transform(b_ob->matrix_world());
- Transform itfm = transform_quick_inverse(tfm);
+ int ren_step = (1 << draw_step) + 1;
+ if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
+ ren_step += b_part.kink_extra_steps();
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
+
+ int keyno = CData->curvekey_co.size();
+ int curvenum = CData->curve_keynum.size();
+
+ CData->psys_firstcurve.push_back(curvenum);
+ CData->psys_curvenum.push_back(totcurves);
+ CData->psys_shader.push_back(shader);
+
+ float radius = get_float(cpsys, "radius_scale") * 0.5f;
+
+ CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
+ CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
+ CData->psys_shape.push_back(get_float(cpsys, "shape"));
+ CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
+
+ int pa_no = 0;
+ if(!(b_part.child_type() == 0))
+ pa_no = totparts;
+
+ int num_add = (totparts+totchild - pa_no);
+ CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
+ CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
+ CData->curve_length.reserve(CData->curve_length.size() + num_add);
+ CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
+ CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
+
+ for(; pa_no < totparts+totchild; pa_no++) {
+ int keynum = 0;
+ CData->curve_firstkey.push_back(keyno);
+
+ float curve_length = 0.0f;
+ float3 pcKey;
+ for(int step_no = 0; step_no < ren_step; step_no++) {
+ float nco[3];
+ b_psys.co_hair(b_ob, pa_no, step_no, nco);
+ float3 cKey = make_float3(nco[0], nco[1], nco[2]);
+ cKey = transform_point(&itfm, cKey);
+ if(step_no > 0) {
+ float step_length = len(cKey - pcKey);
+ if(step_length == 0.0f)
+ continue;
+ curve_length += step_length;
+ }
+ CData->curvekey_co.push_back(cKey);
+ CData->curvekey_time.push_back(curve_length);
+ pcKey = cKey;
+ keynum++;
+ }
+ keyno += keynum;
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
- int shader = mesh->used_shaders[mi];
- int draw_step = background ? b_part.render_step() : b_part.draw_step();
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if(b_part.child_type() == 0)
- totcurves += totparts;
+ CData->curve_keynum.push_back(keynum);
+ CData->curve_length.push_back(curve_length);
+ curvenum++;
+ }
+}
- if(totcurves == 0)
- continue;
+static void ObtainCacheParticleUV(Mesh * /*mesh*/, BL::Object /*b_ob*/, BL::Mesh b_mesh, BL::ParticleSystem b_psys, BL::ParticleSystemModifier b_psmd,
+ ParticleCurveData *CData, bool background, int uv_num)
+{
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if(b_part.child_type() == 0)
+ totcurves += totparts;
- int ren_step = (1 << draw_step) + 1;
- if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
- ren_step += b_part.kink_extra_steps();
+ if(totcurves == 0)
+ return;
- PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
+ int pa_no = 0;
+ if(!(b_part.child_type() == 0))
+ pa_no = totparts;
- CData->psys_firstcurve.push_back(curvenum);
- CData->psys_curvenum.push_back(totcurves);
- CData->psys_shader.push_back(shader);
+ int num_add = (totparts+totchild - pa_no);
+ CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
- float radius = get_float(cpsys, "radius_scale") * 0.5f;
-
- CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
- CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
- CData->psys_shape.push_back(get_float(cpsys, "shape"));
- CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
-
- int pa_no = 0;
- if(!(b_part.child_type() == 0))
- pa_no = totparts;
-
- int num_add = (totparts+totchild - pa_no);
- CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
- CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
- CData->curve_length.reserve(CData->curve_length.size() + num_add);
- CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
- CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
-
- for(; pa_no < totparts+totchild; pa_no++) {
- int keynum = 0;
- CData->curve_firstkey.push_back(keyno);
-
- float curve_length = 0.0f;
- float3 pcKey;
- for(int step_no = 0; step_no < ren_step; step_no++) {
- float nco[3];
- b_psys.co_hair(*b_ob, pa_no, step_no, nco);
- float3 cKey = make_float3(nco[0], nco[1], nco[2]);
- cKey = transform_point(&itfm, cKey);
- if(step_no > 0) {
- float step_length = len(cKey - pcKey);
- if(step_length == 0.0f)
- continue;
- curve_length += step_length;
- }
- CData->curvekey_co.push_back(cKey);
- CData->curvekey_time.push_back(curve_length);
- pcKey = cKey;
- keynum++;
- }
- keyno += keynum;
+ BL::ParticleSystem::particles_iterator b_pa;
+ b_psys.particles.begin(b_pa);
+ for(; pa_no < totparts+totchild; pa_no++) {
+ /* Add UVs */
+ BL::Mesh::tessface_uv_textures_iterator l;
+ b_mesh.tessface_uv_textures.begin(l);
- CData->curve_keynum.push_back(keynum);
- CData->curve_length.push_back(curve_length);
- curvenum++;
- }
- }
- }
- }
+ float3 uv = make_float3(0.0f, 0.0f, 0.0f);
+ if(b_mesh.tessface_uv_textures.length())
+ b_psys.uv_on_emitter(b_psmd, *b_pa, pa_no, uv_num, &uv.x);
+ CData->curve_uv.push_back(uv);
- return true;
+ if(pa_no < totparts && b_pa != b_psys.particles.end())
+ ++b_pa;
+ }
}
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num)
+static void ObtainCacheParticleVcol(Mesh * /*mesh*/, BL::Object /*b_ob*/, BL::Mesh b_mesh, BL::ParticleSystem b_psys, BL::ParticleSystemModifier b_psmd,
+ ParticleCurveData *CData, bool background, int vcol_num)
{
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if(b_part.child_type() == 0)
+ totcurves += totparts;
- CData->curve_uv.clear();
+ if(totcurves == 0)
+ return;
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ int pa_no = 0;
+ if(!(b_part.child_type() == 0))
+ pa_no = totparts;
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if(b_part.child_type() == 0)
- totcurves += totparts;
+ int num_add = (totparts+totchild - pa_no);
+ CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
- if(totcurves == 0)
- continue;
+ BL::ParticleSystem::particles_iterator b_pa;
+ b_psys.particles.begin(b_pa);
+ for(; pa_no < totparts+totchild; pa_no++) {
+ /* Add vertex colors */
+ BL::Mesh::tessface_vertex_colors_iterator l;
+ b_mesh.tessface_vertex_colors.begin(l);
- int pa_no = 0;
- if(!(b_part.child_type() == 0))
- pa_no = totparts;
+ float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
+ if(b_mesh.tessface_vertex_colors.length())
+ b_psys.mcol_on_emitter(b_psmd, *b_pa, pa_no, vcol_num, &vcol.x);
+ CData->curve_vcol.push_back(vcol);
- int num_add = (totparts+totchild - pa_no);
- CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
+ if(pa_no < totparts && b_pa != b_psys.particles.end())
+ ++b_pa;
+ }
+}
+
+/* A little bit of templated code here to avoid much duplication for parent/child strands:
+ * Most attributes are the same for both types, but some are handled slightly differently.
+ * These attributes are handled by templated utility functions that automatically get selected by type.
+ */
+template <typename StrandsT>
+struct StrandsTraits;
- BL::ParticleSystem::particles_iterator b_pa;
- b_psys.particles.begin(b_pa);
- for(; pa_no < totparts+totchild; pa_no++) {
- /* Add UVs */
- BL::Mesh::tessface_uv_textures_iterator l;
- b_mesh->tessface_uv_textures.begin(l);
+template<>
+struct StrandsTraits<BL::Strands>
+{
+ typedef BL::StrandsCurve curve_t;
+ typedef BL::StrandsVertex vertex_t;
+
+ static float3 get_location(BL::Strands b_strands, int index)
+ {
+ float *co = (b_strands.has_motion_state())? b_strands.motion_state[index].location() : b_strands.vertices[index].location();
+ return make_float3(co[0], co[1], co[2]);
+ }
+ static float3 get_uv(BL::Strands /*b_strands*/, int /*index*/, int /*uv_num*/)
+ {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+ static float3 get_vcol(BL::Strands /*b_strands*/, int /*index*/, int /*vcol_num*/)
+ {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+};
- float3 uv = make_float3(0.0f, 0.0f, 0.0f);
- if(b_mesh->tessface_uv_textures.length())
- b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
- CData->curve_uv.push_back(uv);
+template<>
+struct StrandsTraits<BL::StrandsChildren>
+{
+ typedef BL::StrandsChildCurve curve_t;
+ typedef BL::StrandsChildVertex vertex_t;
+
+ static float3 get_location(BL::StrandsChildren b_strands, int index)
+ {
+ float *co = b_strands.vertices[index].location();
+ return make_float3(co[0], co[1], co[2]);
+ }
+ static float3 get_uv(BL::StrandsChildren b_strands, int index, int uv_num)
+ {
+ if (uv_num < b_strands.num_curve_uv_layers()) {
+ size_t offset = uv_num * b_strands.curves.length();
+ float *uv = b_strands.curve_uvs[offset + index].uv();
+ return make_float3(uv[0], uv[1], 0.0f);
+ }
+ else
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+ static float3 get_vcol(BL::StrandsChildren b_strands, int index, int vcol_num)
+ {
+ if (vcol_num < b_strands.num_curve_vcol_layers()) {
+ size_t offset = vcol_num * b_strands.curves.length();
+ float *vcol = b_strands.curve_vcols[offset + index].vcol();
+ return make_float3(vcol[0], vcol[1], vcol[2]);
+ }
+ else
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+};
- if(pa_no < totparts && b_pa != b_psys.particles.end())
- ++b_pa;
- }
+template <typename StrandsT>
+static bool ObtainCacheStrandsData(Mesh *mesh, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem b_psys, StrandsT b_strands, const Transform &/*itfm*/,
+ ParticleCurveData *CData, bool /*background*/)
+{
+ typedef StrandsTraits<StrandsT> traits;
+ typedef typename traits::curve_t CurveT;
+
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
+
+ int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
+ int shader = mesh->used_shaders[mi];
+
+ int totcurves = b_strands.curves.length();
+ int totvert = b_strands.vertices.length();
+
+ int keyno = CData->curvekey_co.size();
+ int curvenum = CData->curve_keynum.size();
+
+ CData->psys_firstcurve.push_back(curvenum);
+ CData->psys_curvenum.push_back(totcurves);
+ CData->psys_shader.push_back(shader);
+
+ float radius = get_float(cpsys, "radius_scale") * 0.5f;
+
+ CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
+ CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
+ CData->psys_shape.push_back(get_float(cpsys, "shape"));
+ CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
+
+ CData->curve_firstkey.reserve(CData->curve_firstkey.size() + totcurves);
+ CData->curve_keynum.reserve(CData->curve_keynum.size() + totcurves);
+ CData->curve_length.reserve(CData->curve_length.size() + totcurves);
+ CData->curvekey_co.reserve(CData->curvekey_co.size() + totvert);
+ CData->curvekey_time.reserve(CData->curvekey_time.size() + totvert);
+
+ int icurve = 0;
+ int ivert = 0;
+ for(; icurve < totcurves; ++icurve) {
+ CurveT b_curve = b_strands.curves[icurve];
+ int numverts = b_curve.size();
+ int showverts = b_curve.render_size();
+ int usedverts = 0;
+ CData->curve_firstkey.push_back(keyno);
+
+ float curve_length = 0.0f;
+ float3 pcKey;
+ for(int cvert = 0; cvert < showverts; ++cvert) {
+ float3 cKey = traits::get_location(b_strands, ivert + cvert);
+
+ if(cvert > 0) {
+ float step_length = len(cKey - pcKey);
+ if(step_length == 0.0f)
+ continue;
+ curve_length += step_length;
}
+ CData->curvekey_co.push_back(cKey);
+ CData->curvekey_time.push_back(curve_length);
+ pcKey = cKey;
+ usedverts++;
}
- }
+ keyno += usedverts;
+ ivert += numverts;
+ CData->curve_keynum.push_back(usedverts);
+ CData->curve_length.push_back(curve_length);
+ curvenum++;
+ }
+
return true;
}
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num)
+template <typename StrandsT>
+static bool ObtainCacheStrandsUV(Mesh * /*mesh*/, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem /*b_psys*/, StrandsT b_strands,
+ ParticleCurveData *CData, bool /*background*/, int uv_num)
{
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
-
- CData->curve_vcol.clear();
-
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if(b_part.child_type() == 0)
- totcurves += totparts;
-
- if(totcurves == 0)
- continue;
-
- int pa_no = 0;
- if(!(b_part.child_type() == 0))
- pa_no = totparts;
-
- int num_add = (totparts+totchild - pa_no);
- CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
+ typedef StrandsTraits<StrandsT> traits;
+
+// BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
- BL::ParticleSystem::particles_iterator b_pa;
- b_psys.particles.begin(b_pa);
- for(; pa_no < totparts+totchild; pa_no++) {
- /* Add vertex colors */
- BL::Mesh::tessface_vertex_colors_iterator l;
- b_mesh->tessface_vertex_colors.begin(l);
+ int totcurves = b_strands.curves.length();
- float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
- if(b_mesh->tessface_vertex_colors.length())
- b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
- CData->curve_vcol.push_back(vcol);
+ CData->curve_uv.reserve(CData->curve_uv.size() + totcurves);
- if(pa_no < totparts && b_pa != b_psys.particles.end())
- ++b_pa;
- }
- }
- }
+ int icurve = 0;
+ for(; icurve < totcurves; ++icurve) {
+ CData->curve_uv.push_back(traits::get_uv(b_strands, icurve, uv_num));
}
+
+ return true;
+}
+template <typename StrandsT>
+static bool ObtainCacheStrandsVcol(Mesh * /*mesh*/, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem /*b_psys*/, StrandsT b_strands,
+ ParticleCurveData *CData, bool /*background*/, int vcol_num)
+{
+ typedef StrandsTraits<StrandsT> traits;
+
+// BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+ int totcurves = b_strands.curves.length();
+
+ CData->curve_vcol.reserve(CData->curve_vcol.size() + totcurves);
+
+ int icurve = 0;
+ for(; icurve < totcurves; ++icurve) {
+ CData->curve_vcol.push_back(traits::get_vcol(b_strands, icurve, vcol_num));
+ }
+
return true;
}
@@ -750,6 +873,39 @@ void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol,
}
}
+void ExportCurveUV(Mesh *mesh, ParticleCurveData *CData, ustring name, bool active_render, int primitive, int vert_offset, int resol)
+{
+ AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
+ Attribute *attr_uv;
+
+ if(primitive == CURVE_TRIANGLES) {
+ if(active_render)
+ attr_uv = mesh->attributes.add(std, name);
+ else
+ attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
+
+ float3 *uv = attr_uv->data_float3();
+
+ ExportCurveTriangleUV(CData, vert_offset, resol, uv);
+ }
+ else {
+ if(active_render)
+ attr_uv = mesh->curve_attributes.add(std, name);
+ else
+ attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
+
+ float3 *uv = attr_uv->data_float3();
+
+ if(uv) {
+ size_t i = 0;
+
+ for(size_t curve = 0; curve < CData->curve_uv.size(); curve++)
+ if(!(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f))
+ uv[i++] = CData->curve_uv[curve];
+ }
+ }
+}
+
void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata)
{
if(cdata == NULL)
@@ -782,6 +938,31 @@ void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int reso
}
}
+void ExportCurveVcol(Mesh *mesh, ParticleCurveData *CData, ustring name, int primitive, int vert_offset, int resol)
+{
+ if(primitive == CURVE_TRIANGLES) {
+ Attribute *attr_vcol = mesh->attributes.add(name, TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
+
+ uchar4 *cdata = attr_vcol->data_uchar4();
+
+ ExportCurveTriangleVcol(CData, vert_offset, resol, cdata);
+ }
+ else {
+ Attribute *attr_vcol = mesh->curve_attributes.add(name, TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
+
+ float3 *fdata = attr_vcol->data_float3();
+
+ if(fdata) {
+ size_t i = 0;
+
+ for(size_t curve = 0; curve < CData->curve_vcol.size(); curve++)
+ if(!(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f))
+ fdata[i++] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
+ }
+ }
+}
+
+
/* Hair Curve Sync */
void BlenderSync::sync_curve_settings()
@@ -856,8 +1037,61 @@ void BlenderSync::sync_curve_settings()
curve_system_manager->tag_update(scene);
}
-void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index)
+struct CurvesPSysData {
+ CurvesPSysData(BL::ParticleSystemModifier b_psmd=PointerRNA_NULL, BL::ParticleSystem b_psys=PointerRNA_NULL,
+ BL::Strands b_strands=PointerRNA_NULL, BL::StrandsChildren b_strands_children=PointerRNA_NULL) :
+ b_psmd(b_psmd), b_psys(b_psys), b_strands(b_strands), b_strands_children(b_strands_children)
+ {}
+
+ BL::ParticleSystemModifier b_psmd;
+ BL::ParticleSystem b_psys;
+ BL::Strands b_strands;
+ BL::StrandsChildren b_strands_children;
+};
+
+static void curves_get_psys_data(std::vector<CurvesPSysData> &b_psys_list, BL::Scene b_scene, BL::Object b_ob, BL::Object b_parent, BL::DupliObject b_dupli_ob, bool preview)
+{
+ BL::Object::modifiers_iterator b_mod;
+ for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
+ if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (preview ? b_mod->show_viewport() : b_mod->show_render())) {
+ BL::ParticleSystemModifier b_psmd((const PointerRNA)b_mod->ptr);
+ BL::ParticleSystem b_psys((const PointerRNA)b_psmd.particle_system().ptr);
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+ if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
+ int settings = preview ? 1 : 2;
+
+ BL::StrandsChildren b_strands_children = PointerRNA_NULL;
+ BL::Strands b_strands = PointerRNA_NULL;
+
+ if (b_dupli_ob && b_parent) {
+ b_strands_children = b_dupli_ob.strands_children_new(b_scene, b_parent, b_psys, settings);
+ if (!b_strands_children)
+ b_strands = b_dupli_ob.strands_new(b_scene, b_parent, b_psys, settings);
+ }
+
+ b_psys_list.push_back(CurvesPSysData(b_psmd, b_psys, b_strands, b_strands_children));
+ }
+ }
+ }
+}
+
+static void curves_free_psys_data(std::vector<CurvesPSysData> &b_psys_list, BL::DupliObject b_dupli_ob)
+{
+ /* free temporary strands data */
+ for (int i = 0; i < b_psys_list.size(); ++i) {
+ CurvesPSysData &psys_data = b_psys_list[i];
+ if (psys_data.b_strands)
+ b_dupli_ob.strands_free(psys_data.b_strands);
+ if (psys_data.b_strands_children)
+ b_dupli_ob.strands_children_free(psys_data.b_strands_children);
+ }
+}
+
+void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent, bool motion, int time_index, BL::DupliObject b_dupli_ob)
{
+ BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
+
if(!motion) {
/* Clear stored curve data */
mesh->curve_keys.clear();
@@ -888,27 +1122,46 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
if(!preview)
set_resolution(&b_ob, &b_scene, true);
- ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
+ Transform tfm = get_transform(b_ob.matrix_world());
+ Transform itfm = transform_quick_inverse(tfm);
+
+ /* obtain camera parameters */
+ float3 RotCam;
+ Camera *camera = scene->camera;
+ if(camera->type == CAMERA_ORTHOGRAPHIC) {
+ Transform &ctfm = camera->matrix;
+ RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
+ }
+ else {
+ Transform &ctfm = camera->matrix;
+ RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w));
+ }
+ bool is_ortho_camera = camera->type == CAMERA_ORTHOGRAPHIC;
+
+ std::vector<CurvesPSysData> b_psys_list;
+ curves_get_psys_data(b_psys_list, b_scene, b_ob, b_parent, b_dupli_ob, preview);
+
+ for (int i = 0; i < b_psys_list.size(); ++i) {
+ CurvesPSysData &psys_data = b_psys_list[i];
+ if (psys_data.b_strands_children)
+ /* use child strands cache */
+ ObtainCacheStrandsData(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
+ itfm, &CData, !preview);
+ else if (psys_data.b_strands)
+ /* use parent strands cache */
+ ObtainCacheStrandsData(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
+ itfm, &CData, !preview);
+ else {
+ /* use object data */
+ ObtainCacheParticleData(mesh, b_ob, psys_data.b_psys,
+ itfm, &CData, !preview);
+ }
+ }
/* add hair geometry to mesh */
if(primitive == CURVE_TRIANGLES) {
if(triangle_method == CURVE_CAMERA_TRIANGLES) {
- /* obtain camera parameters */
- float3 RotCam;
- Camera *camera = scene->camera;
- Transform &ctfm = camera->matrix;
- if(camera->type == CAMERA_ORTHOGRAPHIC) {
- RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
- }
- else {
- Transform tfm = get_transform(b_ob.matrix_world());
- Transform itfm = transform_quick_inverse(tfm);
- RotCam = transform_point(&itfm, make_float3(ctfm.x.w,
- ctfm.y.w,
- ctfm.z.w));
- }
- bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC;
- ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho);
+ ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho_camera);
}
else {
ExportCurveTriangleGeometry(mesh, &CData, resolution);
@@ -955,33 +1208,31 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
int vcol_num = 0;
for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
+ ustring name = ustring(l->name().c_str());
+
if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
continue;
- ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
-
- if(primitive == CURVE_TRIANGLES) {
- Attribute *attr_vcol = mesh->attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
-
- uchar4 *cdata = attr_vcol->data_uchar4();
-
- ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata);
- }
- else {
- Attribute *attr_vcol = mesh->curve_attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
-
- float3 *fdata = attr_vcol->data_float3();
-
- if(fdata) {
- size_t i = 0;
-
- for(size_t curve = 0; curve < CData.curve_vcol.size(); curve++)
- if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
- fdata[i++] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
+ CData.curve_vcol.clear();
+
+ for (int i = 0; i < b_psys_list.size(); ++i) {
+ CurvesPSysData &psys_data = b_psys_list[i];
+ if (psys_data.b_strands_children)
+ /* use child strands cache */
+ ObtainCacheStrandsVcol(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
+ &CData, !preview, vcol_num);
+ else if (psys_data.b_strands)
+ /* use parent strands cache */
+ ObtainCacheStrandsVcol(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
+ &CData, !preview, vcol_num);
+ else {
+ /* use object data */
+ ObtainCacheParticleVcol(mesh, b_ob, b_mesh, psys_data.b_psys, psys_data.b_psmd,
+ &CData, !preview, vcol_num);
}
}
+
+ ExportCurveVcol(mesh, &CData, name, primitive, tri_num * 3, used_res);
}
}
@@ -992,45 +1243,37 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
bool active_render = l->active_render();
- AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
ustring name = ustring(l->name().c_str());
/* UV map */
- if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
- Attribute *attr_uv;
-
- ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num);
-
- if(primitive == CURVE_TRIANGLES) {
- if(active_render)
- attr_uv = mesh->attributes.add(std, name);
- else
- attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
-
- float3 *uv = attr_uv->data_float3();
-
- ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv);
- }
+ if(!(mesh->need_attribute(scene, name) || (active_render && mesh->need_attribute(scene, ATTR_STD_UV))))
+ continue;
+
+ CData.curve_uv.clear();
+
+ for (int i = 0; i < b_psys_list.size(); ++i) {
+ CurvesPSysData &psys_data = b_psys_list[i];
+ if (psys_data.b_strands_children)
+ /* use child strands cache */
+ ObtainCacheStrandsUV(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
+ &CData, !preview, uv_num);
+ else if (psys_data.b_strands)
+ /* use parent strands cache */
+ ObtainCacheStrandsUV(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
+ &CData, !preview, uv_num);
else {
- if(active_render)
- attr_uv = mesh->curve_attributes.add(std, name);
- else
- attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
-
- float3 *uv = attr_uv->data_float3();
-
- if(uv) {
- size_t i = 0;
-
- for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
- if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
- uv[i++] = CData.curve_uv[curve];
- }
+ /* use object data */
+ ObtainCacheParticleUV(mesh, b_ob, b_mesh, psys_data.b_psys, psys_data.b_psmd,
+ &CData, !preview, uv_num);
}
}
+
+ ExportCurveUV(mesh, &CData, name, active_render, primitive, tri_num * 3, used_res);
}
}
+ curves_free_psys_data(b_psys_list, b_dupli_ob);
+
if(!preview)
set_resolution(&b_ob, &b_scene, false);
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index d88ebb854d2..3fa80a89947 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -229,7 +229,13 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer *b_l
/* Create Volume Attribute */
-static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame)
+static void create_mesh_volume_attribute(BL::Object b_ob,
+ Mesh *mesh,
+ ImageManager *image_manager,
+ AttributeStandard std,
+ float frame,
+ AttributeStandard special_std = ATTR_STD_NONE,
+ bool from_alpha = false)
{
BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
@@ -240,17 +246,35 @@ static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManag
VoxelAttribute *volume_data = attr->data_voxel();
bool is_float, is_linear;
bool animated = false;
+ AttributeStandard data_attr = (special_std == ATTR_STD_NONE) ? std : special_std;
volume_data->manager = image_manager;
- volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
+ volume_data->slot = image_manager->add_image(Attribute::standard_name(data_attr),
b_ob.ptr.data, animated, frame, is_float, is_linear, INTERPOLATION_LINEAR, true);
+ volume_data->from_alpha = from_alpha;
}
static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh, float frame)
{
/* for smoke volume rendering */
- if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY))
- create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY, frame);
+ if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY)) {
+ /* Special case: we re-map density to A channel of Color texture
+ * if both attributes are requested.
+ */
+ AttributeStandard special_std = ATTR_STD_VOLUME_DENSITY;
+ bool from_alpha = false;
+ if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR)) {
+ special_std = ATTR_STD_VOLUME_COLOR;
+ from_alpha = true;
+ }
+ create_mesh_volume_attribute(b_ob,
+ mesh,
+ scene->image_manager,
+ ATTR_STD_VOLUME_DENSITY,
+ frame,
+ special_std,
+ from_alpha);
+ }
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR))
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR, frame);
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME))
@@ -422,6 +446,52 @@ static void attr_create_pointiness(Scene *scene,
}
}
+/* Create vertex custom attributes. */
+static void attr_create_vertex_properties(Scene *scene,
+ Mesh *mesh,
+ BL::Mesh b_mesh)
+{
+ {
+ BL::Mesh::vertex_layers_float_iterator l;
+ for(b_mesh.vertex_layers_float.begin(l); l != b_mesh.vertex_layers_float.end(); ++l) {
+ if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
+ continue;
+
+ Attribute *attr = mesh->attributes.add(
+ ustring(l->name().c_str()), TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
+
+ BL::MeshVertexFloatPropertyLayer::data_iterator d;
+ float *data = attr->data_float();
+ size_t i = 0;
+
+ for(l->data.begin(d); d != l->data.end(); ++d, ++i) {
+ *data = d->value();
+ data += 1;
+ }
+ }
+ }
+
+ {
+ BL::Mesh::vertex_layers_int_iterator l;
+ for(b_mesh.vertex_layers_int.begin(l); l != b_mesh.vertex_layers_int.end(); ++l) {
+ if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
+ continue;
+
+ Attribute *attr = mesh->attributes.add(
+ ustring(l->name().c_str()), TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
+
+ BL::MeshVertexIntPropertyLayer::data_iterator d;
+ float *data = attr->data_float();
+ size_t i = 0;
+
+ for(l->data.begin(d); d != l->data.end(); ++d, ++i) {
+ *data = (float)d->value();
+ data += 1;
+ }
+ }
+ }
+}
+
/* Create Mesh */
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
@@ -528,6 +598,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
*/
attr_create_vertex_color(scene, mesh, b_mesh, nverts);
attr_create_uv_map(scene, mesh, b_mesh, nverts);
+ attr_create_vertex_properties(scene, mesh, b_mesh);
/* for volume objects, create a matrix to transform from object space to
* mesh texture space. this does not work with deformations but that can
@@ -587,8 +658,10 @@ static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerR
/* Sync */
-Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
+Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide_tris, BL::DupliObject b_dupli_ob)
{
+ BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
+
/* When viewport display is not needed during render we can force some
* caches to be releases from blender side in order to reduce peak memory
* footprint during synchronization process.
@@ -599,7 +672,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
/* test if we can instance or if the object is modified */
BL::ID b_ob_data = b_ob.data();
- BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
BL::Material material_override = render_layer.material_override;
/* find shader indices */
@@ -630,7 +702,24 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
}
Mesh *mesh;
- if(!mesh_map.sync(&mesh, key)) {
+ bool need_update;
+ BL::CacheLibrary b_cachelib = b_parent.cache_library();
+ bool use_dupli_override = b_dupli_ob && b_cachelib &&
+ (b_cachelib.source_mode() == BL::CacheLibrary::source_mode_CACHE ||
+ b_cachelib.display_mode() == BL::CacheLibrary::display_mode_RESULT);
+ if (use_dupli_override) {
+ /* if a dupli override (cached data) is used, identify the mesh by object and parent together,
+ * so that individual per-dupli overrides are possible.
+ */
+ MeshKey key = MeshKey(b_parent, b_ob);
+ need_update = mesh_map.sync(&mesh, b_ob, b_parent, key);
+ }
+ else {
+ BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
+ need_update = mesh_map.sync(&mesh, key);
+ }
+
+ if(!need_update) {
/* if transform was applied to mesh, need full update */
if(object_updated && mesh->transform_applied);
/* test if shaders changed, these can be object level so mesh
@@ -681,7 +770,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
b_ob.update_from_editmode();
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
- BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
+ BL::Mesh b_mesh = (use_dupli_override)?
+ dupli_to_mesh(b_data, b_scene, b_parent, b_dupli_ob, !preview, need_undeformed):
+ object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
if(b_mesh) {
if(render_layer.use_surfaces && !hide_tris) {
@@ -694,10 +785,10 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
}
if(render_layer.use_hair)
- sync_curves(mesh, b_mesh, b_ob, false);
+ sync_curves(mesh, b_mesh, b_parent, false, 0, b_dupli_ob);
if(can_free_caches) {
- b_ob.cache_release();
+ b_ob.cache_release(false);
}
/* free derived mesh */
@@ -740,8 +831,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
return mesh;
}
-void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time)
+void BlenderSync::sync_mesh_motion(BL::Object b_parent, Object *object, float motion_time, BL::DupliObject b_dupli_ob)
{
+ BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
/* ensure we only sync instanced meshes once */
Mesh *mesh = object->mesh;
@@ -800,7 +892,9 @@ void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion
if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
/* get derived mesh */
- b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
+ b_mesh = (b_dupli_ob && b_parent)?
+ dupli_to_mesh(b_data, b_scene, b_parent, b_dupli_ob, !preview, false):
+ object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
}
if(!b_mesh) {
@@ -890,7 +984,7 @@ void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion
/* hair motion */
if(numkeys)
- sync_curves(mesh, b_mesh, b_ob, true, time_index);
+ sync_curves(mesh, b_mesh, b_parent, true, time_index, b_dupli_ob);
/* free derived mesh */
b_data.meshes.remove(b_mesh);
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 1e17d306fd0..6afcc2231aa 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -234,8 +234,53 @@ void BlenderSync::sync_background_light(bool use_portal)
/* Object */
-Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
- Transform& tfm, uint layer_flag, float motion_time, bool hide_tris, bool *use_portal)
+static bool object_boundbox_clip(Scene *scene,
+ BL::Object b_ob,
+ Transform& tfm,
+ float margin)
+{
+ Camera *cam = scene->camera;
+ Transform& worldtondc = cam->worldtondc;
+ BL::Array<float, 24> boundbox = b_ob.bound_box();
+ float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
+ bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+ bool all_behind = true;
+ for(int i = 0; i < 8; ++i) {
+ float3 p = make_float3(boundbox[3 * i + 0],
+ boundbox[3 * i + 1],
+ boundbox[3 * i + 2]);
+ p = transform_point(&tfm, p);
+ p = transform_point(&worldtondc, p);
+ if(p.z >= -margin) {
+ all_behind = false;
+ }
+ p /= p.z;
+ bb_min = min(bb_min, p);
+ bb_max = max(bb_max, p);
+ }
+ if(!all_behind) {
+ if(bb_min.x >= 1.0f + margin ||
+ bb_min.y >= 1.0f + margin ||
+ bb_max.x <= -margin ||
+ bb_max.y <= -margin)
+ {
+ return true;
+ }
+ return false;
+ }
+ return true;
+}
+
+Object *BlenderSync::sync_object(BL::Object b_parent,
+ int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+ BL::DupliObject b_dupli_ob,
+ Transform& tfm,
+ uint layer_flag,
+ float motion_time,
+ bool hide_tris,
+ bool use_camera_cull,
+ float camera_cull_margin,
+ bool *use_portal)
{
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
bool motion = motion_time != 0.0f;
@@ -253,6 +298,11 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
if(!object_is_mesh(b_ob))
return NULL;
+ /* Perform camera space culling. */
+ if(use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin)) {
+ return NULL;
+ }
+
/* key to lookup object */
ObjectKey key(b_parent, persistent_id, b_ob);
Object *object;
@@ -279,7 +329,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
/* mesh deformation */
if(object->mesh)
- sync_mesh_motion(b_ob, object, motion_time);
+ sync_mesh_motion(b_parent, object, motion_time, b_dupli_ob);
}
return object;
@@ -294,7 +344,10 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
/* mesh sync */
- object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
+ if (b_dupli_ob)
+ object->mesh = sync_mesh(b_parent, object_updated, hide_tris, b_dupli_ob);
+ else
+ object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
/* special case not tracked by object update flags */
@@ -480,6 +533,15 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
mesh_motion_synced.clear();
}
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ bool allow_camera_cull = scene->camera->type != CAMERA_PANORAMA &&
+ !b_scene.render().use_multiview() &&
+ get_boolean(cscene, "use_camera_cull");
+ float camera_cull_margin = 0.0f;
+ if(allow_camera_cull) {
+ camera_cull_margin = get_float(cscene, "camera_cull_margin");
+ }
+
/* object loop */
BL::Scene::object_bases_iterator b_base;
BL::Scene b_sce = b_scene;
@@ -502,6 +564,12 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
if(!hide) {
progress.set_sync_status("Synchronizing object", b_ob.name());
+ PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+ bool use_camera_cull = allow_camera_cull && get_boolean(cobject, "use_camera_cull");
+ if(use_camera_cull) {
+ /* Need to have proper projection matrix. */
+ scene->camera->update();
+ }
if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) {
/* dupli objects */
b_ob.dupli_list_create(b_scene, dupli_settings);
@@ -521,7 +589,16 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
/* sync object and mesh or light data */
- Object *object = sync_object(b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion_time, hide_tris, &use_portal);
+ Object *object = sync_object(b_ob,
+ persistent_id.data,
+ *b_dup,
+ tfm,
+ ob_layer,
+ motion_time,
+ hide_tris,
+ use_camera_cull,
+ camera_cull_margin,
+ &use_portal);
/* sync possible particle data, note particle_id
* starts counting at 1, first is dummy particle */
@@ -541,7 +618,16 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
if(!object_render_hide(b_ob, true, true, hide_tris)) {
/* object itself */
Transform tfm = get_transform(b_ob.matrix_world());
- sync_object(b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion_time, hide_tris, &use_portal);
+ sync_object(b_ob,
+ NULL,
+ PointerRNA_NULL,
+ tfm,
+ ob_layer,
+ motion_time,
+ hide_tris,
+ use_camera_cull,
+ camera_cull_margin,
+ &use_portal);
}
}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index cdc44748923..9a1db703836 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -101,7 +101,8 @@ void BlenderSession::create_session()
start_resize_time = 0.0;
/* create scene */
- scene = new Scene(scene_params, session_params.device);
+ bool free_data_after_update = background && !scene_params.persistent_data;
+ scene = new Scene(scene_params, session_params.device, free_data_after_update);
/* setup callbacks for builtin image support */
scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7);
@@ -413,6 +414,7 @@ void BlenderSession::render()
/* set callback to write out render results */
session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
session->update_render_tile_cb = function_bind(&BlenderSession::update_render_tile, this, _1);
+ session->clear_database_cb = function_bind(&BlenderSession::clear_blender_database, this);
/* get buffer parameters */
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
@@ -511,6 +513,7 @@ void BlenderSession::render()
/* clear callback */
session->write_render_tile_cb = function_null;
session->update_render_tile_cb = function_null;
+ session->clear_database_cb = function_null;
/* free all memory used (host and device), so we wouldn't leave render
* engine with extra memory allocated
@@ -1012,6 +1015,18 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti
is_float = true;
}
+ else {
+ /* TODO(sergey): Check we're indeed in shader node tree. */
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
+ BL::Node b_node(ptr);
+ if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+ BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+ channels = 4;
+ width = height = depth = b_point_density_node.resolution();
+ is_float = true;
+ }
+ }
}
bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels)
@@ -1154,9 +1169,41 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
}
+ else {
+ /* TODO(sergey): Check we're indeed in shader node tree. */
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
+ BL::Node b_node(ptr);
+ if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+ BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+ int length;
+ b_point_density_node.calc_point_density(b_scene, &length, &pixels);
+ }
+ }
return false;
}
+void BlenderSession::clear_blender_database()
+{
+ const bool is_interface_locked = b_engine.render() &&
+ b_engine.render().use_lock_interface();
+ const bool can_free_database = BlenderSession::headless || is_interface_locked;
+ if(!can_free_database) {
+ /* Database might be used by the interface, can not free it at all. */
+ return;
+ }
+ for(BL::Scene b_sce = b_scene; b_sce; b_sce = b_sce.background_set()) {
+ BL::Scene::object_bases_iterator b_base;
+ for(b_sce.object_bases.begin(b_base);
+ b_base != b_sce.object_bases.end();
+ ++b_base)
+ {
+ BL::Object b_ob = b_base->object();
+ b_ob.cache_release(true);
+ }
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index 708776dc8ca..5498548eb74 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -109,6 +109,8 @@ protected:
void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels);
bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels);
bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels);
+
+ void clear_blender_database();
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 2b0e8acae38..140560bed0f 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -22,6 +22,7 @@
#include "scene.h"
#include "shader.h"
+#include "blender_texture.h"
#include "blender_sync.h"
#include "blender_util.h"
@@ -736,6 +737,62 @@ static ShaderNode *add_node(Scene *scene,
uvm->from_dupli = b_uvmap_node.from_dupli();
node = uvm;
}
+ else if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+ BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+ PointDensityTextureNode *point_density = new PointDensityTextureNode();
+ point_density->filename = b_point_density_node.name();
+ point_density->space =
+ PointDensityTextureNode::space_enum[(int)b_point_density_node.space()];
+ point_density->interpolation =
+ (InterpolationType)b_point_density_node.interpolation();
+ point_density->builtin_data = b_point_density_node.ptr.data;
+
+ /* Transformation form world space to texture space. */
+ BL::Object b_ob(b_point_density_node.object());
+ if(b_ob) {
+ float3 loc, size;
+ point_density_texture_space(b_point_density_node, loc, size);
+ point_density->tfm =
+ transform_translate(-loc) * transform_scale(size) *
+ transform_inverse(get_transform(b_ob.matrix_world()));
+ }
+
+ /* TODO(sergey): Use more proper update flag. */
+ if(true) {
+ scene->image_manager->tag_reload_image(point_density->filename,
+ point_density->builtin_data,
+ point_density->interpolation);
+ }
+ node = point_density;
+ }
+ else if(b_node.is_a(&RNA_ShaderNodeOpenVDB)) {
+ BL::ShaderNodeOpenVDB b_vdb_node(b_node);
+ OpenVDBNode *vdb_node = new OpenVDBNode();
+ vdb_node->filename = b_vdb_node.filename();
+ vdb_node->sampling = b_vdb_node.sampling();
+
+ /* TODO(kevin) */
+ if(b_vdb_node.source() == 1) {
+ string filename = b_vdb_node.filename();
+ string basename = filename.substr(0, filename.size() - 8);
+ stringstream ss;
+ ss << b_scene.frame_current();
+ string frame = ss.str();
+ frame.insert(frame.begin(), 4 - frame.size(), '0');
+
+ vdb_node->filename = ustring::format("%s%s.vdb", basename, frame);
+ }
+
+ BL::Node::outputs_iterator b_output;
+
+ for(b_vdb_node.outputs.begin(b_output); b_output != b_vdb_node.outputs.end(); ++b_output) {
+ vdb_node->output_names.push_back(ustring(b_output->name()));
+ vdb_node->add_output(vdb_node->output_names.back().c_str(),
+ convert_socket_type(*b_output));
+ }
+
+ node = vdb_node;
+ }
if(node)
graph->add(node);
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index c5fb7925306..87e2932d6b1 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -435,6 +435,8 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background, bo
params.use_qbvh = false;
}
+ params.use_bvh_triangle_storage = RNA_boolean_get(&cscene, "debug_use_triangle_storage");
+
return params;
}
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 89d93e19e9f..ef279a4fe63 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -83,13 +83,22 @@ private:
void sync_curve_settings();
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
- Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris);
- void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index = 0);
- Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
- Transform& tfm, uint layer_flag, float motion_time, bool hide_tris, bool *use_portal);
+ Mesh *sync_mesh(BL::Object b_parent, bool object_updated, bool hide_tris, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
+ void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent, bool motion, int time_index = 0, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
+ Object *sync_object(BL::Object b_parent,
+ int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+ BL::DupliObject b_dupli_ob,
+ Transform& tfm,
+ uint layer_flag,
+ float motion_time,
+ bool hide_tris,
+ bool use_camera_cull,
+ float camera_cull_margin,
+ bool *use_portal);
void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm, bool *use_portal);
void sync_background_light(bool use_portal);
- void sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time);
+ void sync_mesh_motion(BL::Object b_parent, Object *object, float motion_time, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
+
void sync_camera_motion(BL::Object b_ob, float motion_time);
/* particles */
@@ -111,7 +120,7 @@ private:
id_map<void*, Shader> shader_map;
id_map<ObjectKey, Object> object_map;
- id_map<void*, Mesh> mesh_map;
+ id_map<MeshKey, Mesh> mesh_map;
id_map<ObjectKey, Light> light_map;
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
set<Mesh*> mesh_synced;
diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp
new file mode 100644
index 00000000000..cb4dd1792d0
--- /dev/null
+++ b/intern/cycles/blender/blender_texture.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011-2015 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_texture.h"
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+/* Point density helpers. */
+
+static void density_texture_space_invert(float3& loc,
+ float3& size)
+{
+ if(size.x != 0.0f) size.x = 0.5f/size.x;
+ if(size.y != 0.0f) size.y = 0.5f/size.y;
+ if(size.z != 0.0f) size.z = 0.5f/size.z;
+
+ loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
+}
+
+static void density_object_texture_space(BL::Object b_ob,
+ float radius,
+ float3& loc,
+ float3& size)
+{
+ if(b_ob.type() == BL::Object::type_MESH) {
+ BL::Mesh b_mesh(b_ob.data());
+ loc = get_float3(b_mesh.texspace_location());
+ size = get_float3(b_mesh.texspace_size());
+ }
+ else {
+ /* TODO(sergey): Not supported currently. */
+ }
+ /* Adjust texture space to include density points on the boundaries. */
+ size = size + make_float3(radius, radius, radius);
+ density_texture_space_invert(loc, size);
+}
+
+static void density_particle_system_texture_space(
+ BL::Object b_ob,
+ BL::ParticleSystem b_particle_system,
+ float radius,
+ float3& loc,
+ float3& size)
+{
+ if(b_particle_system.settings().type() == BL::ParticleSettings::type_HAIR) {
+ /* TODO(sergey): Not supported currently. */
+ return;
+ }
+ Transform tfm = get_transform(b_ob.matrix_world());
+ Transform itfm = transform_inverse(tfm);
+ float3 min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
+ max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+ float3 particle_size = make_float3(radius, radius, radius);
+ for(int i = 0; i < b_particle_system.particles.length(); ++i) {
+ BL::Particle particle = b_particle_system.particles[i];
+ float3 location = get_float3(particle.location());
+ location = transform_point(&itfm, location);
+ min = ccl::min(min, location - particle_size);
+ max = ccl::max(max, location + particle_size);
+ }
+ /* Calculate texture space from the particle bounds. */
+ loc = (min + max) * 0.5f;
+ size = (max - min) * 0.5f;
+ density_texture_space_invert(loc, size);
+}
+
+} /* namespace */
+
+void point_density_texture_space(BL::ShaderNodeTexPointDensity b_point_density_node,
+ float3& loc,
+ float3& size)
+{
+ /* Fallback values. */
+ loc = make_float3(0.0f, 0.0f, 0.0f);
+ size = make_float3(0.0f, 0.0f, 0.0f);
+ BL::Object b_ob(b_point_density_node.object());
+ if(!b_ob) {
+ return;
+ }
+ if(b_point_density_node.point_source() ==
+ BL::ShaderNodeTexPointDensity::point_source_PARTICLE_SYSTEM)
+ {
+ BL::ParticleSystem b_particle_system(
+ b_point_density_node.particle_system());
+ if(b_particle_system) {
+ density_particle_system_texture_space(b_ob,
+ b_particle_system,
+ b_point_density_node.radius(),
+ loc,
+ size);
+ }
+ }
+ else {
+ density_object_texture_space(b_ob,
+ b_point_density_node.radius(),
+ loc,
+ size);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h
new file mode 100644
index 00000000000..74fbca02a9e
--- /dev/null
+++ b/intern/cycles/blender/blender_texture.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2011-2015 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 __BLENDER_TEXTURE_H__
+#define __BLENDER_TEXTURE_H__
+
+#include <stdlib.h>
+#include "blender_sync.h"
+
+CCL_NAMESPACE_BEGIN
+
+void point_density_texture_space(BL::ShaderNodeTexPointDensity b_point_density_node,
+ float3& loc,
+ float3& size);
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_TEXTURE_H__ */
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 165242d0dff..b7a5e0f3c3a 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -52,6 +52,18 @@ static inline BL::Mesh object_to_mesh(BL::BlendData data, BL::Object object, BL:
return me;
}
+static inline BL::Mesh dupli_to_mesh(BL::BlendData data, BL::Scene scene, BL::Object parent, BL::DupliObject dob, bool render, bool calc_undeformed)
+{
+ BL::Mesh me = data.meshes.new_from_dupli(scene, parent, dob, (render)? 2: 1, false, calc_undeformed);
+ if ((bool)me) {
+ if (me.use_auto_smooth()) {
+ me.calc_normals_split();
+ }
+ me.calc_tessface(true);
+ }
+ return me;
+}
+
static inline void colorramp_to_array(BL::ColorRamp ramp, float4 *data, int size)
{
for(int i = 0; i < size; i++) {
@@ -586,6 +598,36 @@ struct ObjectKey {
}
};
+/* Mesh Key */
+
+struct MeshKey {
+ void *parent;
+ void *mesh;
+
+ MeshKey(void *mesh_)
+ : parent(NULL), mesh(mesh_)
+ {
+ }
+
+ MeshKey(void *parent_, void *mesh_)
+ : parent(parent_), mesh(mesh_)
+ {
+ }
+
+ bool operator<(const MeshKey& k) const
+ {
+ if(mesh < k.mesh) {
+ return true;
+ }
+ else if(mesh == k.mesh) {
+ return parent < k.parent;
+ return true;
+ }
+
+ return false;
+ }
+};
+
/* Particle System Key */
struct ParticleSystemKey {
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 350ca16f6e2..9b808203694 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -278,28 +278,34 @@ void BVH::pack_triangle(int idx, float4 woop[3])
void BVH::pack_primitives()
{
- int nsize = TRI_NODE_SIZE;
+ const int nsize = TRI_NODE_SIZE;
+ const bool use_triangle_storage = params.use_triangle_storage;
size_t tidx_size = pack.prim_index.size();
pack.tri_woop.clear();
- pack.tri_woop.resize(tidx_size * nsize);
+ if (use_triangle_storage) {
+ pack.tri_woop.resize(tidx_size * nsize);
+ }
+ else {
+ pack.tri_woop.resize(0);
+ }
pack.prim_visibility.clear();
pack.prim_visibility.resize(tidx_size);
for(unsigned int i = 0; i < tidx_size; i++) {
if(pack.prim_index[i] != -1) {
- float4 woop[3];
-
- if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
- pack_triangle(i, woop);
- }
- else {
- /* Avoid use of uninitialized memory. */
- memset(&woop, 0, sizeof(woop));
+ if(use_triangle_storage) {
+ float4 woop[3];
+ if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
+ pack_triangle(i, woop);
+ }
+ else {
+ /* Avoid use of uninitialized memory. */
+ memset(&woop, 0, sizeof(woop));
+ }
+ memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
}
- memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
-
int tob = pack.prim_object[i];
Object *ob = objects[tob];
pack.prim_visibility[i] = ob->visibility;
@@ -308,7 +314,9 @@ void BVH::pack_primitives()
pack.prim_visibility[i] |= PATH_RAY_CURVE;
}
else {
- memset(&pack.tri_woop[i * nsize], 0, sizeof(float4)*3);
+ if(use_triangle_storage) {
+ memset(&pack.tri_woop[i * nsize], 0, sizeof(float4)*3);
+ }
pack.prim_visibility[i] = 0;
}
}
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index af8d8eeb3ee..892fd906e77 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -49,6 +49,9 @@ public:
/* QBVH */
bool use_qbvh;
+ /* Use pre-aligned tringle storage for faster lookup. */
+ bool use_triangle_storage;
+
/* fixed parameters */
enum {
MAX_DEPTH = 64,
@@ -73,6 +76,7 @@ public:
top_level = false;
use_cache = false;
use_qbvh = false;
+ use_triangle_storage = true;
}
/* SAH costs */
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index d7c59f42a5e..13196e2ba6b 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -30,7 +30,7 @@ if(NOT CYCLES_STANDALONE_REPOSITORY)
set(GLEW_INCLUDE_DIR "${GLEW_INCLUDE_PATH}")
endif()
-if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
+if(WITH_CYCLES_STANDALONE)
set(CYCLES_APP_GLEW_LIBRARY ${BLENDER_GLEW_LIBRARIES})
endif()
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index d0279b27046..872d5ab4af5 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -115,6 +115,7 @@ set(SRC_SVM_HEADERS
svm/svm_noise.h
svm/svm_noisetex.h
svm/svm_normal.h
+ svm/svm_openvdb.h
svm/svm_ramp.h
svm/svm_sepcomb_hsv.h
svm/svm_sepcomb_vector.h
@@ -125,6 +126,7 @@ set(SRC_SVM_HEADERS
svm/svm_value.h
svm/svm_vector_transform.h
svm/svm_voronoi.h
+ svm/svm_voxel.h
svm/svm_wave.h
)
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index 3ef918dc842..ee5d4df2889 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -119,9 +119,19 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- const float4 tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ float4 tri_a, tri_b, tri_c;
+ if (kernel_data.bvh.use_tri_storage) {
+ tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
+ tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
+ tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ }
+ else {
+ const int prim = kernel_tex_fetch(__prim_index, triAddr);
+ const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
+ tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
+ tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
+ }
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
@@ -212,9 +222,19 @@ ccl_device_inline void triangle_intersect_subsurface(
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- const float4 tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ float4 tri_a, tri_b, tri_c;
+ if (kernel_data.bvh.use_tri_storage) {
+ tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
+ tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
+ tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ }
+ else {
+ const int prim = kernel_tex_fetch(__prim_index, triAddr);
+ const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
+ tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
+ tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
+ }
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
@@ -327,9 +347,19 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
P = P + D*t;
- const float4 tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
+ float4 tri_a, tri_b, tri_c;
+ if (kernel_data.bvh.use_tri_storage) {
+ tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
+ tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1);
+ tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
+ }
+ else {
+ const int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
+ tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
+ tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
+ }
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
@@ -384,9 +414,19 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
P = P + D*t;
- const float4 tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
+ float4 tri_a, tri_b, tri_c;
+ if (kernel_data.bvh.use_tri_storage) {
+ tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
+ tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1);
+ tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
+ }
+ else {
+ const int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
+ tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
+ tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
+ }
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h
index c72afa2a3a4..24430dd223b 100644
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ b/intern/cycles/kernel/geom/geom_volume.h
@@ -53,17 +53,21 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd,
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
#else
float4 r;
+ int slot = id >> 1;
if(sd->flag & SD_VOLUME_CUBIC)
- r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
+ r = kernel_tex_image_interp_3d_ex(slot, P.x, P.y, P.z, INTERPOLATION_CUBIC);
else
- r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
+ r = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
#endif
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
/* todo: support float textures to lower memory usage for single floats */
- return average(float4_to_float3(r));
+ if(id & 1)
+ return r.w;
+ else
+ return average(float4_to_float3(r));
}
ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float3 *dx, float3 *dy)
@@ -73,16 +77,20 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
#else
float4 r;
+ int slot = id >> 1;
if(sd->flag & SD_VOLUME_CUBIC)
- r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
+ r = kernel_tex_image_interp_3d_ex(slot, P.x, P.y, P.z, INTERPOLATION_CUBIC);
else
- r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
+ r = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
#endif
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
- return float4_to_float3(r);
+ if(id & 1)
+ return make_float3(r.w, r.w, r.w);
+ else
+ return float4_to_float3(r);
}
#endif
diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h
index 0bf1ed36d1e..8a1ad7052f8 100644
--- a/intern/cycles/kernel/kernel_compat_cpu.h
+++ b/intern/cycles/kernel/kernel_compat_cpu.h
@@ -40,6 +40,8 @@
#include "util_simd.h"
#include "util_half.h"
#include "util_types.h"
+#include "util_openvdb.h"
+#include "util_vector.h"
#define ccl_addr_space
@@ -416,6 +418,8 @@ typedef texture_image<uchar4> texture_image_uchar4;
#define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y))
#define kernel_tex_image_interp_3d(tex, x, y, z) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp_3d(x, y, z) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp_3d(x, y, z))
#define kernel_tex_image_interp_3d_ex(tex, x, y, z, interpolation) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp_3d_ex(x, y, z, interpolation) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp_3d_ex(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_data (kg->__data)
diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h
index 17fa18909c4..157720d6679 100644
--- a/intern/cycles/kernel/kernel_globals.h
+++ b/intern/cycles/kernel/kernel_globals.h
@@ -33,11 +33,15 @@ struct OSLShadingSystem;
#define MAX_BYTE_IMAGES 1024
#define MAX_FLOAT_IMAGES 1024
+#define MAX_VOLUME 1024
typedef struct KernelGlobals {
texture_image_uchar4 texture_byte_images[MAX_BYTE_IMAGES];
texture_image_float4 texture_float_images[MAX_FLOAT_IMAGES];
+ 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"
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 2a70bfcb8f0..c071be5419a 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -67,6 +67,9 @@ CCL_NAMESPACE_BEGIN
#ifdef WITH_OSL
#define __OSL__
#endif
+#ifdef WITH_OPENVDB
+#define __OPENVDB__
+#endif
#define __SUBSURFACE__
#define __CMJ__
#define __VOLUME__
@@ -952,7 +955,8 @@ typedef struct KernelBVH {
int have_curves;
int have_instancing;
int use_qbvh;
- int pad1, pad2;
+ int use_tri_storage;
+ int pad1;
} KernelBVH;
typedef enum CurveFlag {
@@ -976,7 +980,8 @@ typedef struct KernelCurves {
typedef struct KernelTables {
int beckmann_offset;
- int pad1, pad2, pad3;
+ int num_volumes;
+ int density_index, pad2;
} KernelTables;
typedef struct KernelData {
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index e06568457c6..cc958a09a46 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -21,7 +21,8 @@ CCL_NAMESPACE_BEGIN
typedef enum VolumeIntegrateResult {
VOLUME_PATH_SCATTERED = 0,
VOLUME_PATH_ATTENUATED = 1,
- VOLUME_PATH_MISSED = 2
+ VOLUME_PATH_MISSED = 2,
+ VOLUME_PATH_CONTINUE = 3,
} VolumeIntegrateResult;
/* Volume shader properties
@@ -161,6 +162,38 @@ ccl_device void kernel_volume_shadow_homogeneous(KernelGlobals *kg, PathState *s
*throughput *= volume_color_transmittance(sigma_t, ray->t);
}
+ccl_device_inline bool kernel_volume_integrate_shadow_ray(
+ KernelGlobals *kg, PathState *state, Ray *ray, ShaderData *sd,
+ float3 *tp, float t, float new_t, float random_jitter_offset,
+ float3 *sum, float tp_eps, int i)
+{
+ float dt = new_t - t;
+
+ /* use random position inside this segment to sample shader */
+ if(new_t == ray->t)
+ random_jitter_offset = lcg_step_float(&state->rng_congruential) * dt;
+
+ float3 new_P = ray->P + ray->D * (t + random_jitter_offset);
+ float3 sigma_t;
+
+ /* compute attenuation over segment */
+ if(volume_shader_extinction_sample(kg, sd, state, new_P, &sigma_t)) {
+ /* Compute expf() only for every Nth step, to save some calculations
+ * because exp(a)*exp(b) = exp(a+b), also do a quick tp_eps check then. */
+
+ *sum += (-sigma_t * (new_t - t));
+ if((i & 0x07) == 0) { /* ToDo: Other interval? */
+ *tp = *tp * make_float3(expf(sum->x), expf(sum->y), expf(sum->z));
+
+ /* stop if nearly all light is blocked */
+ if(tp->x < tp_eps && tp->y < tp_eps && tp->z < tp_eps)
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* heterogeneous volume: integrate stepping through the volume until we
* reach the end, get absorbed entirely, or run out of iterations */
ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, PathState *state, Ray *ray, ShaderData *sd, float3 *throughput)
@@ -178,42 +211,66 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, PathState
float3 sum = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i < max_steps; i++) {
- /* advance to new position */
- float new_t = min(ray->t, (i+1) * step);
- float dt = new_t - t;
-
- /* use random position inside this segment to sample shader */
- if(new_t == ray->t)
- random_jitter_offset = lcg_step_float(&state->rng_congruential) * dt;
-
- float3 new_P = ray->P + ray->D * (t + random_jitter_offset);
- float3 sigma_t;
-
- /* compute attenuation over segment */
- if(volume_shader_extinction_sample(kg, sd, state, new_P, &sigma_t)) {
- /* Compute expf() only for every Nth step, to save some calculations
- * because exp(a)*exp(b) = exp(a+b), also do a quick tp_eps check then. */
+#ifdef __OPENVDB__
+ int vdb_index = kernel_data.tables.density_index;
+ bool has_vdb_volume = kernel_data.tables.num_volumes > 0;
+ float t1 = 0.0f;
+
+ if(has_vdb_volume && vdb_index >= 0 && kg->float_volumes[vdb_index]->has_uniform_voxels()) {
+ /* 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;
+ }
- sum += (-sigma_t * (new_t - t));
- if((i & 0x07) == 0) { /* ToDo: Other interval? */
- tp = *throughput * make_float3(expf(sum.x), expf(sum.y), expf(sum.z));
+ /* 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)) {
+ int i = 0;
+
+ /* Perform small steps through the current leaf or tile. */
+ for(float new_t = step * ceilf(t / step); new_t <= t1; new_t += step) {
+ bool ok = kernel_volume_integrate_shadow_ray(
+ kg, state, ray, sd, &tp, t, new_t, random_jitter_offset,
+ &sum, tp_eps, i);
+
+ if (ok) {
+ *throughput = tp;
+ return;
+ }
- /* stop if nearly all light is blocked */
- if(tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps)
- break;
+ /* stop if at the end of the volume */
+ t = new_t;
+ i++;
}
}
-
- /* stop if at the end of the volume */
- t = new_t;
- if(t == ray->t) {
- /* Update throughput in case we haven't done it above */
- tp = *throughput * make_float3(expf(sum.x), expf(sum.y), expf(sum.z));
- break;
+ }
+ else
+#endif
+ {
+ for(int i = 0; i < max_steps; i++) {
+ /* advance to new position */
+ float new_t = min(ray->t, (i+1) * step);
+
+ bool ok = kernel_volume_integrate_shadow_ray(
+ kg, state, ray, sd, &tp, t, new_t, random_jitter_offset,
+ &sum, tp_eps, i);
+
+ /* stop if at the end of the volume */
+ t = new_t;
+ if(ok || t == ray->t) {
+ break;
+ }
}
}
+ /* Update throughput in case we haven't done it above */
+ tp = *throughput * make_float3(expf(sum.x), expf(sum.y), expf(sum.z));
+
*throughput = tp;
}
@@ -420,6 +477,112 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(KernelGloba
return VOLUME_PATH_ATTENUATED;
}
+ccl_device_inline VolumeIntegrateResult kernel_volume_integrate_ray(
+ KernelGlobals *kg, PathState *state, Ray *ray, ShaderData *sd,
+ PathRadiance *L, float3 *throughput, float t, float new_t,
+ float random_jitter_offset, bool has_scatter, float3 *accum_transmittance,
+ int channel, const float tp_eps, float *xi)
+{
+ float dt = new_t - t;
+ float3 tp = *throughput;
+
+ /* use random position inside this segment to sample shader */
+ if(new_t == ray->t)
+ random_jitter_offset = lcg_step_float(&state->rng_congruential) * dt;
+
+ float3 new_P = ray->P + ray->D * (t + random_jitter_offset);
+ VolumeShaderCoefficients coeff;
+
+ /* compute segment */
+ if(volume_shader_sample(kg, sd, state, new_P, &coeff)) {
+ int closure_flag = sd->flag;
+ float3 new_tp;
+ float3 transmittance;
+ bool scatter = false;
+
+ /* distance sampling */
+#ifdef __VOLUME_SCATTER__
+ if((closure_flag & SD_SCATTER) || (has_scatter && (closure_flag & SD_ABSORPTION))) {
+ has_scatter = true;
+
+ float3 sigma_t = coeff.sigma_a + coeff.sigma_s;
+ float3 sigma_s = coeff.sigma_s;
+
+ /* compute transmittance over full step */
+ transmittance = volume_color_transmittance(sigma_t, dt);
+
+ /* decide if we will scatter or continue */
+ float sample_transmittance = kernel_volume_channel_get(transmittance, channel);
+
+ if(1.0f - *xi >= sample_transmittance) {
+ /* compute sampling distance */
+ float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel);
+ float new_dt = -logf(1.0f - *xi)/sample_sigma_t;
+ new_t = t + new_dt;
+
+ /* transmittance and pdf */
+ float3 new_transmittance = volume_color_transmittance(sigma_t, new_dt);
+ float3 pdf = sigma_t * new_transmittance;
+
+ /* throughput */
+ new_tp = tp * sigma_s * new_transmittance / average(pdf);
+ scatter = true;
+ }
+ else {
+ /* throughput */
+ float pdf = average(transmittance);
+ new_tp = tp * transmittance / pdf;
+
+ /* remap xi so we can reuse it and keep thing stratified */
+ *xi = 1.0f - (1.0f - *xi)/sample_transmittance;
+ }
+ }
+ else
+#endif
+ if(closure_flag & SD_ABSORPTION) {
+ /* absorption only, no sampling needed */
+ float3 sigma_a = coeff.sigma_a;
+
+ transmittance = volume_color_transmittance(sigma_a, dt);
+ new_tp = tp * transmittance;
+ }
+
+ /* integrate emission attenuated by absorption */
+ if(L && (closure_flag & SD_EMISSION)) {
+ float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, dt);
+ path_radiance_accum_emission(L, tp, emission, state->bounce);
+ }
+
+ /* modify throughput */
+ if(closure_flag & (SD_ABSORPTION|SD_SCATTER)) {
+ tp = new_tp;
+
+ /* stop if nearly all light blocked */
+ if(tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps) {
+ tp = make_float3(0.0f, 0.0f, 0.0f);
+ *throughput = tp;
+ return VOLUME_PATH_ATTENUATED;
+ }
+ }
+
+ /* prepare to scatter to new direction */
+ if(scatter) {
+ /* adjust throughput and move to new location */
+ sd->P = ray->P + new_t*ray->D;
+ *throughput = tp;
+
+ return VOLUME_PATH_SCATTERED;
+ }
+ else {
+ /* accumulate transmittance */
+ *accum_transmittance *= transmittance;
+ }
+ }
+
+ *throughput = tp;
+ return VOLUME_PATH_CONTINUE;
+}
+
/* heterogeneous volume distance sampling: integrate stepping through the
* volume until we reach the end, get absorbed entirely, or run out of
* iterations. this does probalistically scatter or get transmitted through
@@ -427,7 +590,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(KernelGloba
ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
PathState *state, Ray *ray, ShaderData *sd, PathRadiance *L, float3 *throughput, RNG *rng)
{
- float3 tp = *throughput;
+ VolumeIntegrateResult result = VOLUME_PATH_MISSED;
const float tp_eps = 1e-6f; /* todo: this is likely not the right value */
/* prepare for stepping */
@@ -436,7 +599,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
float random_jitter_offset = lcg_step_float(&state->rng_congruential) * step_size;
/* compute coefficients at the start */
- float t = 0.0f;
+ float t = 0.0f, t1 = 0.0f;
float3 accum_transmittance = make_float3(1.0f, 1.0f, 1.0f);
/* pick random color channel, we use the Veach one-sample
@@ -446,113 +609,65 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
int channel = (int)(rphase*3.0f);
sd->randb_closure = rphase*3.0f - channel;
bool has_scatter = false;
+ bool path_missed = true;
+
+#ifdef __OPENVDB__
+ int vdb_index = kernel_data.tables.density_index;
+ bool has_vdb_volume = kernel_data.tables.num_volumes > 0;
+
+ if(has_vdb_volume && vdb_index >= 0 && kg->float_volumes[vdb_index]->has_uniform_voxels()) {
+ /* 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;
+ }
- for(int i = 0; i < max_steps; i++) {
- /* advance to new position */
- float new_t = min(ray->t, (i+1) * step_size);
- float dt = new_t - t;
-
- /* use random position inside this segment to sample shader */
- if(new_t == ray->t)
- random_jitter_offset = lcg_step_float(&state->rng_congruential) * dt;
-
- float3 new_P = ray->P + ray->D * (t + random_jitter_offset);
- VolumeShaderCoefficients coeff;
-
- /* compute segment */
- if(volume_shader_sample(kg, sd, state, new_P, &coeff)) {
- int closure_flag = sd->flag;
- float3 new_tp;
- float3 transmittance;
- bool scatter = false;
-
- /* distance sampling */
-#ifdef __VOLUME_SCATTER__
- if((closure_flag & SD_SCATTER) || (has_scatter && (closure_flag & SD_ABSORPTION))) {
- has_scatter = true;
-
- float3 sigma_t = coeff.sigma_a + coeff.sigma_s;
- float3 sigma_s = coeff.sigma_s;
-
- /* compute transmittance over full step */
- transmittance = volume_color_transmittance(sigma_t, dt);
-
- /* decide if we will scatter or continue */
- float sample_transmittance = kernel_volume_channel_get(transmittance, channel);
-
- if(1.0f - xi >= sample_transmittance) {
- /* compute sampling distance */
- float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel);
- float new_dt = -logf(1.0f - xi)/sample_sigma_t;
- new_t = t + new_dt;
+ /* 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)) {
+ path_missed = false;
- /* transmittance and pdf */
- float3 new_transmittance = volume_color_transmittance(sigma_t, new_dt);
- float3 pdf = sigma_t * new_transmittance;
+ /* 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) {
+ result = kernel_volume_integrate_ray(kg, state, ray, sd, L, throughput, t, new_t,
+ random_jitter_offset, has_scatter,
+ &accum_transmittance, channel, tp_eps, &xi);
- /* throughput */
- new_tp = tp * sigma_s * new_transmittance / average(pdf);
- scatter = true;
- }
- else {
- /* throughput */
- float pdf = average(transmittance);
- new_tp = tp * transmittance / pdf;
+ if(result != VOLUME_PATH_CONTINUE)
+ return result;
- /* remap xi so we can reuse it and keep thing stratified */
- xi = 1.0f - (1.0f - xi)/sample_transmittance;
- }
+ t = new_t;
}
- else
+ }
+ }
+ else
#endif
- if(closure_flag & SD_ABSORPTION) {
- /* absorption only, no sampling needed */
- float3 sigma_a = coeff.sigma_a;
-
- transmittance = volume_color_transmittance(sigma_a, dt);
- new_tp = tp * transmittance;
- }
-
- /* integrate emission attenuated by absorption */
- if(L && (closure_flag & SD_EMISSION)) {
- float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, dt);
- path_radiance_accum_emission(L, tp, emission, state->bounce);
- }
+ {
+ path_missed = false;
- /* modify throughput */
- if(closure_flag & (SD_ABSORPTION|SD_SCATTER)) {
- tp = new_tp;
+ for(int i = 0; i < max_steps; i++) {
+ /* advance to new position */
+ float new_t = min(ray->t, (i+1) * step_size);
- /* stop if nearly all light blocked */
- if(tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps) {
- tp = make_float3(0.0f, 0.0f, 0.0f);
- break;
- }
- }
+ result = kernel_volume_integrate_ray(kg, state, ray, sd, L, throughput, t, new_t,
+ random_jitter_offset, has_scatter,
+ &accum_transmittance, channel, tp_eps, &xi);
- /* prepare to scatter to new direction */
- if(scatter) {
- /* adjust throughput and move to new location */
- sd->P = ray->P + new_t*ray->D;
- *throughput = tp;
+ if(result != VOLUME_PATH_CONTINUE)
+ return result;
- return VOLUME_PATH_SCATTERED;
- }
- else {
- /* accumulate transmittance */
- accum_transmittance *= transmittance;
- }
+ /* stop if at the end of the volume */
+ t = new_t;
+ if(t == ray->t)
+ break;
}
-
- /* stop if at the end of the volume */
- t = new_t;
- if(t == ray->t)
- break;
}
- *throughput = tp;
-
- return VOLUME_PATH_ATTENUATED;
+ return (path_missed) ? VOLUME_PATH_MISSED : VOLUME_PATH_ATTENUATED;
}
/* get the volume attenuation and emission over line segment defined by
diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp
index 37a73ab2f04..500aef3fe19 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp
@@ -34,6 +34,10 @@ 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/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 15ac6519780..21604e78f7d 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -168,6 +168,7 @@ CCL_NAMESPACE_END
#include "svm_wave.h"
#include "svm_math.h"
#include "svm_mix.h"
+#include "svm_openvdb.h"
#include "svm_ramp.h"
#include "svm_sepcomb_hsv.h"
#include "svm_sepcomb_vector.h"
@@ -179,6 +180,7 @@ CCL_NAMESPACE_END
#include "svm_checker.h"
#include "svm_brick.h"
#include "svm_vector_transform.h"
+#include "svm_voxel.h"
CCL_NAMESPACE_BEGIN
@@ -390,6 +392,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
case NODE_TEX_BRICK:
svm_node_tex_brick(kg, sd, stack, node, &offset);
break;
+ case NODE_TEX_VOXEL:
+ svm_node_tex_voxel(kg, sd, stack, node, &offset);
+ break;
# endif /* __TEXTURES__ */
# ifdef __EXTRA_NODES__
case NODE_NORMAL:
@@ -447,6 +452,11 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
break;
# endif /* __EXTRA_NODES__ */
#endif /* NODES_GROUP(NODE_GROUP_LEVEL_3) */
+#ifdef __OPENVDB__
+ case NODE_OPENVDB:
+ svm_node_openvdb(kg, sd, stack, node, &offset);
+ break;
+#endif
case NODE_END:
return;
default:
diff --git a/intern/cycles/kernel/svm/svm_openvdb.h b/intern/cycles/kernel/svm/svm_openvdb.h
new file mode 100644
index 00000000000..8820dae42c4
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_openvdb.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 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.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __OPENVDB__
+
+ccl_device void svm_node_openvdb(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+{
+ uint slot = node.y;
+ uint type, out_offset, sampling, co_offset;
+ decode_node_uchar4(node.z, &type, &co_offset, &out_offset, &sampling);
+
+ float3 co = stack_load_float3(stack, co_offset);
+
+ Transform tfm;
+ tfm.x = read_node_float(kg, offset);
+ tfm.y = read_node_float(kg, offset);
+ tfm.z = read_node_float(kg, offset);
+ tfm.w = read_node_float(kg, offset);
+ co = transform_point(&tfm, co);
+
+ if(type == NODE_VDB_FLOAT) {
+ float out = kernel_tex_voxel_float(slot, co.x, co.y, co.z, sampling);
+
+ if(stack_valid(out_offset)) {
+ stack_store_float(stack, out_offset, out);
+ }
+ }
+ else if(type == NODE_VDB_FLOAT3) {
+ float3 out = kernel_tex_voxel_float3(slot, co.x, co.y, co.z, sampling);
+
+ if(stack_valid(out_offset)) {
+ stack_store_float3(stack, out_offset, out);
+ }
+ }
+}
+
+#endif
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 009e91192eb..28e55a1e0d5 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -125,7 +125,9 @@ typedef enum NodeType {
NODE_TANGENT,
NODE_NORMAL_MAP,
NODE_HAIR_INFO,
- NODE_UVMAP
+ NODE_UVMAP,
+ NODE_TEX_VOXEL,
+ NODE_OPENVDB,
} NodeType;
typedef enum NodeAttributeType {
@@ -349,6 +351,16 @@ typedef enum NodeBumpOffset {
NODE_BUMP_OFFSET_DY,
} NodeBumpOffset;
+typedef enum NodeTexVoxelSpace {
+ NODE_TEX_VOXEL_SPACE_OBJECT = 0,
+ NODE_TEX_VOXEL_SPACE_WORLD = 1,
+} NodeTexVoxelSpace;
+
+typedef enum NodeOpenVDBType {
+ NODE_VDB_FLOAT = 0,
+ NODE_VDB_FLOAT3 = 1,
+} NodeOpenVDBType;
+
typedef enum ShaderType {
SHADER_TYPE_SURFACE,
SHADER_TYPE_VOLUME,
diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h
new file mode 100644
index 00000000000..4838926503e
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_voxel.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2015 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.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint4 node,
+ int *offset)
+{
+ int id = node.y;
+ uint co_offset, density_out_offset, color_out_offset, space;
+ decode_node_uchar4(node.z, &co_offset, &density_out_offset, &color_out_offset, &space);
+ float3 co = stack_load_float3(stack, co_offset);
+ if(space == NODE_TEX_VOXEL_SPACE_OBJECT) {
+ co = volume_normalized_position(kg, sd, co);
+ }
+ else {
+ kernel_assert(space == NODE_TEX_VOXEL_SPACE_WORLD);
+ Transform tfm;
+ tfm.x = read_node_float(kg, offset);
+ tfm.y = read_node_float(kg, offset);
+ tfm.z = read_node_float(kg, offset);
+ tfm.w = read_node_float(kg, offset);
+ co = transform_point(&tfm, co);
+ }
+ if(co.x < 0.0f || co.y < 0.0f || co.z < 0.0f ||
+ co.x > 1.0f || co.y > 1.0f || co.z > 1.0f)
+ {
+ if (stack_valid(density_out_offset))
+ stack_store_float(stack, density_out_offset, 0.0f);
+ if (stack_valid(color_out_offset))
+ stack_store_float3(stack, color_out_offset, make_float3(0.0f, 0.0f, 0.0f));
+ return;
+ }
+#ifdef __KERNEL_GPU__
+ float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+#else
+ float4 r = kernel_tex_image_interp_3d(id, co.x, co.y, co.z);
+#endif
+ if (stack_valid(density_out_offset))
+ stack_store_float(stack, density_out_offset, r.w);
+ if (stack_valid(color_out_offset))
+ stack_store_float3(stack, color_out_offset, make_float3(r.x, r.y, r.z));
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 4e8a1794813..e85b7e67f6a 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -14,6 +14,12 @@ set(INC_SYS
${GLEW_INCLUDE_DIR}
)
+if(WITH_OPENVDB)
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+endif()
+
set(SRC
attribute.cpp
background.cpp
@@ -29,6 +35,7 @@ set(SRC
mesh_displace.cpp
nodes.cpp
object.cpp
+ openvdb.cpp
osl.cpp
particles.cpp
curves.cpp
@@ -56,6 +63,7 @@ set(SRC_HEADERS
mesh.h
nodes.h
object.h
+ openvdb.h
osl.h
particles.h
curves.h
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index bbc6cf7f65f..b49f0ffe387 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -39,6 +39,7 @@ struct Transform;
struct VoxelAttribute {
ImageManager *manager;
int slot;
+ int from_alpha;
};
/* Attribute
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 45685fe5927..fdd1e3ea32c 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -515,6 +515,7 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total
BVHParams bparams;
bparams.use_cache = params->use_bvh_cache;
bparams.use_spatial_split = params->use_bvh_spatial_split;
+ bparams.use_triangle_storage = params->use_bvh_triangle_storage;
bparams.use_qbvh = params->use_qbvh;
delete bvh;
@@ -554,9 +555,10 @@ bool Mesh::has_motion_blur() const
/* Mesh Manager */
-MeshManager::MeshManager()
+MeshManager::MeshManager(const bool free_data_after_update_)
{
bvh = NULL;
+ free_data_after_update = free_data_after_update_;
need_update = true;
need_flags_update = true;
}
@@ -816,7 +818,10 @@ static void update_attribute_element_offset(Mesh *mesh,
if(mattr->element == ATTR_ELEMENT_VOXEL) {
/* store slot in offset value */
VoxelAttribute *voxel_data = mattr->data_voxel();
- offset = voxel_data->slot;
+ offset = voxel_data->slot << 1;
+ if(voxel_data->from_alpha) {
+ ++offset;
+ }
}
else if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
uchar4 *data = mattr->data_uchar4();
@@ -1085,6 +1090,7 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
bparams.use_qbvh = scene->params.use_qbvh;
bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
bparams.use_cache = scene->params.use_bvh_cache;
+ bparams.use_triangle_storage = scene->params.use_bvh_triangle_storage;
delete bvh;
bvh = BVH::create(bparams, scene->objects);
@@ -1132,6 +1138,7 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->data.bvh.root = pack.root_index;
dscene->data.bvh.use_qbvh = scene->params.use_qbvh;
+ dscene->data.bvh.use_tri_storage = scene->params.use_bvh_triangle_storage? 1: 0;
}
void MeshManager::device_update_flags(Device * /*device*/,
@@ -1320,6 +1327,15 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
device_update_bvh(device, dscene, scene, progress);
+ if(free_data_after_update) {
+ foreach(Object *object, scene->objects) {
+ if(object->mesh->bvh != NULL) {
+ delete object->mesh->bvh;
+ object->mesh->bvh = NULL;
+ }
+ }
+ }
+
need_update = false;
if(need_displacement_images) {
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 76c186a3feb..887ef65004e 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -152,7 +152,10 @@ public:
bool need_update;
bool need_flags_update;
- MeshManager();
+ /* Free memory used by BVH after device update. */
+ bool free_data_after_update;
+
+ MeshManager(const bool free_data_after_update);
~MeshManager();
bool displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress);
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 69ae2078216..7a9ed1006ce 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -16,6 +16,7 @@
#include "image.h"
#include "nodes.h"
+#include "openvdb.h"
#include "svm.h"
#include "svm_math_util.h"
#include "osl.h"
@@ -1297,6 +1298,118 @@ void BrickTextureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_brick_texture");
}
+/* Point Density Texture */
+
+static ShaderEnum point_density_space_init()
+{
+ ShaderEnum enm;
+
+ enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT);
+ enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD);
+
+ return enm;
+}
+
+ShaderEnum PointDensityTextureNode::space_enum = point_density_space_init();
+
+PointDensityTextureNode::PointDensityTextureNode()
+: ShaderNode("point_density")
+{
+ image_manager = NULL;
+ slot = -1;
+ filename = "";
+ space = ustring("Object");
+ builtin_data = NULL;
+ interpolation = INTERPOLATION_LINEAR;
+
+ tfm = transform_identity();
+
+ add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION);
+ add_output("Density", SHADER_SOCKET_FLOAT);
+ add_output("Color", SHADER_SOCKET_COLOR);
+}
+
+PointDensityTextureNode::~PointDensityTextureNode()
+{
+ if(image_manager)
+ image_manager->remove_image(filename, builtin_data, interpolation);
+}
+
+ShaderNode *PointDensityTextureNode::clone() const
+{
+ PointDensityTextureNode *node = new PointDensityTextureNode(*this);
+ node->image_manager = NULL;
+ node->slot = -1;
+ return node;
+}
+
+void PointDensityTextureNode::attributes(Shader *shader,
+ AttributeRequestSet *attributes)
+{
+ if(shader->has_volume)
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void PointDensityTextureNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *density_out = output("Density");
+ ShaderOutput *color_out = output("Color");
+
+ bool use_density = !density_out->links.empty();
+ bool use_color = !color_out->links.empty();
+
+ image_manager = compiler.image_manager;
+
+ if (use_density || use_color) {
+ if (use_density)
+ compiler.stack_assign(density_out);
+ if (use_color)
+ compiler.stack_assign(color_out);
+
+ if(slot == -1) {
+ bool is_float, is_linear;
+ slot = image_manager->add_image(filename, builtin_data,
+ false, 0,
+ is_float, is_linear,
+ interpolation,
+ true);
+ }
+
+ if(slot != -1) {
+ compiler.stack_assign(vector_in);
+ compiler.add_node(NODE_TEX_VOXEL,
+ slot,
+ compiler.encode_uchar4(vector_in->stack_offset,
+ density_out->stack_offset,
+ color_out->stack_offset,
+ space_enum[space]));
+ if(space == "World") {
+ compiler.add_node(tfm.x);
+ compiler.add_node(tfm.y);
+ compiler.add_node(tfm.z);
+ compiler.add_node(tfm.w);
+ }
+ }
+ else {
+ compiler.add_node(NODE_VALUE_F,
+ __float_as_int(0.0f),
+ density_out->stack_offset);
+ compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
+ compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
+ TEX_IMAGE_MISSING_G,
+ TEX_IMAGE_MISSING_B));
+ }
+ }
+}
+
+void PointDensityTextureNode::compile(OSLCompiler& /*compiler*/)
+{
+ /* TODO(sergey): To be supported. */
+}
+
/* Normal */
NormalNode::NormalNode()
@@ -4367,4 +4480,71 @@ void TangentNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_tangent");
}
+OpenVDBNode::OpenVDBNode()
+: ShaderNode("openvdb")
+{
+ filename = "";
+ volume_manager = NULL;
+ sampling = OPENVDB_SAMPLE_POINT;
+ tfm = transform_identity();
+
+ add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION);
+}
+
+void OpenVDBNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if(shader->has_volume)
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void OpenVDBNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ volume_manager = compiler.volume_manager;
+
+ compiler.stack_assign(vector_in);
+
+ for(size_t i = 0; i < outputs.size(); ++i) {
+ ShaderOutput *out = outputs[i];
+
+ if(out->links.empty()) {
+ continue;
+ }
+
+ int type = NODE_VDB_FLOAT;
+
+ if(out->type == SHADER_SOCKET_VECTOR || out->type == SHADER_SOCKET_COLOR) {
+ type = NODE_VDB_FLOAT3;
+ }
+
+ grid_slot = volume_manager->add_volume(filename.string(),
+ output_names[i].string(),
+ sampling, type);
+
+ if(grid_slot == -1) {
+ continue;
+ }
+
+ compiler.stack_assign(out);
+
+ compiler.add_node(NODE_OPENVDB,
+ grid_slot,
+ compiler.encode_uchar4(type,
+ vector_in->stack_offset,
+ out->stack_offset,
+ sampling));
+
+ compiler.add_node(tfm.x);
+ compiler.add_node(tfm.y);
+ compiler.add_node(tfm.z);
+ compiler.add_node(tfm.w);
+ }
+}
+
+void OpenVDBNode::compile(OSLCompiler& /*compiler*/)
+{
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 7ec20f0879b..c839152ec2f 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -25,6 +25,7 @@ CCL_NAMESPACE_BEGIN
class ImageManager;
class Shader;
+class VolumeManager;
/* Texture Mapping */
@@ -213,6 +214,29 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
+class PointDensityTextureNode : public ShaderNode {
+public:
+ SHADER_NODE_NO_CLONE_CLASS(PointDensityTextureNode)
+
+ ~PointDensityTextureNode();
+ ShaderNode *clone() const;
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+
+ bool has_spatial_varying() { return true; }
+ bool has_object_dependency() { return true; }
+
+ ImageManager *image_manager;
+ int slot;
+ string filename;
+ ustring space;
+ void *builtin_data;
+ InterpolationType interpolation;
+
+ Transform tfm;
+
+ static ShaderEnum space_enum;
+};
+
class MappingNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MappingNode)
@@ -734,6 +758,22 @@ public:
ustring attribute;
};
+class OpenVDBNode : public ShaderNode {
+public:
+ SHADER_NODE_CLASS(OpenVDBNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_spatial_varying() { return true; }
+
+ ustring filename;
+ VolumeManager *volume_manager;
+
+ int grid_slot;
+ int sampling;
+ vector<ustring> output_names;
+
+ Transform tfm;
+};
+
CCL_NAMESPACE_END
#endif /* __NODES_H__ */
diff --git a/intern/cycles/render/openvdb.cpp b/intern/cycles/render/openvdb.cpp
new file mode 100644
index 00000000000..44468f4876e
--- /dev/null
+++ b/intern/cycles/render/openvdb.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2015 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 "openvdb.h"
+#include "scene.h"
+#include "util_logging.h"
+#include "util_progress.h"
+
+CCL_NAMESPACE_BEGIN
+
+#define MAX_VOLUME 1024
+
+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;
+}
+
+VolumeManager::~VolumeManager()
+{
+#ifdef WITH_OPENVDB
+ scalar_grids.clear();
+ vector_grids.clear();
+ current_grids.clear();
+ float_volumes.clear();
+ float3_volumes.clear();
+#endif
+}
+
+static inline void catch_exceptions()
+{
+#ifdef WITH_OPENVDB
+ try {
+ throw;
+ }
+ catch (const openvdb::IoError& e) {
+ std::cerr << e.what() << "\n";
+ }
+#endif
+}
+
+int VolumeManager::add_volume(const string& filename, const string& name, int sampling, int grid_type)
+{
+ size_t slot = -1;
+
+ if((slot = find_existing_slot(filename, name, sampling, grid_type)) != -1) {
+ return slot;
+ }
+
+ try {
+ if(is_openvdb_file(filename)) {
+ slot = add_openvdb_volume(filename, name, sampling, grid_type);
+ }
+
+ add_grid_description(filename, name, sampling, slot);
+
+ need_update = true;
+ }
+ catch (...) {
+ catch_exceptions();
+ need_update = false;
+ slot = -1;
+ }
+
+ return slot;
+}
+
+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) {
+ GridDescription grid = current_grids[i];
+
+ if(grid.filename == filename && grid.name == name) {
+ if(grid.sampling == sampling) {
+ return grid.slot;
+ }
+ else {
+ /* sampling was changed, remove the sampler */
+ 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();
+ break;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int VolumeManager::find_density_slot()
+{
+ /* first try finding a matching grid name */
+ for (size_t i = 0; i < current_grids.size(); ++i) {
+ GridDescription grid = current_grids[i];
+
+ if (string_iequals(grid.name, "density") || string_iequals(grid.name, "density high"))
+ return grid.slot;
+ }
+
+ /* try using the first scalar float grid instead */
+ if (!float_volumes.empty()) {
+ return 0;
+ }
+
+ return -1;
+}
+
+bool VolumeManager::is_openvdb_file(const string& filename) const
+{
+ return string_endswith(filename, ".vdb");
+}
+
+template <typename Container>
+size_t find_empty_slot(Container container)
+{
+ size_t slot = 0;
+
+ for(; slot < container.size(); ++slot) {
+ if(!container[slot]) {
+ break;
+ }
+ }
+
+ if(slot == container.size()) {
+ if(slot == MAX_VOLUME) {
+ printf("VolumeManager::add_volume: volume sampler limit reached %d!\n",
+ MAX_VOLUME);
+ return -1;
+ }
+
+ container.resize(slot + 1);
+ }
+
+ return slot;
+}
+
+size_t VolumeManager::add_openvdb_volume(const std::string& filename, const std::string& name, int /*sampling*/, int grid_type)
+{
+ size_t slot = -1;
+
+#ifdef WITH_OPENVDB
+ using namespace openvdb;
+
+ io::File file(filename);
+ file.open();
+
+ if (!file.hasGrid(name)) return -1;
+
+ if(grid_type == NODE_VDB_FLOAT) {
+ slot = find_empty_slot(float_volumes);
+
+ if(slot == -1) return -1;
+
+ if (!file.hasGrid(name)) return -1;
+ FloatGrid::Ptr grid = gridPtrCast<FloatGrid>(file.readGrid(name));
+ vdb_float_volume *sampler = new vdb_float_volume(grid);
+
+ float_volumes.insert(float_volumes.begin() + slot, sampler);
+ scalar_grids.push_back(grid);
+ }
+ else if(grid_type == NODE_VDB_FLOAT3) {
+ slot = find_empty_slot(float3_volumes);
+
+ if(slot == -1) return -1;
+
+ if (!file.hasGrid(name)) return -1;
+ Vec3SGrid::Ptr grid = gridPtrCast<Vec3SGrid>(file.readGrid(name));
+ vdb_float3_volume *sampler = new vdb_float3_volume(grid);
+
+ float3_volumes.insert(float3_volumes.begin() + slot, sampler);
+ vector_grids.push_back(grid);
+ }
+#else
+ (void)filename;
+ (void)name;
+ (void)grid_type;
+#endif
+
+ return slot;
+}
+
+void VolumeManager::add_grid_description(const string& filename, const string& name, int sampling, int slot)
+{
+ GridDescription descr;
+ descr.filename = filename;
+ descr.name = name;
+ descr.sampling = sampling;
+ descr.slot = slot;
+
+ current_grids.push_back(descr);
+}
+
+void VolumeManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+{
+ (void)scene;
+
+ if(!need_update) {
+ return;
+ }
+
+ device_free(device, dscene);
+ progress.set_status("Updating OpenVDB volumes", "Sending samplers to device.");
+
+ for(size_t i = 0; i < float_volumes.size(); ++i) {
+ if(!float_volumes[i]) {
+ continue;
+ }
+ 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->const_copy_to("__float3_volume", float3_volumes[i], i);
+ }
+
+ if(progress.get_cancel()) {
+ return;
+ }
+
+ dscene->data.tables.num_volumes = float_volumes.size() + float3_volumes.size();
+ dscene->data.tables.density_index = find_density_slot();
+
+ VLOG(1) << "Volume samplers allocate: __float_volume, " << float_volumes.size() * sizeof(float_volume) << " bytes";
+ VLOG(1) << "Volume samplers allocate: __float3_volume, " << float3_volumes.size() * sizeof(float3_volume) << " bytes";
+
+#ifdef WITH_OPENVDB
+ for(size_t i = 0; i < scalar_grids.size(); ++i) {
+ VLOG(1) << scalar_grids[i]->getName() << " memory usage: " << scalar_grids[i]->memUsage() / 1024.0f << " kilobytes.\n";
+ }
+
+ for(size_t i = 0; i < vector_grids.size(); ++i) {
+ VLOG(1) << vector_grids[i]->getName() << " memory usage: " << vector_grids[i]->memUsage() / 1024.0f << " kilobytes.\n";
+ }
+#endif
+
+ need_update = false;
+}
+
+void VolumeManager::device_free(Device */*device*/, DeviceScene */*dscene*/)
+{
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/openvdb.h b/intern/cycles/render/openvdb.h
new file mode 100644
index 00000000000..2aa2162c0ff
--- /dev/null
+++ b/intern/cycles/render/openvdb.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 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 __VOLUMEMANAGER_H__
+#define __VOLUMEMANAGER_H__
+
+#include "util_openvdb.h"
+#include "util_string.h"
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceScene;
+class Progress;
+class Scene;
+
+class VolumeManager {
+ struct GridDescription {
+ string filename;
+ string name;
+ int sampling;
+ int slot;
+ };
+
+ vector<GridDescription> current_grids;
+
+#ifdef WITH_OPENVDB
+ vector<openvdb::FloatGrid::Ptr> scalar_grids;
+ vector<openvdb::Vec3SGrid::Ptr> vector_grids;
+#endif
+
+ void delete_volume(int grid_type, int sampling, size_t slot);
+
+ void add_grid_description(const string& filename, const string& name, int sampling, int slot);
+ int find_existing_slot(const string& filename, const string& name, int sampling, int grid_type);
+
+ bool is_openvdb_file(const string& filename) const;
+ size_t add_openvdb_volume(const string& filename, const string& name, int sampling, int grid_type);
+
+public:
+ VolumeManager();
+ ~VolumeManager();
+
+ int add_volume(const string& filename, const string& name, int sampling, int grid_type);
+ int find_density_slot();
+
+ void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+ void device_free(Device *device, DeviceScene *dscene);
+
+ bool need_update;
+
+ vector<float_volume*> float_volumes;
+ vector<float3_volume*> float3_volumes;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __VOLUMEMANAGER_H__ */
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 19d715d834b..feffff30e89 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -26,6 +26,7 @@
#include "light.h"
#include "mesh.h"
#include "object.h"
+#include "openvdb.h"
#include "osl.h"
#include "particles.h"
#include "scene.h"
@@ -43,7 +44,9 @@
CCL_NAMESPACE_BEGIN
-Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
+Scene::Scene(const SceneParams& params_,
+ const DeviceInfo& device_info_,
+ const bool free_data_after_update)
: params(params_)
{
device = NULL;
@@ -54,13 +57,14 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
film = new Film();
background = new Background();
light_manager = new LightManager();
- mesh_manager = new MeshManager();
+ mesh_manager = new MeshManager(free_data_after_update);
object_manager = new ObjectManager();
integrator = new Integrator();
image_manager = new ImageManager();
particle_system_manager = new ParticleSystemManager();
curve_system_manager = new CurveSystemManager();
bake_manager = new BakeManager();
+ volume_manager = new VolumeManager();
/* OSL only works on the CPU */
if(device_info_.type == DEVICE_CPU)
@@ -118,6 +122,7 @@ void Scene::free_memory(bool final)
image_manager->device_free_builtin(device, &dscene);
lookup_tables->device_free(device, &dscene);
+ volume_manager->device_free(device, &dscene);
}
if(final) {
@@ -134,6 +139,7 @@ void Scene::free_memory(bool final)
delete curve_system_manager;
delete image_manager;
delete bake_manager;
+ delete volume_manager;
}
}
@@ -240,6 +246,11 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return;
+ progress.set_status("Updating OpenVDB Volumes");
+ volume_manager->device_update(device, &dscene, this, progress);
+
+ if(progress.get_cancel() || device->have_error()) return;
+
if(device->have_error() == false) {
progress.set_status("Updating Device", "Writing constant memory");
device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
@@ -300,6 +311,7 @@ bool Scene::need_reset()
|| particle_system_manager->need_update
|| curve_system_manager->need_update
|| bake_manager->need_update
+ || volume_manager->need_update
|| film->need_update);
}
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 851e5ac0b72..e7460c348ee 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -24,6 +24,7 @@
#include "kernel_types.h"
+#include "util_openvdb.h"
#include "util_param.h"
#include "util_string.h"
#include "util_system.h"
@@ -55,6 +56,7 @@ class ShaderManager;
class Progress;
class BakeManager;
class BakeData;
+class VolumeManager;
/* Scene Device Data */
@@ -128,6 +130,7 @@ public:
enum BVHType { BVH_DYNAMIC, BVH_STATIC } bvh_type;
bool use_bvh_cache;
bool use_bvh_spatial_split;
+ bool use_bvh_triangle_storage;
bool use_qbvh;
bool persistent_data;
@@ -137,6 +140,7 @@ public:
bvh_type = BVH_DYNAMIC;
use_bvh_cache = false;
use_bvh_spatial_split = false;
+ use_bvh_triangle_storage = true;
use_qbvh = false;
persistent_data = false;
}
@@ -146,6 +150,7 @@ public:
&& bvh_type == params.bvh_type
&& use_bvh_cache == params.use_bvh_cache
&& use_bvh_spatial_split == params.use_bvh_spatial_split
+ && use_bvh_triangle_storage == params.use_bvh_triangle_storage
&& use_qbvh == params.use_qbvh
&& persistent_data == params.persistent_data); }
};
@@ -177,6 +182,7 @@ public:
ParticleSystemManager *particle_system_manager;
CurveSystemManager *curve_system_manager;
BakeManager *bake_manager;
+ VolumeManager *volume_manager;
/* default shaders */
int default_surface;
@@ -194,7 +200,9 @@ public:
/* mutex must be locked manually by callers */
thread_mutex mutex;
- Scene(const SceneParams& params, const DeviceInfo& device_info);
+ Scene(const SceneParams& params,
+ const DeviceInfo& device_info,
+ const bool free_data_after_update = false);
~Scene();
void device_update(Device *device, Progress& progress);
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 57c1500628a..6408ba3adb9 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -812,6 +812,10 @@ void Session::update_scene()
progress.set_status("Updating Scene");
scene->device_update(device, progress);
}
+
+ if(clear_database_cb) {
+ clear_database_cb();
+ }
}
void Session::update_status_time(bool show_pause, bool show_done)
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index c669bccd34b..ab9f2ddb0f2 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -128,6 +128,7 @@ public:
function<void(RenderTile&)> write_render_tile_cb;
function<void(RenderTile&)> update_render_tile_cb;
+ function<void(void)> clear_database_cb;
Session(const SessionParams& params);
~Session();
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index d0bd34915df..1281beaac46 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -76,7 +76,7 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
if(shader->use_mis && shader->has_surface_emission)
scene->light_manager->need_update = true;
- SVMCompiler compiler(scene->shader_manager, scene->image_manager);
+ SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->volume_manager);
compiler.background = ((int)i == scene->default_background);
compiler.compile(shader, svm_nodes, i);
}
@@ -104,10 +104,11 @@ void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *s
/* Graph Compiler */
-SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_manager_)
+SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_manager_, VolumeManager *volume_manager_)
{
shader_manager = shader_manager_;
image_manager = image_manager_;
+ volume_manager = volume_manager_;
max_stack_use = 0;
current_type = SHADER_TYPE_SURFACE;
current_shader = NULL;
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index 4b390fb88f9..db07dd5b9e2 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -34,6 +34,7 @@ class ShaderGraph;
class ShaderInput;
class ShaderNode;
class ShaderOutput;
+class VolumeManager;
/* Shader Manager */
@@ -52,7 +53,7 @@ public:
class SVMCompiler {
public:
- SVMCompiler(ShaderManager *shader_manager, ImageManager *image_manager);
+ SVMCompiler(ShaderManager *shader_manager, ImageManager *image_manager, VolumeManager *volume_manager_);
void compile(Shader *shader, vector<int4>& svm_nodes, int index);
void stack_assign(ShaderOutput *output);
@@ -74,6 +75,7 @@ public:
ShaderType output_type() { return current_type; }
ImageManager *image_manager;
+ VolumeManager *volume_manager;
ShaderManager *shader_manager;
bool background;
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index 0acb9e9304c..a9217c65901 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRC_HEADERS
util_math_fast.h
util_md5.h
util_opengl.h
+ util_openvdb.h
util_optimization.h
util_param.h
util_path.h
@@ -83,6 +84,12 @@ if(WITH_CYCLES_DEBUG)
)
endif()
+if(WITH_OPENVDB)
+ add_definitions(
+ -DWITH_OPENVDB
+ )
+endif()
+
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
diff --git a/intern/cycles/util/util_openvdb.h b/intern/cycles/util/util_openvdb.h
new file mode 100644
index 00000000000..e262ec94c30
--- /dev/null
+++ b/intern/cycles/util/util_openvdb.h
@@ -0,0 +1,415 @@
+#ifndef __UTIL_OPENVDB_H__
+#define __UTIL_OPENVDB_H__
+
+#ifdef WITH_OPENVDB
+# include "util_map.h"
+#endif
+
+#include "util_types.h"
+
+#include "kernel_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct Ray;
+struct Intersection;
+
+enum {
+ OPENVDB_SAMPLE_POINT = 0,
+ OPENVDB_SAMPLE_BOX = 1,
+};
+
+class float_volume {
+public:
+ virtual ~float_volume() {}
+ virtual float sample(float x, float y, float z, int sampling) = 0;
+ virtual bool intersect(const Ray *ray, Intersection *isect) = 0;
+ virtual bool march(float *t0, float *t1) = 0;
+ virtual bool has_uniform_voxels() = 0;
+};
+
+class float3_volume {
+public:
+ virtual ~float3_volume() {}
+ virtual float3 sample(float x, float y, float z, int sampling) = 0;
+ virtual bool intersect(const Ray *ray, Intersection *isect) = 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
+
+CCL_NAMESPACE_BEGIN
+
+#if defined(HAS_CPP11_FEATURES)
+using std::isfinite;
+#else
+using boost::math::isfinite;
+#endif
+
+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> isector_t;
+ typedef isector_t::RayType vdb_ray_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;
+
+ openvdb::FloatGrid::ConstAccessor *accessor;
+ openvdb::math::Transform *transfrom;
+
+ /* 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;
+
+ bool uniform_voxels;
+
+public:
+ vdb_float_volume(openvdb::FloatGrid::Ptr grid)
+ : transfrom(&grid->transform())
+ {
+ accessor = new openvdb::FloatGrid::ConstAccessor(grid->getConstAccessor());
+
+ /* only grids with uniform voxels can be used with VolumeRayIntersector */
+ if(grid->hasUniformVoxels()) {
+ uniform_voxels = true;
+ main_isector = new isector_t(*grid);
+ }
+ else {
+ uniform_voxels = false;
+ main_isector = NULL;
+ }
+ }
+
+ ~vdb_float_volume()
+ {
+ for(point_map::iterator iter = point_samplers.begin();
+ iter != point_samplers.end();
+ ++iter)
+ {
+ delete iter->second;
+ }
+
+ for(box_map::iterator iter = box_samplers.begin();
+ iter != box_samplers.end();
+ ++iter)
+ {
+ delete iter->second;
+ }
+
+ if(uniform_voxels) {
+ delete main_isector;
+
+ for(isect_map::iterator iter = isectors.begin();
+ iter != isectors.end();
+ ++iter)
+ {
+ delete iter->second;
+ }
+ }
+ }
+
+ 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);
+ point_sampler_t *sampler;
+
+ if(iter == point_samplers.end()) {
+ openvdb::FloatGrid::ConstAccessor *acc = new openvdb::FloatGrid::ConstAccessor(*accessor);
+ sampler = new point_sampler_t(*acc, *transfrom);
+ pair<pthread_t, point_sampler_t *> sampl(thread, sampler);
+ point_samplers.insert(sampl);
+ }
+ else {
+ sampler = iter->second;
+ }
+
+ return sampler->wsSample(openvdb::Vec3d(x, y, z));
+ }
+ else {
+ box_map::iterator iter = box_samplers.find(thread);
+ box_sampler_t *sampler;
+
+ if(iter == box_samplers.end()) {
+ openvdb::FloatGrid::ConstAccessor *acc = new openvdb::FloatGrid::ConstAccessor(*accessor);
+ sampler = new box_sampler_t(*acc, *transfrom);
+ pair<pthread_t, box_sampler_t *> sampl(thread, sampler);
+ box_samplers.insert(sampl);
+ }
+ else {
+ 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);
+ isector_t *vdb_isect;
+
+ if(iter == isectors.end()) {
+ vdb_isect = new isector_t(*main_isector);
+ pair<pthread_t, isector_t *> inter(thread, vdb_isect);
+ isectors.insert(inter);
+ }
+ else {
+ 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;
+
+ openvdb::Real vdb_t0(*t0), vdb_t1(*t1);
+
+ if(vdb_isect->march(vdb_t0, vdb_t1)) {
+ *t0 = (float)vdb_isect->getWorldTime(vdb_t0);
+ *t1 = (float)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 */
+/* TODO(kevin): staggered velocity grid sampling */
+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::VolumeRayIntersector<openvdb::Vec3SGrid> isector_t;
+ typedef isector_t::RayType vdb_ray_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;
+
+ openvdb::Vec3SGrid::ConstAccessor *accessor;
+ openvdb::math::Transform *transfrom;
+
+ /* 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;
+
+ bool uniform_voxels;
+
+public:
+ vdb_float3_volume(openvdb::Vec3SGrid::Ptr grid)
+ : transfrom(&grid->transform())
+ {
+ accessor = new openvdb::Vec3SGrid::ConstAccessor(grid->getConstAccessor());
+
+ /* only grids with uniform voxels can be used with VolumeRayIntersector */
+ if(grid->hasUniformVoxels()) {
+ uniform_voxels = true;
+ main_isector = new isector_t(*grid);
+ }
+ else {
+ uniform_voxels = false;
+ main_isector = NULL;
+ }
+ }
+
+ ~vdb_float3_volume()
+ {
+ for(point_map::iterator iter = point_samplers.begin();
+ iter != point_samplers.end();
+ ++iter)
+ {
+ delete iter->second;
+ }
+
+ for(box_map::iterator iter = box_samplers.begin();
+ iter != box_samplers.end();
+ ++iter)
+ {
+ delete iter->second;
+ }
+
+ if(uniform_voxels) {
+ delete main_isector;
+
+ for(isect_map::iterator iter = isectors.begin();
+ iter != isectors.end();
+ ++iter)
+ {
+ delete iter->second;
+ }
+ }
+ }
+
+ ccl_always_inline float3 sample(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);
+ point_sampler_t *sampler;
+
+ if(iter == point_samplers.end()) {
+ openvdb::Vec3SGrid::ConstAccessor *acc = new openvdb::Vec3SGrid::ConstAccessor(*accessor);
+ sampler = new point_sampler_t(*acc, *transfrom);
+ pair<pthread_t, point_sampler_t *> sampl(thread, sampler);
+ point_samplers.insert(sampl);
+ }
+ else {
+ sampler = iter->second;
+ }
+
+ r = sampler->wsSample(openvdb::Vec3d(x, y, z));
+ }
+ else {
+ box_map::iterator iter = box_samplers.find(thread);
+ box_sampler_t *sampler;
+
+ if(iter == box_samplers.end()) {
+ openvdb::Vec3SGrid::ConstAccessor *acc = new openvdb::Vec3SGrid::ConstAccessor(*accessor);
+ sampler = new box_sampler_t(*acc, *transfrom);
+ pair<pthread_t, box_sampler_t *> sampl(thread, sampler);
+ box_samplers.insert(sampl);
+ }
+ else {
+ sampler = iter->second;
+ }
+
+ r = sampler->wsSample(openvdb::Vec3d(x, y, z));
+ }
+
+ return make_float3(r.x(), r.y(), r.z());
+ }
+
+ ccl_always_inline bool intersect(const Ray *ray, Intersection */*isect*/)
+ {
+ pthread_t thread = pthread_self();
+ isect_map::iterator iter = isectors.find(thread);
+ isector_t *vdb_isect;
+
+ if(iter == isectors.end()) {
+ vdb_isect = new isector_t(*main_isector);
+ pair<pthread_t, isector_t *> inter(thread, vdb_isect);
+ isectors.insert(inter);
+ }
+ else {
+ 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;
+
+ openvdb::Real vdb_t0(*t0), vdb_t1(*t1);
+
+ if(vdb_isect->march(vdb_t0, vdb_t1)) {
+ *t0 = (float)vdb_isect->getWorldTime(vdb_t0);
+ *t1 = (float)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_OPENVDB_H__ */
+
diff --git a/intern/openvdb/CMakeLists.txt b/intern/openvdb/CMakeLists.txt
new file mode 100644
index 00000000000..d7186338a16
--- /dev/null
+++ b/intern/openvdb/CMakeLists.txt
@@ -0,0 +1,61 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2015, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Kevin Dietrich.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+)
+
+set(INC_SYS
+ ${GLEW_INCLUDE_PATH}
+)
+
+set(SRC
+ openvdb_capi.h
+)
+
+if(WITH_OPENVDB)
+ add_definitions(
+ -DWITH_OPENVDB
+ -DOPENVDB_USE_BLOSC
+ )
+
+ list(APPEND INC_SYS
+ ${OPENEXR_INCLUDE_DIRS}
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+
+ list(APPEND SRC
+ intern/openvdb_dense_convert.cpp
+ intern/openvdb_primitive.cpp
+ intern/openvdb_reader.cpp
+ intern/openvdb_render.cpp
+ intern/openvdb_writer.cpp
+ openvdb_capi.cpp
+ openvdb_util.cpp
+ )
+endif()
+
+blender_add_lib(bf_intern_openvdb "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/openvdb/SConscript b/intern/openvdb/SConscript
new file mode 100644
index 00000000000..b05437b36fe
--- /dev/null
+++ b/intern/openvdb/SConscript
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2015, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Kevin Dietrich
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import ('env')
+
+sources = []
+
+defs = []
+incs = [
+ '.',
+ 'intern',
+ '../guardedalloc',
+ '../../source/blender/blenkernel',
+ '../../source/blender/blenlib',
+ '../../source/blender/makesdna',
+ '../../source/blender/makesrna',
+ env['BF_OPENVDB_INC'],
+ env['BF_BOOST_INC'],
+ env['BF_GLEW_INC']
+]
+
+incs.append(env['BF_OPENEXR_INC'].split())
+
+if env['WITH_BF_OPENVDB']:
+ defs.append('WITH_OPENVDB')
+ defs.append('DDF_DEBUG=0')
+ sources = env.Glob('*.cpp') + env.Glob('intern/*.cpp')
+
+env.BlenderLib ( libname = 'bf_intern_openvdb', sources = sources, includes = Split(incs), defines = defs, libtype=['core'], priority = [364] )
diff --git a/intern/openvdb/intern/openvdb_dense_convert.cpp b/intern/openvdb/intern/openvdb_dense_convert.cpp
new file mode 100644
index 00000000000..d7a9896675e
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_dense_convert.cpp
@@ -0,0 +1,263 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <openvdb/tools/ValueTransformer.h>
+
+#include "openvdb_capi.h"
+#include "openvdb_dense_convert.h"
+#include "openvdb_writer.h"
+
+using namespace openvdb;
+
+namespace internal {
+
+class MergeScalarGrids {
+ tree::ValueAccessor<const FloatTree> m_acc_x, m_acc_y, m_acc_z;
+
+public:
+ MergeScalarGrids(const FloatTree *x_tree, const FloatTree *y_tree, const FloatTree *z_tree)
+ : m_acc_x(*x_tree)
+ , m_acc_y(*y_tree)
+ , m_acc_z(*z_tree)
+ {}
+
+ MergeScalarGrids(const MergeScalarGrids &other)
+ : m_acc_x(other.m_acc_x)
+ , m_acc_y(other.m_acc_y)
+ , m_acc_z(other.m_acc_z)
+ {}
+
+ void operator()(const Vec3STree::ValueOnIter &it) const
+ {
+ const math::Coord xyz = it.getCoord();
+ float x = m_acc_x.getValue(xyz);
+ float y = m_acc_y.getValue(xyz);
+ float z = m_acc_z.getValue(xyz);
+
+ it.setValue(Vec3s(x, y, z));
+ }
+};
+
+GridBase *OpenVDB_export_vector_grid(OpenVDBWriter *writer,
+ const std::string &name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3],
+ float fluid_mat[4][4],
+ VecType vec_type,
+ const bool is_color,
+ const FloatGrid *mask)
+{
+
+ math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1));
+
+ Mat4R mat = Mat4R(
+ fluid_mat[0][0], fluid_mat[0][1], fluid_mat[0][2], fluid_mat[0][3],
+ fluid_mat[1][0], fluid_mat[1][1], fluid_mat[1][2], fluid_mat[1][3],
+ fluid_mat[2][0], fluid_mat[2][1], fluid_mat[2][2], fluid_mat[2][3],
+ fluid_mat[3][0], fluid_mat[3][1], fluid_mat[3][2], fluid_mat[3][3]);
+
+ math::Transform::Ptr transform = math::Transform::createLinearTransform(mat);
+
+ FloatGrid::Ptr grid[3];
+
+ grid[0] = FloatGrid::create(0.0f);
+ tools::Dense<const float, tools::LayoutXYZ> dense_grid_x(bbox, data_x);
+ tools::copyFromDense(dense_grid_x, grid[0]->tree(), TOLERANCE);
+
+ grid[1] = FloatGrid::create(0.0f);
+ tools::Dense<const float, tools::LayoutXYZ> dense_grid_y(bbox, data_y);
+ tools::copyFromDense(dense_grid_y, grid[1]->tree(), TOLERANCE);
+
+ grid[2] = FloatGrid::create(0.0f);
+ tools::Dense<const float, tools::LayoutXYZ> dense_grid_z(bbox, data_z);
+ tools::copyFromDense(dense_grid_z, grid[2]->tree(), TOLERANCE);
+
+ Vec3SGrid::Ptr vecgrid = Vec3SGrid::create(Vec3s(0.0f));
+
+ /* Activate voxels in the vector grid based on the scalar grids to ensure
+ * thread safety later on */
+ for (int i = 0; i < 3; ++i) {
+ vecgrid->tree().topologyUnion(grid[i]->tree());
+ }
+
+ MergeScalarGrids op(&(grid[0]->tree()), &(grid[1]->tree()), &(grid[2]->tree()));
+ tools::foreach(vecgrid->beginValueOn(), op, true, false);
+
+ vecgrid->setTransform(transform);
+
+ if (mask) {
+ vecgrid = tools::clip(*vecgrid, *mask);
+ }
+
+ vecgrid->setName(name);
+ vecgrid->setIsInWorldSpace(false);
+ vecgrid->setVectorType(vec_type);
+ vecgrid->insertMeta("is_color", BoolMetadata(is_color));
+
+ writer->insert(vecgrid);
+
+ return vecgrid.get();
+}
+
+class SplitVectorGrid {
+ FloatGrid::Ptr m_grid_x, m_grid_y, m_grid_z;
+
+public:
+ SplitVectorGrid()
+ {}
+
+ void operator()(const Vec3SGrid::Ptr &vecgrid)
+ {
+ Vec3s bg = vecgrid->background();
+ m_grid_x = FloatGrid::create(bg.x());
+ m_grid_y = FloatGrid::create(bg.y());
+ m_grid_z = FloatGrid::create(bg.z());
+
+ if (math::Transform::Ptr xform = vecgrid->transform().copy()) {
+ m_grid_x->setTransform(xform);
+ m_grid_y->setTransform(xform);
+ m_grid_z->setTransform(xform);
+ }
+
+ FloatGrid::Accessor acc_x = m_grid_x->getAccessor(),
+ acc_y = m_grid_y->getAccessor(),
+ acc_z = m_grid_z->getAccessor();
+
+ CoordBBox bbox;
+ for (Vec3SGrid::ValueOnCIter it = vecgrid->cbeginValueOn(); it; ++it) {
+ if (!it.getBoundingBox(bbox)) continue;
+
+ const Vec3s &val = it.getValue();
+
+ if (it.isTileValue()) {
+ m_grid_x->fill(bbox, val.x());
+ m_grid_y->fill(bbox, val.y());
+ m_grid_z->fill(bbox, val.z());
+ }
+ else {
+ acc_x.setValueOn(bbox.min(), val.x());
+ acc_y.setValueOn(bbox.min(), val.y());
+ acc_z.setValueOn(bbox.min(), val.z());
+ }
+ }
+ }
+
+ const FloatGrid::Ptr &grid_x() { return m_grid_x; }
+ const FloatGrid::Ptr &grid_y() { return m_grid_y; }
+ const FloatGrid::Ptr &grid_z() { return m_grid_z; }
+};
+
+void OpenVDB_import_grid_vector(OpenVDBReader *reader,
+ const std::string &name,
+ float **data_x, float **data_y, float **data_z,
+ const int res[3])
+{
+ Vec3SGrid::Ptr vgrid = gridPtrCast<Vec3SGrid>(reader->getGrid(name));
+
+#if 0
+ SplitVectorGrid vector_split;
+ vector_split(vgrid);
+
+ FloatGrid::Ptr grid[3];
+ math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1));
+
+ grid[0] = vector_split.grid_x();
+ tools::Dense<float, tools::LayoutXYZ> dense_grid_x(bbox);
+ tools::copyToDense(*grid[0], dense_grid_x);
+ *data_x = dense_grid_x.data();
+
+ grid[1] = vector_split.grid_y();
+ tools::Dense<float, tools::LayoutXYZ> dense_grid_y(bbox);
+ tools::copyToDense(*grid[1], dense_grid_y);
+ *data_y = dense_grid_y.data();
+
+ grid[2] = vector_split.grid_z();
+ tools::Dense<float, tools::LayoutXYZ> dense_grid_z(bbox);
+ tools::copyToDense(*grid[2], dense_grid_z);
+ *data_z = dense_grid_z.data();
+#else
+ Vec3SGrid::Accessor acc = vgrid->getAccessor();
+ math::Coord xyz;
+ int &x = xyz[0], &y = xyz[1], &z = xyz[2];
+
+ int index = 0;
+ for (z = 0; z < res[2]; ++z) {
+ for (y = 0; y < res[1]; ++y) {
+ for (x = 0; x < res[0]; ++x, ++index) {
+ math::Vec3s value = acc.getValue(xyz);
+ (*data_x)[index] = value.x();
+ (*data_y)[index] = value.y();
+ (*data_z)[index] = value.z();
+ }
+ }
+ }
+#endif
+}
+
+void OpenVDB_update_fluid_transform(const char *filename, float matrix[4][4], float matrix_high[4][4])
+{
+ /* TODO(kevin): deduplicate this call */
+ initialize();
+
+ Mat4R fluid_mat = Mat4R(
+ matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
+ matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
+ matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],
+ matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]);
+
+ Mat4R fluid_matBig = Mat4R(
+ matrix_high[0][0], matrix_high[0][1], matrix_high[0][2], matrix_high[0][3],
+ matrix_high[1][0], matrix_high[1][1], matrix_high[1][2], matrix_high[1][3],
+ matrix_high[2][0], matrix_high[2][1], matrix_high[2][2], matrix_high[2][3],
+ matrix_high[3][0], matrix_high[3][1], matrix_high[3][2], matrix_high[3][3]);
+
+ math::Transform::Ptr transform = math::Transform::createLinearTransform(fluid_mat);
+ math::Transform::Ptr transformBig = math::Transform::createLinearTransform(fluid_matBig);
+
+ io::File file(filename);
+ file.open();
+ GridPtrVecPtr grids = file.getGrids();
+ GridBase::Ptr grid;
+
+ for (size_t i = 0; i < grids->size(); ++i) {
+ grid = (*grids)[i];
+
+ const std::string name = grid->getName();
+ size_t found = name.find("High");
+
+ if (found != std::string::npos) {
+ grid->setTransform(transformBig);
+ }
+ else {
+ grid->setTransform(transform);
+ }
+ }
+
+ file.close();
+}
+
+} // namespace internal
diff --git a/intern/openvdb/intern/openvdb_dense_convert.h b/intern/openvdb/intern/openvdb_dense_convert.h
new file mode 100644
index 00000000000..d0243decf53
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_dense_convert.h
@@ -0,0 +1,140 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_DENSE_CONVERT_H__
+#define __OPENVDB_DENSE_CONVERT_H__
+
+#include <openvdb/openvdb.h>
+#include <openvdb/tools/Dense.h>
+#include <openvdb/tools/Clip.h>
+
+#include "openvdb_primitive.h"
+#include "openvdb_reader.h"
+#include "openvdb_writer.h"
+
+#define TOLERANCE 1e-3f
+
+namespace internal {
+
+template <typename GridType, typename T>
+GridType *OpenVDB_export_grid(OpenVDBWriter *writer,
+ const std::string &name,
+ const T *data,
+ const int res[3],
+ float fluid_mat[4][4],
+ const openvdb::FloatGrid *mask)
+{
+ using namespace openvdb;
+
+ math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1));
+
+ Mat4R mat = Mat4R(
+ fluid_mat[0][0], fluid_mat[0][1], fluid_mat[0][2], fluid_mat[0][3],
+ fluid_mat[1][0], fluid_mat[1][1], fluid_mat[1][2], fluid_mat[1][3],
+ fluid_mat[2][0], fluid_mat[2][1], fluid_mat[2][2], fluid_mat[2][3],
+ fluid_mat[3][0], fluid_mat[3][1], fluid_mat[3][2], fluid_mat[3][3]);
+
+ math::Transform::Ptr transform = math::Transform::createLinearTransform(mat);
+
+ typename GridType::Ptr grid = GridType::create(T(0));
+
+ tools::Dense<const T, openvdb::tools::LayoutXYZ> dense_grid(bbox, data);
+ tools::copyFromDense(dense_grid, grid->tree(), TOLERANCE);
+
+ grid->setTransform(transform);
+
+ if (mask) {
+ grid = tools::clip(*grid, *mask);
+ }
+
+ grid->setName(name);
+ grid->setIsInWorldSpace(false);
+
+ writer->insert(grid);
+
+ return grid.get();
+}
+
+template <typename GridType, typename T>
+OpenVDBPrimitive *OpenVDB_import_grid(OpenVDBReader *reader,
+ const std::string &name,
+ T **data,
+ const int res[3])
+{
+ using namespace openvdb;
+
+ typename GridType::Ptr grid_tmp = gridPtrCast<GridType>(reader->getGrid(name));
+#if 0
+ math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1));
+
+ tools::Dense<T, tools::LayoutXYZ> dense_grid(bbox);
+ tools::copyToDense(*grid_tmp, dense_grid);
+ memcpy(*data, dense_grid.data(), sizeof(T) * res[0] * res[1] * res[2]);
+#else
+ typename GridType::Accessor acc = grid_tmp->getAccessor();
+ math::Coord xyz;
+ int &x = xyz[0], &y = xyz[1], &z = xyz[2];
+
+ int index = 0;
+ for (z = 0; z < res[2]; ++z) {
+ for (y = 0; y < res[1]; ++y) {
+ for (x = 0; x < res[0]; ++x, ++index) {
+ (*data)[index] = acc.getValue(xyz);
+ }
+ }
+ }
+#endif
+
+ OpenVDBPrimitive *vdb_prim = new OpenVDBPrimitive();
+ vdb_prim->setGrid(grid_tmp);
+
+ return vdb_prim;
+}
+
+openvdb::GridBase *OpenVDB_export_vector_grid(OpenVDBWriter *writer,
+ const std::string &name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3],
+ float fluid_mat[4][4],
+ openvdb::VecType vec_type,
+ const bool is_color,
+ const openvdb::FloatGrid *mask);
+
+
+void OpenVDB_import_grid_vector(OpenVDBReader *reader,
+ const std::string &name,
+ float **data_x, float **data_y, float **data_z,
+ const int res[3]);
+
+void OpenVDB_update_fluid_transform(const char *filename,
+ float matrix[4][4],
+ float matrix_high[4][4]);
+
+}
+
+#endif /* __OPENVDB_DENSE_CONVERT_H__ */
+
diff --git a/intern/openvdb/intern/openvdb_primitive.cpp b/intern/openvdb/intern/openvdb_primitive.cpp
new file mode 100644
index 00000000000..301a1a5fcbe
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_primitive.cpp
@@ -0,0 +1,92 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_primitive.h"
+
+OpenVDBPrimitive::OpenVDBPrimitive()
+{}
+
+OpenVDBPrimitive::~OpenVDBPrimitive()
+{}
+
+openvdb::GridBase &OpenVDBPrimitive::getGrid()
+{
+ return *m_grid;
+}
+
+const openvdb::GridBase &OpenVDBPrimitive::getConstGrid() const
+{
+ return *m_grid;
+}
+
+openvdb::GridBase::Ptr OpenVDBPrimitive::getGridPtr()
+{
+ return m_grid;
+}
+
+openvdb::GridBase::ConstPtr OpenVDBPrimitive::getConstGridPtr() const
+{
+ return m_grid;
+}
+
+void OpenVDBPrimitive::setGrid(openvdb::GridBase::Ptr grid)
+{
+ m_grid = grid->copyGrid();
+}
+
+static openvdb::Mat4R convertMatrix(const float mat[4][4])
+{
+ return openvdb::Mat4R(
+ mat[0][0], mat[0][1], mat[0][2], mat[0][3],
+ mat[1][0], mat[1][1], mat[1][2], mat[1][3],
+ mat[2][0], mat[2][1], mat[2][2], mat[2][3],
+ mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
+}
+
+/* A simple protection to avoid crashes for cases when something goes wrong for
+ * some reason in the matrix creation. */
+static openvdb::math::MapBase::Ptr createAffineMap(const float mat[4][4])
+{
+ using namespace openvdb::math;
+ MapBase::Ptr transform;
+
+ try {
+ transform.reset(new AffineMap(convertMatrix(mat)));
+ }
+ catch (const openvdb::ArithmeticError &e) {
+ std::cerr << e.what() << "\n";
+ transform.reset(new AffineMap());
+ }
+
+ return transform;
+}
+
+void OpenVDBPrimitive::setTransform(const float mat[4][4])
+{
+ using namespace openvdb::math;
+
+ Transform::Ptr transform = Transform::Ptr(new Transform(createAffineMap(mat)));
+ m_grid->setTransform(transform);
+}
diff --git a/intern/openvdb/intern/openvdb_primitive.h b/intern/openvdb/intern/openvdb_primitive.h
new file mode 100644
index 00000000000..65633dfa86a
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_primitive.h
@@ -0,0 +1,47 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_PRIMITIVE_H__
+#define __OPENVDB_PRIMITIVE_H__
+
+#include <openvdb/openvdb.h>
+
+class OpenVDBPrimitive {
+ openvdb::GridBase::Ptr m_grid;
+
+public:
+ OpenVDBPrimitive();
+ ~OpenVDBPrimitive();
+
+ openvdb::GridBase &getGrid();
+ const openvdb::GridBase &getConstGrid() const;
+ openvdb::GridBase::Ptr getGridPtr();
+ openvdb::GridBase::ConstPtr getConstGridPtr() const;
+
+ void setGrid(openvdb::GridBase::Ptr grid);
+ void setTransform(const float mat[4][4]);
+};
+
+#endif /* __OPENVDB_PRIMITIVE_H__ */
diff --git a/intern/openvdb/intern/openvdb_reader.cpp b/intern/openvdb/intern/openvdb_reader.cpp
new file mode 100644
index 00000000000..1ed080e7574
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_reader.cpp
@@ -0,0 +1,107 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_reader.h"
+
+#define COPY_MAX_BYTES 10485760 /* 10 Mb */
+
+OpenVDBReader::OpenVDBReader()
+ : m_meta_map(new openvdb::MetaMap)
+{
+ /* Although it is safe, it may not be good to have this here... */
+ openvdb::initialize();
+ m_file = NULL;
+}
+
+OpenVDBReader::~OpenVDBReader()
+{
+ if (m_file) {
+ m_file->close();
+ delete m_file;
+ }
+}
+
+void OpenVDBReader::open(const std::string &filename)
+{
+ if (m_file) {
+ m_file->close();
+ delete m_file;
+ }
+
+ m_file = new openvdb::io::File(filename);
+ m_file->setCopyMaxBytes(COPY_MAX_BYTES);
+ m_file->open();
+
+ m_meta_map = m_file->getMetadata();
+}
+
+void OpenVDBReader::floatMeta(const std::string &name, float &value)
+{
+ value = m_meta_map->metaValue<float>(name);
+}
+
+void OpenVDBReader::intMeta(const std::string &name, int &value)
+{
+ value = m_meta_map->metaValue<int>(name);
+}
+
+void OpenVDBReader::vec3sMeta(const std::string &name, float value[3])
+{
+ openvdb::Vec3s meta_val = m_meta_map->metaValue<openvdb::Vec3s>(name);
+
+ value[0] = meta_val.x();
+ value[1] = meta_val.y();
+ value[2] = meta_val.z();
+}
+
+void OpenVDBReader::vec3IMeta(const std::string &name, int value[3])
+{
+ openvdb::Vec3i meta_val = m_meta_map->metaValue<openvdb::Vec3i>(name);
+
+ value[0] = meta_val.x();
+ value[1] = meta_val.y();
+ value[2] = meta_val.z();
+}
+
+void OpenVDBReader::mat4sMeta(const std::string &name, float value[4][4])
+{
+ openvdb::Mat4s meta_val = m_meta_map->metaValue<openvdb::Mat4s>(name);
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ value[i][j] = meta_val[i][j];
+ }
+ }
+}
+
+openvdb::GridBase::Ptr OpenVDBReader::getGrid(const std::string &name)
+{
+ return m_file->readGrid(name);
+}
+
+size_t OpenVDBReader::numGrids() const
+{
+ return m_file->getGrids()->size();
+}
diff --git a/intern/openvdb/intern/openvdb_reader.h b/intern/openvdb/intern/openvdb_reader.h
new file mode 100644
index 00000000000..ae79b63c9c7
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_reader.h
@@ -0,0 +1,51 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_READER_H__
+#define __OPENVDB_READER_H__
+
+#include <openvdb/openvdb.h>
+
+class OpenVDBReader {
+ openvdb::MetaMap::Ptr m_meta_map;
+ openvdb::io::File *m_file;
+
+public:
+ OpenVDBReader();
+ ~OpenVDBReader();
+
+ void open(const std::string &filename);
+
+ void floatMeta(const std::string &name, float &value);
+ void intMeta(const std::string &name, int &value);
+ void vec3sMeta(const std::string &name, float value[3]);
+ void vec3IMeta(const std::string &name, int value[3]);
+ void mat4sMeta(const std::string &name, float value[4][4]);
+
+ openvdb::GridBase::Ptr getGrid(const std::string &name);
+ size_t numGrids() const;
+};
+
+#endif /* __OPENVDB_READER_H__ */
diff --git a/intern/openvdb/intern/openvdb_render.cpp b/intern/openvdb/intern/openvdb_render.cpp
new file mode 100644
index 00000000000..51aa43676c9
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_render.cpp
@@ -0,0 +1,136 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <GL/glew.h>
+#include <openvdb/openvdb.h>
+
+#include "openvdb_primitive.h"
+#include "openvdb_render.h"
+
+namespace internal {
+
+void OpenVDBPrimitive_draw_tree(OpenVDBPrimitive *vdb_prim, const bool draw_root, const bool draw_level_1, const bool draw_level_2, const bool draw_leaves)
+{
+ using namespace openvdb;
+ using namespace openvdb::math;
+
+ FloatGrid::Ptr grid = gridPtrCast<FloatGrid>(vdb_prim->getGridPtr());
+
+ math::Vec3d wmin, wmax;
+ math::Vec3s color(0.0f);
+
+ math::Vec3s node_color[4] = {
+ math::Vec3s(0.0060f, 0.2790f, 0.6250f), // leaf nodes
+ math::Vec3s(0.8710f, 0.3940f, 0.0191f), // intermediate internal node levels
+ math::Vec3s(0.0432f, 0.3300f, 0.0411f), // first internal node level
+ math::Vec3s(0.0450f, 0.0450f, 0.0450f) // root
+ };
+
+ math::CoordBBox bbox;
+
+ glBegin(GL_LINES);
+
+ for (FloatTree::NodeCIter node_iter = grid->tree().cbeginNode(); node_iter; ++node_iter) {
+ node_iter.getBoundingBox(bbox);
+
+ const Vec3d min(bbox.min().x() - 0.5, bbox.min().y() - 0.5, bbox.min().z() - 0.5);
+ const Vec3d max(bbox.max().x() + 0.5, bbox.max().y() + 0.5, bbox.max().z() + 0.5);
+
+ wmin = grid->indexToWorld(min);
+ wmax = grid->indexToWorld(max);
+
+ const int level = node_iter.getLevel();
+
+ if (level == 0) {
+ if (!draw_leaves) {
+ continue;
+ }
+ color = node_color[0];
+ }
+
+ if (level == 1) {
+ if (!draw_level_2) {
+ continue;
+ }
+ color = node_color[1];
+ }
+
+ if (level == 2) {
+ if (!draw_level_1) {
+ continue;
+ }
+ color = node_color[2];
+ }
+
+ if (level == 3) {
+ if (!draw_root) {
+ continue;
+ }
+ color = node_color[3];
+ }
+
+ glColor3f(color[0], color[1], color[2]);
+
+ glVertex3f(wmin.x(), wmax.y(), wmax.z());
+ glVertex3f(wmax.x(), wmax.y(), wmax.z());
+
+ glVertex3f(wmin.x(), wmax.y(), wmin.z());
+ glVertex3f(wmax.x(), wmax.y(), wmin.z());
+
+ glVertex3f(wmin.x(), wmin.y(), wmax.z());
+ glVertex3f(wmax.x(), wmin.y(), wmax.z());
+
+ glVertex3f(wmin.x(), wmin.y(), wmin.z());
+ glVertex3f(wmax.x(), wmin.y(), wmin.z());
+
+ glVertex3f(wmin.x(), wmin.y(), wmin.z());
+ glVertex3f(wmin.x(), wmin.y(), wmax.z());
+
+ glVertex3f(wmin.x(), wmax.y(), wmin.z());
+ glVertex3f(wmin.x(), wmax.y(), wmax.z());
+
+ glVertex3f(wmax.x(), wmin.y(), wmin.z());
+ glVertex3f(wmax.x(), wmin.y(), wmax.z());
+
+ glVertex3f(wmax.x(), wmax.y(), wmin.z());
+ glVertex3f(wmax.x(), wmax.y(), wmax.z());
+
+ glVertex3f(wmin.x(), wmin.y(), wmin.z());
+ glVertex3f(wmin.x(), wmax.y(), wmin.z());
+
+ glVertex3f(wmax.x(), wmin.y(), wmin.z());
+ glVertex3f(wmax.x(), wmax.y(), wmin.z());
+
+ glVertex3f(wmax.x(), wmin.y(), wmax.z());
+ glVertex3f(wmax.x(), wmax.y(), wmax.z());
+
+ glVertex3f(wmin.x(), wmin.y(), wmax.z());
+ glVertex3f(wmin.x(), wmax.y(), wmax.z());
+ }
+
+ glEnd();
+}
+
+}
diff --git a/intern/openvdb/intern/openvdb_render.h b/intern/openvdb/intern/openvdb_render.h
new file mode 100644
index 00000000000..06bff3540b7
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_render.h
@@ -0,0 +1,15 @@
+#ifndef __OPENVDB_RENDER_H__
+#define __OPENVDB_RENDER_H__
+
+struct OpenVDBPrimitive;
+
+namespace internal {
+
+void OpenVDBPrimitive_draw_tree(OpenVDBPrimitive *vdb_prim, const bool draw_root,
+ const bool draw_level_1, const bool draw_level_2,
+ const bool draw_leaves);
+
+}
+
+#endif /* __OPENVDB_RENDER_H__ */
+
diff --git a/intern/openvdb/intern/openvdb_writer.cpp b/intern/openvdb/intern/openvdb_writer.cpp
new file mode 100644
index 00000000000..9c2ad40c425
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_writer.cpp
@@ -0,0 +1,93 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_writer.h"
+
+OpenVDBWriter::OpenVDBWriter()
+ : m_grids(new openvdb::GridPtrVec())
+ , m_meta_map(new openvdb::MetaMap())
+{
+ m_meta_map->insertMeta("creator", openvdb::StringMetadata("Blender/OpenVDBWriter"));
+}
+
+OpenVDBWriter::~OpenVDBWriter()
+{}
+
+void OpenVDBWriter::insert(const openvdb::GridBase::Ptr &grid)
+{
+ m_grids->push_back(grid);
+}
+
+void OpenVDBWriter::insert(const openvdb::GridBase &grid)
+{
+ m_grids->push_back(grid.copyGrid());
+}
+
+void OpenVDBWriter::insertFloatMeta(const std::string &name, const float value)
+{
+ m_meta_map->insertMeta(name, openvdb::FloatMetadata(value));
+}
+
+void OpenVDBWriter::insertIntMeta(const std::string &name, const int value)
+{
+ m_meta_map->insertMeta(name, openvdb::Int32Metadata(value));
+}
+
+void OpenVDBWriter::insertVec3sMeta(const std::string &name, const openvdb::Vec3s value)
+{
+ m_meta_map->insertMeta(name, openvdb::Vec3SMetadata(value));
+}
+
+void OpenVDBWriter::insertVec3IMeta(const std::string &name, const openvdb::Vec3I value)
+{
+ m_meta_map->insertMeta(name, openvdb::Vec3IMetadata(value));
+}
+
+void OpenVDBWriter::insertMat4sMeta(const std::string &name, const float value[4][4])
+{
+ openvdb::Mat4s mat = openvdb::Mat4s(
+ value[0][0], value[0][1], value[0][2], value[0][3],
+ value[1][0], value[1][1], value[1][2], value[1][3],
+ value[2][0], value[2][1], value[2][2], value[2][3],
+ value[3][0], value[3][1], value[3][2], value[3][3]);
+
+ m_meta_map->insertMeta(name, openvdb::Mat4SMetadata(mat));
+}
+
+void OpenVDBWriter::setFileCompression(const int flags)
+{
+ m_flags = flags;
+}
+
+void OpenVDBWriter::write(const std::string &filename) const
+{
+ openvdb::io::File file(filename);
+ file.setCompression(m_flags);
+ file.write(*m_grids, *m_meta_map);
+ file.close();
+
+ /* Should perhaps be an option at some point */
+ m_grids->clear();
+}
diff --git a/intern/openvdb/intern/openvdb_writer.h b/intern/openvdb/intern/openvdb_writer.h
new file mode 100644
index 00000000000..6f36d6233a3
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_writer.h
@@ -0,0 +1,55 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_WRITER_H__
+#define __OPENVDB_WRITER_H__
+
+#include <openvdb/openvdb.h>
+
+class OpenVDBWriter {
+ openvdb::GridPtrVecPtr m_grids;
+ openvdb::MetaMap::Ptr m_meta_map;
+
+ int m_flags;
+
+public:
+ OpenVDBWriter();
+ ~OpenVDBWriter();
+
+ void insert(const openvdb::GridBase::Ptr &grid);
+ void insert(const openvdb::GridBase &grid);
+
+ void insertFloatMeta(const std::string &name, const float value);
+ void insertIntMeta(const std::string &name, const int value);
+ void insertVec3sMeta(const std::string &name, const openvdb::Vec3s value);
+ void insertVec3IMeta(const std::string &name, const openvdb::Vec3I value);
+ void insertMat4sMeta(const std::string &name, const float value[4][4]);
+
+ void setFileCompression(const int flags);
+
+ void write(const std::string &filename) const;
+};
+
+#endif /* __OPENVDB_WRITER_H__ */
diff --git a/intern/openvdb/openvdb_capi.cpp b/intern/openvdb/openvdb_capi.cpp
new file mode 100644
index 00000000000..64df4b94c3d
--- /dev/null
+++ b/intern/openvdb/openvdb_capi.cpp
@@ -0,0 +1,248 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_capi.h"
+#include "openvdb_dense_convert.h"
+#include "openvdb_primitive.h"
+#include "openvdb_render.h"
+#include "openvdb_util.h"
+
+using namespace openvdb;
+
+struct OpenVDBFloatGrid { int unused; };
+struct OpenVDBIntGrid { int unused; };
+struct OpenVDBVectorGrid { int unused; };
+
+int OpenVDB_getVersionHex()
+{
+ return OPENVDB_LIBRARY_VERSION;
+}
+
+void OpenVDB_get_grid_info(const char *filename, OpenVDBGridInfoCallback cb, void *userdata)
+{
+ int ret = OPENVDB_NO_ERROR;
+ initialize();
+
+ try {
+ io::File file(filename);
+ file.open();
+
+ GridPtrVecPtr grids = file.getGrids();
+ int grid_num = grids->size();
+
+ for (size_t i = 0; i < grid_num; ++i) {
+ GridBase::ConstPtr grid = (*grids)[i];
+
+ std::string name = grid->getName();
+ std::string value_type = grid->valueType();
+ bool is_color = false;
+ if (grid->getMetadata< TypedMetadata<bool> >("is_color"))
+ is_color = grid->metaValue<bool>("is_color");
+
+ cb(userdata, name.c_str(), value_type.c_str(), is_color);
+ }
+ }
+ catch (...) {
+ catch_exception(ret);
+ }
+}
+
+void OpenVDB_update_fluid_transform(const char *filename,
+ float matrix[4][4],
+ float matrix_high[4][4])
+{
+ int ret = OPENVDB_NO_ERROR;
+
+ try {
+ internal::OpenVDB_update_fluid_transform(filename, matrix, matrix_high);
+ }
+ catch (...) {
+ catch_exception(ret);
+ }
+}
+
+OpenVDBFloatGrid *OpenVDB_export_grid_fl(OpenVDBWriter *writer,
+ const char *name, float *data,
+ const int res[3], float matrix[4][4],
+ OpenVDBFloatGrid *mask)
+{
+ OpenVDBFloatGrid *grid =
+ (OpenVDBFloatGrid *)internal::OpenVDB_export_grid<FloatGrid>(writer, name, data, res, matrix, (FloatGrid *)mask);
+ return grid;
+}
+
+OpenVDBIntGrid *OpenVDB_export_grid_ch(OpenVDBWriter *writer,
+ const char *name, unsigned char *data,
+ const int res[3], float matrix[4][4],
+ OpenVDBFloatGrid *mask)
+{
+ OpenVDBIntGrid *grid =
+ (OpenVDBIntGrid *)internal::OpenVDB_export_grid<Int32Grid>(writer, name, data, res, matrix, (FloatGrid *)mask);
+ return grid;
+}
+
+OpenVDBVectorGrid *OpenVDB_export_grid_vec(struct OpenVDBWriter *writer,
+ const char *name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3], float matrix[4][4], short vec_type,
+ const bool is_color, OpenVDBFloatGrid *mask)
+{
+ OpenVDBVectorGrid *grid =
+ (OpenVDBVectorGrid *)internal::OpenVDB_export_vector_grid(writer, name,
+ data_x, data_y, data_z, res, matrix,
+ static_cast<openvdb::VecType>(vec_type),
+ is_color, (FloatGrid *)mask);
+ return grid;
+}
+
+OpenVDBPrimitive *OpenVDB_import_grid_fl(OpenVDBReader *reader,
+ const char *name, float **data,
+ const int res[3])
+{
+ return internal::OpenVDB_import_grid<FloatGrid>(reader, name, data, res);
+}
+
+void OpenVDB_import_grid_ch(OpenVDBReader *reader,
+ const char *name, unsigned char **data,
+ const int res[3])
+{
+ internal::OpenVDB_import_grid<Int32Grid>(reader, name, data, res);
+}
+
+void OpenVDB_import_grid_vec(struct OpenVDBReader *reader,
+ const char *name,
+ float **data_x, float **data_y, float **data_z,
+ const int res[3])
+{
+ internal::OpenVDB_import_grid_vector(reader, name, data_x, data_y, data_z, res);
+}
+
+OpenVDBWriter *OpenVDBWriter_create()
+{
+ return new OpenVDBWriter();
+}
+
+void OpenVDBWriter_free(OpenVDBWriter *writer)
+{
+ delete writer;
+ writer = NULL;
+}
+
+void OpenVDBWriter_set_compression(OpenVDBWriter *writer, const int flag)
+{
+ int compression_flags = io::COMPRESS_ACTIVE_MASK;
+
+ if (flag == 0) {
+ compression_flags |= io::COMPRESS_ZIP;
+ }
+ else if (flag == 1) {
+ compression_flags |= io::COMPRESS_BLOSC;
+ }
+ else {
+ compression_flags = io::COMPRESS_NONE;
+ }
+
+ writer->setFileCompression(compression_flags);
+}
+
+void OpenVDBWriter_add_meta_fl(OpenVDBWriter *writer, const char *name, const float value)
+{
+ writer->insertFloatMeta(name, value);
+}
+
+void OpenVDBWriter_add_meta_int(OpenVDBWriter *writer, const char *name, const int value)
+{
+ writer->insertIntMeta(name, value);
+}
+
+void OpenVDBWriter_add_meta_v3(OpenVDBWriter *writer, const char *name, const float value[3])
+{
+ writer->insertVec3sMeta(name, value);
+}
+
+void OpenVDBWriter_add_meta_v3_int(OpenVDBWriter *writer, const char *name, const int value[3])
+{
+ writer->insertVec3IMeta(name, value);
+}
+
+void OpenVDBWriter_add_meta_mat4(OpenVDBWriter *writer, const char *name, float value[4][4])
+{
+ writer->insertMat4sMeta(name, value);
+}
+
+void OpenVDBWriter_write(OpenVDBWriter *writer, const char *filename)
+{
+ writer->write(filename);
+}
+
+OpenVDBReader *OpenVDBReader_create()
+{
+ return new OpenVDBReader();
+}
+
+void OpenVDBReader_free(OpenVDBReader *reader)
+{
+ delete reader;
+ reader = NULL;
+}
+
+void OpenVDBReader_open(OpenVDBReader *reader, const char *filename)
+{
+ reader->open(filename);
+}
+
+void OpenVDBReader_get_meta_fl(OpenVDBReader *reader, const char *name, float *value)
+{
+ reader->floatMeta(name, *value);
+}
+
+void OpenVDBReader_get_meta_int(OpenVDBReader *reader, const char *name, int *value)
+{
+ reader->intMeta(name, *value);
+}
+
+void OpenVDBReader_get_meta_v3(OpenVDBReader *reader, const char *name, float value[3])
+{
+ reader->vec3sMeta(name, value);
+}
+
+void OpenVDBReader_get_meta_v3_int(OpenVDBReader *reader, const char *name, int value[3])
+{
+ reader->vec3IMeta(name, value);
+}
+
+void OpenVDBReader_get_meta_mat4(OpenVDBReader *reader, const char *name, float value[4][4])
+{
+ reader->mat4sMeta(name, value);
+}
+
+void OpenVDB_draw_primitive(OpenVDBPrimitive *vdb_prim,
+ const bool draw_root,
+ const bool draw_level_1,
+ const bool draw_level_2,
+ const bool draw_leaves)
+{
+ internal::OpenVDBPrimitive_draw_tree(vdb_prim, draw_root, draw_level_1, draw_level_2, draw_leaves);
+}
diff --git a/intern/openvdb/openvdb_capi.h b/intern/openvdb/openvdb_capi.h
new file mode 100644
index 00000000000..d0d4d80cb19
--- /dev/null
+++ b/intern/openvdb/openvdb_capi.h
@@ -0,0 +1,131 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_CAPI_H__
+#define __OPENVDB_CAPI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct OpenVDBReader;
+struct OpenVDBWriter;
+struct OpenVDBFloatGrid;
+struct OpenVDBIntGrid;
+struct OpenVDBPrimitive;
+struct OpenVDBVectorGrid;
+
+int OpenVDB_getVersionHex(void);
+
+typedef void (*OpenVDBGridInfoCallback)(void *userdata, const char *name, const char *value_type, bool is_color);
+void OpenVDB_get_grid_info(const char *filename, OpenVDBGridInfoCallback cb, void *userdata);
+
+enum {
+ OPENVDB_NO_ERROR = 0,
+ OPENVDB_ARITHM_ERROR = 1,
+ OPENVDB_ILLEGAL_ERROR = 2,
+ OPENVDB_INDEX_ERROR = 3,
+ OPENVDB_IO_ERROR = 4,
+ OPENVDB_KEY_ERROR = 5,
+ OPENVDB_LOOKUP_ERROR = 6,
+ OPENVDB_IMPL_ERROR = 7,
+ OPENVDB_REF_ERROR = 8,
+ OPENVDB_TYPE_ERROR = 9,
+ OPENVDB_VALUE_ERROR = 10,
+ OPENVDB_UNKNOWN_ERROR = 11,
+};
+
+enum {
+ VEC_INVARIANT = 0,
+ VEC_COVARIANT = 1,
+ VEC_COVARIANT_NORMALIZE = 2,
+ VEC_CONTRAVARIANT_RELATIVE = 3,
+ VEC_CONTRAVARIANT_ABSOLUTE = 4,
+};
+
+void OpenVDB_update_fluid_transform(const char *filename,
+ float matrix[4][4],
+ float matrix_high[4][4]);
+
+struct OpenVDBFloatGrid *OpenVDB_export_grid_fl(struct OpenVDBWriter *writer,
+ const char *name, float *data,
+ const int res[3], float matrix[4][4],
+ struct OpenVDBFloatGrid *mask);
+
+struct OpenVDBIntGrid *OpenVDB_export_grid_ch(struct OpenVDBWriter *writer,
+ const char *name, unsigned char *data,
+ const int res[3], float matrix[4][4],
+ struct OpenVDBFloatGrid *mask);
+
+struct OpenVDBVectorGrid *OpenVDB_export_grid_vec(struct OpenVDBWriter *writer,
+ const char *name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3], float matrix[4][4], short vec_type,
+ const bool is_color,
+ struct OpenVDBFloatGrid *mask);
+
+struct OpenVDBPrimitive *OpenVDB_import_grid_fl(struct OpenVDBReader *reader,
+ const char *name, float **data,
+ const int res[3]);
+
+void OpenVDB_import_grid_ch(struct OpenVDBReader *reader,
+ const char *name, unsigned char **data,
+ const int res[3]);
+
+void OpenVDB_import_grid_vec(struct OpenVDBReader *reader,
+ const char *name,
+ float **data_x, float **data_y, float **data_z,
+ const int res[3]);
+
+struct OpenVDBWriter *OpenVDBWriter_create(void);
+void OpenVDBWriter_free(struct OpenVDBWriter *writer);
+void OpenVDBWriter_set_compression(struct OpenVDBWriter *writer, const int flag);
+void OpenVDBWriter_add_meta_fl(struct OpenVDBWriter *writer, const char *name, const float value);
+void OpenVDBWriter_add_meta_int(struct OpenVDBWriter *writer, const char *name, const int value);
+void OpenVDBWriter_add_meta_v3(struct OpenVDBWriter *writer, const char *name, const float value[3]);
+void OpenVDBWriter_add_meta_v3_int(struct OpenVDBWriter *writer, const char *name, const int value[3]);
+void OpenVDBWriter_add_meta_mat4(struct OpenVDBWriter *writer, const char *name, float value[4][4]);
+void OpenVDBWriter_write(struct OpenVDBWriter *writer, const char *filename);
+
+struct OpenVDBReader *OpenVDBReader_create(void);
+void OpenVDBReader_free(struct OpenVDBReader *reader);
+void OpenVDBReader_open(struct OpenVDBReader *reader, const char *filename);
+void OpenVDBReader_get_meta_fl(struct OpenVDBReader *reader, const char *name, float *value);
+void OpenVDBReader_get_meta_int(struct OpenVDBReader *reader, const char *name, int *value);
+void OpenVDBReader_get_meta_v3(struct OpenVDBReader *reader, const char *name, float value[3]);
+void OpenVDBReader_get_meta_v3_int(struct OpenVDBReader *reader, const char *name, int value[3]);
+void OpenVDBReader_get_meta_mat4(struct OpenVDBReader *reader, const char *name, float value[4][4]);
+
+void OpenVDB_draw_primitive(struct OpenVDBPrimitive *vdb_prim,
+ const bool draw_root,
+ const bool draw_level_1,
+ const bool draw_level_2,
+ const bool draw_leaves);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OPENVDB_CAPI_H__ */
diff --git a/intern/openvdb/openvdb_util.cpp b/intern/openvdb/openvdb_util.cpp
new file mode 100644
index 00000000000..4caa62c6395
--- /dev/null
+++ b/intern/openvdb/openvdb_util.cpp
@@ -0,0 +1,80 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <openvdb/Exceptions.h>
+
+#include "openvdb_capi.h"
+#include "openvdb_util.h"
+
+void catch_exception(int &ret)
+{
+ try {
+ throw;
+ }
+ catch (const openvdb::ArithmeticError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_ARITHM_ERROR;
+ }
+ catch (const openvdb::IllegalValueException &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_ILLEGAL_ERROR;
+ }
+ catch (const openvdb::IndexError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_INDEX_ERROR;
+ }
+ catch (const openvdb::IoError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_IO_ERROR;
+ }
+ catch (const openvdb::KeyError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_KEY_ERROR;
+ }
+ catch (const openvdb::LookupError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_LOOKUP_ERROR;
+ }
+ catch (const openvdb::NotImplementedError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_IMPL_ERROR;
+ }
+ catch (const openvdb::ReferenceError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_REF_ERROR;
+ }
+ catch (const openvdb::TypeError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_TYPE_ERROR;
+ }
+ catch (const openvdb::ValueError &e) {
+ std::cerr << e.what() << std::endl;
+ ret = OPENVDB_VALUE_ERROR;
+ }
+ catch (...) {
+ std::cerr << "Unknown error in OpenVDB library..." << std::endl;
+ ret = OPENVDB_UNKNOWN_ERROR;
+ }
+}
diff --git a/intern/openvdb/openvdb_util.h b/intern/openvdb/openvdb_util.h
new file mode 100644
index 00000000000..56ed9ce412b
--- /dev/null
+++ b/intern/openvdb/openvdb_util.h
@@ -0,0 +1,31 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_UTIL_H__
+#define __OPENVDB_UTIL_H__
+
+void catch_exception(int &ret);
+
+#endif /* __OPENVDB_UTIL_H__ */
diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h
index 08dbded176e..8fa7daaad79 100644
--- a/intern/smoke/extern/smoke_API.h
+++ b/intern/smoke/extern/smoke_API.h
@@ -74,7 +74,7 @@ size_t smoke_get_index2d(int x, int max_x, int y);
void smoke_dissolve(struct FLUID_3D *fluid, int speed, int log);
// wavelet turbulence functions
-struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors);
+struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors, int use_sim);
void smoke_turbulence_free(struct WTURBULENCE *wt);
void smoke_turbulence_step(struct WTURBULENCE *wt, struct FLUID_3D *fluid);
@@ -109,6 +109,7 @@ int smoke_has_colors(struct FLUID_3D *fluid);
int smoke_turbulence_has_fuel(struct WTURBULENCE *wt);
int smoke_turbulence_has_colors(struct WTURBULENCE *wt);
+void smoke_ensure_simulation(struct FLUID_3D *fluid, struct WTURBULENCE *wt);
void smoke_ensure_heat(struct FLUID_3D *fluid);
void smoke_ensure_fire(struct FLUID_3D *fluid, struct WTURBULENCE *wt);
void smoke_ensure_colors(struct FLUID_3D *fluid, struct WTURBULENCE *wt, float init_r, float init_g, float init_b);
diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp
index 3d712d2124a..2260057c0d2 100644
--- a/intern/smoke/intern/WTURBULENCE.cpp
+++ b/intern/smoke/intern/WTURBULENCE.cpp
@@ -51,8 +51,10 @@ static const float persistence = 0.56123f;
//////////////////////////////////////////////////////////////////////
// constructor
//////////////////////////////////////////////////////////////////////
-WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors)
+WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors, int init_sim)
{
+ _need_sim_data = init_sim != 0;
+
// if noise magnitude is below this threshold, its contribution
// is negilgible, so stop evaluating new octaves
_cullingThreshold = 1e-3;
@@ -87,11 +89,14 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
// allocate high resolution density field
_totalStepsBig = 0;
_densityBig = new float[_totalCellsBig];
- _densityBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _densityBig[i] =
- _densityBigOld[i] = 0.;
+ memset(_densityBig, 0, sizeof(*_densityBig) * _totalCellsBig);
+
+ if (_need_sim_data) {
+ _densityBigOld = new float[_totalCellsBig];
+ memset(_densityBigOld, 0, sizeof(*_densityBigOld) * _totalCellsBig);
+ }
+ else {
+ _densityBigOld = NULL;
}
/* fire */
@@ -112,7 +117,6 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
_tcU = new float[_totalCellsSm];
_tcV = new float[_totalCellsSm];
_tcW = new float[_totalCellsSm];
- _tcTemp = new float[_totalCellsSm];
// map all
const float dx = 1.0f/(float)(_resSm[0]);
@@ -126,29 +130,72 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
_tcU[index] = x*dx;
_tcV[index] = y*dy;
_tcW[index] = z*dz;
- _tcTemp[index] = 0.;
}
+ if (_need_sim_data) {
+ _tcTemp = new float[_totalCellsSm];
+ memset(_tcTemp, 0, sizeof(*_tcTemp) * _totalCellsSm);
+ }
+ else {
+ _tcTemp = NULL;
+ }
+
// noise tiles
_noiseTile = new float[noiseTileSize * noiseTileSize * noiseTileSize];
setNoise(noisetype, noisefile_path);
}
+void WTURBULENCE::initSimulation()
+{
+ if (_need_sim_data) {
+ return;
+ }
+
+ if(_densityBigOld == NULL) {
+ _densityBigOld = new float[_totalCellsBig];
+ memset(_densityBigOld, 0, sizeof(*_densityBigOld) * _totalCellsBig);
+ }
+
+ if (_tcTemp == NULL) {
+ _tcTemp = new float[_totalCellsSm];
+ memset(_tcTemp, 0, sizeof(*_tcTemp) * _totalCellsSm);
+ }
+
+ if (_fuelBig != NULL) {
+ if (_fuelBigOld == NULL) {
+ _fuelBigOld = new float[_totalCellsBig];
+ _reactBigOld = new float[_totalCellsBig];
+ memset(_fuelBigOld, 0, sizeof(*_fuelBigOld) * _totalCellsBig);
+ memset(_reactBigOld, 0, sizeof(*_reactBigOld) * _totalCellsBig);
+ }
+ }
+
+ if (_color_rBig != NULL) {
+ if (_color_rBigOld == NULL) {
+ _color_rBigOld = new float[_totalCellsBig];
+ _color_gBigOld = new float[_totalCellsBig];
+ _color_bBigOld = new float[_totalCellsBig];
+ memset(_color_rBigOld, 0, sizeof(*_color_rBigOld) * _totalCellsBig);
+ memset(_color_gBigOld, 0, sizeof(*_color_gBigOld) * _totalCellsBig);
+ memset(_color_bBigOld, 0, sizeof(*_color_bBigOld) * _totalCellsBig);
+ }
+ }
+}
+
void WTURBULENCE::initFire()
{
if (!_fuelBig) {
_flameBig = new float[_totalCellsBig];
_fuelBig = new float[_totalCellsBig];
- _fuelBigOld = new float[_totalCellsBig];
_reactBig = new float[_totalCellsBig];
- _reactBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _flameBig[i] =
- _fuelBig[i] =
- _fuelBigOld[i] = 0.;
- _reactBig[i] =
- _reactBigOld[i] = 0.;
+ memset(_flameBig, 0, sizeof(*_flameBig) * _totalCellsBig);
+ memset(_fuelBig, 0, sizeof(*_fuelBig) * _totalCellsBig);
+ memset(_reactBig, 0, sizeof(*_reactBig) * _totalCellsBig);
+ if (_need_sim_data) {
+ _fuelBigOld = new float[_totalCellsBig];
+ _reactBigOld = new float[_totalCellsBig];
+ memset(_fuelBigOld, 0, sizeof(*_fuelBigOld) * _totalCellsBig);
+ memset(_reactBigOld, 0, sizeof(*_reactBigOld) * _totalCellsBig);
}
}
}
@@ -157,19 +204,20 @@ void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
{
if (!_color_rBig) {
_color_rBig = new float[_totalCellsBig];
- _color_rBigOld = new float[_totalCellsBig];
_color_gBig = new float[_totalCellsBig];
- _color_gBigOld = new float[_totalCellsBig];
_color_bBig = new float[_totalCellsBig];
- _color_bBigOld = new float[_totalCellsBig];
-
for(int i = 0; i < _totalCellsBig; i++) {
_color_rBig[i] = _densityBig[i] * init_r;
- _color_rBigOld[i] = 0.0f;
_color_gBig[i] = _densityBig[i] * init_g;
- _color_gBigOld[i] = 0.0f;
_color_bBig[i] = _densityBig[i] * init_b;
- _color_bBigOld[i] = 0.0f;
+ }
+ if (_need_sim_data) {
+ _color_rBigOld = new float[_totalCellsBig];
+ _color_gBigOld = new float[_totalCellsBig];
+ _color_bBigOld = new float[_totalCellsBig];
+ memset(_color_rBigOld, 0, sizeof(*_color_rBigOld) * _totalCellsBig);
+ memset(_color_gBigOld, 0, sizeof(*_color_gBigOld) * _totalCellsBig);
+ memset(_color_bBigOld, 0, sizeof(*_color_bBigOld) * _totalCellsBig);
}
}
}
@@ -179,7 +227,7 @@ void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
//////////////////////////////////////////////////////////////////////
WTURBULENCE::~WTURBULENCE() {
delete[] _densityBig;
- delete[] _densityBigOld;
+ if (_densityBigOld) delete[] _densityBigOld;
if (_flameBig) delete[] _flameBig;
if (_fuelBig) delete[] _fuelBig;
if (_fuelBigOld) delete[] _fuelBigOld;
@@ -196,7 +244,7 @@ WTURBULENCE::~WTURBULENCE() {
delete[] _tcU;
delete[] _tcV;
delete[] _tcW;
- delete[] _tcTemp;
+ if (_tcTemp) delete[] _tcTemp;
delete[] _noiseTile;
}
diff --git a/intern/smoke/intern/WTURBULENCE.h b/intern/smoke/intern/WTURBULENCE.h
index 36635325f62..fbc3e9eb8ba 100644
--- a/intern/smoke/intern/WTURBULENCE.h
+++ b/intern/smoke/intern/WTURBULENCE.h
@@ -36,11 +36,14 @@ struct WTURBULENCE
{
public:
// both config files can be NULL, altCfg might override values from noiseCfg
- WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors);
+ WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors, int init_sim);
/// destructor
virtual ~WTURBULENCE();
+ // Ensure data needed for simulation is allocated
+ void initSimulation();
+
void initFire();
void initColors(float init_r, float init_g, float init_b);
@@ -144,6 +147,8 @@ struct WTURBULENCE
void computeEigenvalues(float *_eigMin, float *_eigMax);
void decomposeEnergy(float *energy, float *_highFreqEnergy);
+
+ bool _need_sim_data;
};
#endif // WTURBULENCE_H
diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp
index d79aaf76d56..28b39531b91 100644
--- a/intern/smoke/intern/smoke_API.cpp
+++ b/intern/smoke/intern/smoke_API.cpp
@@ -44,10 +44,10 @@ extern "C" FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, i
return fluid;
}
-extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors)
+extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors, int use_sim)
{
if (amplify)
- return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors);
+ return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors, use_sim);
else
return NULL;
}
@@ -480,6 +480,13 @@ extern "C" int smoke_turbulence_has_colors(WTURBULENCE *wt)
}
/* additional field initialization */
+extern "C" void smoke_ensure_simulation(FLUID_3D * /*fluid*/, WTURBULENCE *wt)
+{
+ if (wt) {
+ wt->initSimulation();
+ }
+}
+
extern "C" void smoke_ensure_heat(FLUID_3D *fluid)
{
if (fluid) {