diff options
Diffstat (limited to 'intern')
37 files changed, 1930 insertions, 328 deletions
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 19986912375..8f39c5126f5 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -37,13 +37,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; @@ -120,8 +130,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)) { @@ -335,6 +359,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; @@ -350,6 +384,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", @@ -395,6 +430,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 53262b93dd0..06fc6a33953 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -42,6 +42,9 @@ #include "util_xml.h" #include "cycles_xml.h" +#ifdef WITH_ALEMBIC +#include "cycles_alembic.h" +#endif CCL_NAMESPACE_BEGIN @@ -1130,6 +1133,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); @@ -1179,6 +1201,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 7fa71397271..fb6a3d76dec 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): @@ -678,8 +684,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'} @@ -694,8 +700,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") @@ -707,6 +715,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""" @@ -1216,7 +1227,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 @@ -1440,7 +1452,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() @@ -1520,6 +1533,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..ea69bc7a636 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -422,6 +422,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 +574,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 +634,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 +648,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 +678,28 @@ 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(); + const BL::CacheLibrary::eval_mode_enum dupli_eval_mode = + preview ? BL::CacheLibrary::eval_mode_REALTIME + : BL::CacheLibrary::eval_mode_RENDER; + bool use_dupli_override = b_dupli_ob && b_cachelib && + ((b_cachelib.eval_mode() & dupli_eval_mode) != 0) && + (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 +750,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,7 +765,7 @@ 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(); @@ -740,8 +811,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 +872,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 +964,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 bcc366732df..e999945e955 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; @@ -277,7 +327,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; @@ -292,7 +342,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 */ @@ -478,6 +531,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; @@ -500,6 +562,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); @@ -519,7 +587,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 */ @@ -539,7 +616,17 @@ 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 bb345e2b3cf..379ac8c8fa5 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -100,7 +100,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); @@ -1001,6 +1002,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) @@ -1143,6 +1156,17 @@ 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; } diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index d3b01fbf1d4..9f48600161d 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,34 @@ 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; + } 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 cb50680160c..3199afedf3c 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++) { @@ -568,6 +580,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 0d9412a5712..ff435b751ad 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -285,28 +285,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; @@ -315,7 +321,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 89dd3542ef6..b6c6e502c95 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -124,6 +124,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 220169f56d3..d6e4abc8267 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -110,9 +110,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); @@ -203,9 +213,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); @@ -318,9 +338,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); @@ -375,9 +405,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/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 54b78dec54d..fbdeeed1216 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -950,7 +950,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 { diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index e5e25eb6ca8..db83d2ec024 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -179,6 +179,7 @@ CCL_NAMESPACE_END #include "svm_checker.h" #include "svm_brick.h" #include "svm_vector_transform.h" +#include "svm_voxel.h" CCL_NAMESPACE_BEGIN @@ -434,7 +435,10 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade break; case NODE_NORMAL_MAP: svm_node_normal_map(kg, sd, stack, node); - break; + break; + case NODE_TEX_VOXEL: + svm_node_tex_voxel(kg, sd, stack, node, &offset); + break; case NODE_END: default: return; diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 4f2117a605b..52f9bec02ef 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -119,7 +119,8 @@ typedef enum NodeType { NODE_TANGENT, NODE_NORMAL_MAP, NODE_HAIR_INFO, - NODE_UVMAP + NODE_UVMAP, + NODE_TEX_VOXEL, } NodeType; typedef enum NodeAttributeType { @@ -364,6 +365,11 @@ 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 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/mesh.cpp b/intern/cycles/render/mesh.cpp index 19ca159d03f..884186c5914 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; } @@ -1085,6 +1087,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 +1135,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*/, @@ -1313,6 +1317,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; } 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 430c059d686..f799e2682eb 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1297,6 +1297,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() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index ac7bbaf3547..56d21716f3b 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -196,6 +196,29 @@ public: int offset_frequency, squash_frequency; }; +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) diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 19d715d834b..d0237919f89 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -43,7 +43,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,7 +56,7 @@ 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(); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 851e5ac0b72..f4980b3e0d3 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -128,6 +128,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 +138,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 +148,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); } }; @@ -194,7 +197,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/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) { |