From 47402dcb9160793fcfd87ea3c6e6685ea6954b3f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 2 Feb 2020 13:09:18 +0100 Subject: Cleanup: split Cycles export into smaller files --- intern/cycles/blender/CMakeLists.txt | 5 + intern/cycles/blender/blender_curves.cpp | 57 ++++ intern/cycles/blender/blender_geometry.cpp | 146 +++++++++++ intern/cycles/blender/blender_id_map.h | 279 ++++++++++++++++++++ intern/cycles/blender/blender_image.cpp | 360 ++++++++++++++++++++++++++ intern/cycles/blender/blender_light.cpp | 213 +++++++++++++++ intern/cycles/blender/blender_mesh.cpp | 281 +++----------------- intern/cycles/blender/blender_object.cpp | 206 +-------------- intern/cycles/blender/blender_object_cull.cpp | 1 + intern/cycles/blender/blender_python.cpp | 1 + intern/cycles/blender/blender_session.cpp | 335 ------------------------ intern/cycles/blender/blender_sync.h | 57 ++-- intern/cycles/blender/blender_util.h | 276 +++----------------- intern/cycles/blender/blender_volume.cpp | 95 +++++++ 14 files changed, 1274 insertions(+), 1038 deletions(-) create mode 100644 intern/cycles/blender/blender_geometry.cpp create mode 100644 intern/cycles/blender/blender_id_map.h create mode 100644 intern/cycles/blender/blender_image.cpp create mode 100644 intern/cycles/blender/blender_light.cpp create mode 100644 intern/cycles/blender/blender_volume.cpp (limited to 'intern/cycles') diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index 0888eeb78bb..d9a2ebf8571 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -18,6 +18,9 @@ set(INC_SYS set(SRC blender_camera.cpp blender_device.cpp + blender_image.cpp + blender_geometry.cpp + blender_light.cpp blender_mesh.cpp blender_object.cpp blender_object_cull.cpp @@ -30,9 +33,11 @@ set(SRC blender_sync.cpp blender_texture.cpp blender_viewport.cpp + blender_volume.cpp CCL_api.h blender_device.h + blender_id_map.h blender_object_cull.h blender_sync.h blender_session.h diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 755214f422c..64efaab70e0 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -1160,6 +1160,63 @@ void BlenderSync::sync_particle_hair( } mesh->compute_bounds(); + mesh->geometry_flags |= Mesh::GEOMETRY_CURVES; +} + +void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh) +{ + /* compares curve_keys rather than strands in order to handle quick hair + * adjustments in dynamic BVH - other methods could probably do this better*/ + array oldcurve_keys; + array oldcurve_radius; + oldcurve_keys.steal_data(mesh->curve_keys); + oldcurve_radius.steal_data(mesh->curve_radius); + + if (view_layer.use_hair) { + /* Particle hair. */ + bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); + BL::Mesh b_mesh = object_to_mesh( + b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE); + + if (b_mesh) { + sync_particle_hair(mesh, b_mesh, b_ob, false); + free_object_to_mesh(b_data, b_ob, b_mesh); + } + } + + /* tag update */ + bool rebuild = (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius); + mesh->tag_update(scene, rebuild); +} + +void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph, + BL::Object b_ob, + Mesh *mesh, + int motion_step) +{ + /* Skip if no curves were exported. */ + size_t numkeys = mesh->curve_keys.size(); + if (numkeys == 0) { + return; + } + + /* Export deformed coordinates. */ + if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { + /* Particle hair. */ + BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE); + if (b_mesh) { + sync_particle_hair(mesh, b_mesh, b_ob, true, motion_step); + free_object_to_mesh(b_data, b_ob, b_mesh); + return; + } + } + + /* No deformation on this frame, copy coordinates if other frames did have it. */ + Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (attr_mP) { + float3 *keys = &mesh->curve_keys[0]; + memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys); + } } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp new file mode 100644 index 00000000000..151b741b003 --- /dev/null +++ b/intern/cycles/blender/blender_geometry.cpp @@ -0,0 +1,146 @@ + +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/mesh.h" +#include "render/object.h" + +#include "blender/blender_sync.h" +#include "blender/blender_util.h" + +CCL_NAMESPACE_BEGIN + +Mesh *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, + BL::Object &b_ob, + BL::Object &b_ob_instance, + bool object_updated, + bool use_particle_hair) +{ + /* Test if we can instance or if the object is modified. */ + BL::ID b_ob_data = b_ob.data(); + BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data; + MeshKey key(b_key_id.ptr.data, use_particle_hair); + BL::Material material_override = view_layer.material_override; + Shader *default_shader = scene->default_surface; + + /* Find shader indices. */ + vector used_shaders; + + BL::Object::material_slots_iterator slot; + for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { + if (material_override) { + find_shader(material_override, used_shaders, default_shader); + } + else { + BL::ID b_material(slot->material()); + find_shader(b_material, used_shaders, default_shader); + } + } + + if (used_shaders.size() == 0) { + if (material_override) + find_shader(material_override, used_shaders, default_shader); + else + used_shaders.push_back(default_shader); + } + + /* Test if we need to sync. */ + Mesh *mesh; + + if (!mesh_map.sync(&mesh, b_key_id, key)) { + /* 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 + * does not get tagged for recalc. */ + else if (mesh->used_shaders != used_shaders) + ; + else { + /* Even if not tagged for recalc, we may need to sync anyway + * because the shader needs different mesh attributes. */ + bool attribute_recalc = false; + + foreach (Shader *shader, mesh->used_shaders) + if (shader->need_update_mesh) + attribute_recalc = true; + + if (!attribute_recalc) + return mesh; + } + } + + /* Ensure we only sync instanced meshes once. */ + if (mesh_synced.find(mesh) != mesh_synced.end()) + return mesh; + + progress.set_sync_status("Synchronizing object", b_ob.name()); + + mesh_synced.insert(mesh); + + mesh->clear(); + mesh->used_shaders = used_shaders; + mesh->name = ustring(b_ob_data.name().c_str()); + + if (use_particle_hair) { + sync_hair(b_depsgraph, b_ob, mesh); + } + else if (object_fluid_gas_domain_find(b_ob)) { + sync_volume(b_ob, mesh); + } + else { + sync_mesh(b_depsgraph, b_ob, mesh); + } + + return mesh; +} + +void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, + BL::Object &b_ob, + Object *object, + float motion_time, + bool use_particle_hair) +{ + /* Ensure we only sync instanced meshes once. */ + Mesh *mesh = object->mesh; + + if (mesh_motion_synced.find(mesh) != mesh_motion_synced.end()) + return; + + mesh_motion_synced.insert(mesh); + + /* Ensure we only motion sync meshes that also had mesh synced, to avoid + * unnecessary work and to ensure that its attributes were clear. */ + if (mesh_synced.find(mesh) == mesh_synced.end()) + return; + + /* Find time matching motion step required by mesh. */ + int motion_step = mesh->motion_step(motion_time); + if (motion_step < 0) { + return; + } + + if (use_particle_hair) { + sync_hair_motion(b_depsgraph, b_ob, mesh, motion_step); + } + else if (object_fluid_gas_domain_find(b_ob)) { + /* No volume motion blur support yet. */ + } + else { + sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_id_map.h b/intern/cycles/blender/blender_id_map.h new file mode 100644 index 00000000000..52031cd9f34 --- /dev/null +++ b/intern/cycles/blender/blender_id_map.h @@ -0,0 +1,279 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BLENDER_ID_MAP_H__ +#define __BLENDER_ID_MAP_H__ + +#include + +#include "util/util_map.h" +#include "util/util_set.h" +#include "util/util_vector.h" + +CCL_NAMESPACE_BEGIN + +/* ID Map + * + * Utility class to map between Blender datablocks and Cycles data structures, + * and keep track of recalc tags from the dependency graph. */ + +template class id_map { + public: + id_map(vector *scene_data_) + { + scene_data = scene_data_; + } + + T *find(const BL::ID &id) + { + return find(id.ptr.owner_id); + } + + T *find(const K &key) + { + if (b_map.find(key) != b_map.end()) { + T *data = b_map[key]; + return data; + } + + return NULL; + } + + void set_recalc(const BL::ID &id) + { + b_recalc.insert(id.ptr.data); + } + + void set_recalc(void *id_ptr) + { + b_recalc.insert(id_ptr); + } + + bool has_recalc() + { + return !(b_recalc.empty()); + } + + void pre_sync() + { + used_set.clear(); + } + + bool sync(T **r_data, const BL::ID &id) + { + return sync(r_data, id, id, id.ptr.owner_id); + } + + bool sync(T **r_data, const BL::ID &id, const K &key) + { + return sync(r_data, id, id, key); + } + + bool sync(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key) + { + T *data = find(key); + bool recalc; + + if (!data) { + /* add data if it didn't exist yet */ + data = new T(); + scene_data->push_back(data); + b_map[key] = data; + recalc = true; + } + else { + recalc = (b_recalc.find(id.ptr.data) != b_recalc.end()); + if (parent.ptr.data && parent.ptr.data != id.ptr.data) { + recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end()); + } + } + + used(data); + + *r_data = data; + return recalc; + } + + bool is_used(const K &key) + { + T *data = find(key); + return (data) ? used_set.find(data) != used_set.end() : false; + } + + void used(T *data) + { + /* tag data as still in use */ + used_set.insert(data); + } + + void set_default(T *data) + { + b_map[NULL] = data; + } + + bool post_sync(bool do_delete = true) + { + /* remove unused data */ + vector new_scene_data; + typename vector::iterator it; + bool deleted = false; + + for (it = scene_data->begin(); it != scene_data->end(); it++) { + T *data = *it; + + if (do_delete && used_set.find(data) == used_set.end()) { + delete data; + deleted = true; + } + else + new_scene_data.push_back(data); + } + + *scene_data = new_scene_data; + + /* update mapping */ + map new_map; + typedef pair TMapPair; + typename map::iterator jt; + + for (jt = b_map.begin(); jt != b_map.end(); jt++) { + TMapPair &pair = *jt; + + if (used_set.find(pair.second) != used_set.end()) + new_map[pair.first] = pair.second; + } + + used_set.clear(); + b_recalc.clear(); + b_map = new_map; + + return deleted; + } + + const map &key_to_scene_data() + { + return b_map; + } + + protected: + vector *scene_data; + map b_map; + set used_set; + set b_recalc; +}; + +/* Object Key + * + * To uniquely identify instances, we use the parent, object and persistent instance ID. + * We also export separate object for a mesh and its particle hair. */ + +enum { OBJECT_PERSISTENT_ID_SIZE = 16 }; + +struct ObjectKey { + void *parent; + int id[OBJECT_PERSISTENT_ID_SIZE]; + void *ob; + bool use_particle_hair; + + ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_) + : parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_) + { + if (id_) + memcpy(id, id_, sizeof(id)); + else + memset(id, 0, sizeof(id)); + } + + bool operator<(const ObjectKey &k) const + { + if (ob < k.ob) { + return true; + } + else if (ob == k.ob) { + if (parent < k.parent) { + return true; + } + else if (parent == k.parent) { + if (use_particle_hair < k.use_particle_hair) { + return true; + } + else if (use_particle_hair == k.use_particle_hair) { + return memcmp(id, k.id, sizeof(id)) < 0; + } + } + } + + return false; + } +}; + +/* Mesh Key + * + * We export separate geomtry for a mesh and its particle hair, so key needs to + * distinguish between them. */ + +struct MeshKey { + void *id; + bool use_particle_hair; + + MeshKey(void *id, bool use_particle_hair) : id(id), use_particle_hair(use_particle_hair) + { + } + + bool operator<(const MeshKey &k) const + { + if (id < k.id) { + return true; + } + else if (id == k.id) { + if (use_particle_hair < k.use_particle_hair) { + return true; + } + } + + return false; + } +}; + +/* Particle System Key */ + +struct ParticleSystemKey { + void *ob; + int id[OBJECT_PERSISTENT_ID_SIZE]; + + ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_) + { + if (id_) + memcpy(id, id_, sizeof(id)); + else + memset(id, 0, sizeof(id)); + } + + bool operator<(const ParticleSystemKey &k) const + { + /* first id is particle index, we don't compare that */ + if (ob < k.ob) + return true; + else if (ob == k.ob) + return memcmp(id + 1, k.id + 1, sizeof(int) * (OBJECT_PERSISTENT_ID_SIZE - 1)) < 0; + + return false; + } +}; + +CCL_NAMESPACE_END + +#endif /* __BLENDER_ID_MAP_H__ */ diff --git a/intern/cycles/blender/blender_image.cpp b/intern/cycles/blender/blender_image.cpp new file mode 100644 index 00000000000..0fe42b2d479 --- /dev/null +++ b/intern/cycles/blender/blender_image.cpp @@ -0,0 +1,360 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/image.h" + +#include "blender/blender_sync.h" +#include "blender/blender_session.h" +#include "blender/blender_util.h" + +CCL_NAMESPACE_BEGIN + +/* builtin image file name is actually an image datablock name with + * absolute sequence frame number concatenated via '@' character + * + * this function splits frame from builtin name + */ +int BlenderSession::builtin_image_frame(const string &builtin_name) +{ + int last = builtin_name.find_last_of('@'); + return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); +} + +void BlenderSession::builtin_image_info(const string &builtin_name, + void *builtin_data, + ImageMetaData &metadata) +{ + /* empty image */ + metadata.width = 1; + metadata.height = 1; + + if (!builtin_data) + return; + + /* recover ID pointer */ + PointerRNA ptr; + RNA_id_pointer_create((ID *)builtin_data, &ptr); + BL::ID b_id(ptr); + + if (b_id.is_a(&RNA_Image)) { + /* image data */ + BL::Image b_image(b_id); + + metadata.builtin_free_cache = !b_image.has_data(); + metadata.is_float = b_image.is_float(); + metadata.width = b_image.size()[0]; + metadata.height = b_image.size()[1]; + metadata.depth = 1; + metadata.channels = b_image.channels(); + + if (metadata.is_float) { + /* Float images are already converted on the Blender side, + * no need to do anything in Cycles. */ + metadata.colorspace = u_colorspace_raw; + } + } + else if (b_id.is_a(&RNA_Object)) { + /* smoke volume data */ + BL::Object b_ob(b_id); + BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); + + metadata.is_float = true; + metadata.depth = 1; + metadata.channels = 1; + + if (!b_domain) + return; + + if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) + metadata.channels = 1; + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) + metadata.channels = 4; + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) + metadata.channels = 3; + else + return; + + int3 resolution = get_int3(b_domain.domain_resolution()); + int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1; + + /* Velocity and heat data is always low-resolution. */ + if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { + amplify = 1; + } + + metadata.width = resolution.x * amplify; + metadata.height = resolution.y * amplify; + metadata.depth = resolution.z * amplify; + } + 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); + metadata.channels = 4; + metadata.width = b_point_density_node.resolution(); + metadata.height = metadata.width; + metadata.depth = metadata.width; + metadata.is_float = true; + } + } +} + +bool BlenderSession::builtin_image_pixels(const string &builtin_name, + void *builtin_data, + int tile, + unsigned char *pixels, + const size_t pixels_size, + const bool associate_alpha, + const bool free_cache) +{ + if (!builtin_data) { + return false; + } + + const int frame = builtin_image_frame(builtin_name); + + PointerRNA ptr; + RNA_id_pointer_create((ID *)builtin_data, &ptr); + BL::Image b_image(ptr); + + const int width = b_image.size()[0]; + const int height = b_image.size()[1]; + const int channels = b_image.channels(); + + unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile); + const size_t num_pixels = ((size_t)width) * height; + + if (image_pixels && num_pixels * channels == pixels_size) { + memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char)); + } + else { + if (channels == 1) { + memset(pixels, 0, pixels_size * sizeof(unsigned char)); + } + else { + const size_t num_pixels_safe = pixels_size / channels; + unsigned char *cp = pixels; + for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) { + cp[0] = 255; + cp[1] = 0; + cp[2] = 255; + if (channels == 4) { + cp[3] = 255; + } + } + } + } + + if (image_pixels) { + MEM_freeN(image_pixels); + } + + /* Free image buffers to save memory during render. */ + if (free_cache) { + b_image.buffers_free(); + } + + if (associate_alpha) { + /* Premultiply, byte images are always straight for Blender. */ + unsigned char *cp = pixels; + for (size_t i = 0; i < num_pixels; i++, cp += channels) { + cp[0] = (cp[0] * cp[3]) >> 8; + cp[1] = (cp[1] * cp[3]) >> 8; + cp[2] = (cp[2] * cp[3]) >> 8; + } + } + return true; +} + +bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, + void *builtin_data, + int tile, + float *pixels, + const size_t pixels_size, + const bool, + const bool free_cache) +{ + if (!builtin_data) { + return false; + } + + PointerRNA ptr; + RNA_id_pointer_create((ID *)builtin_data, &ptr); + BL::ID b_id(ptr); + + if (b_id.is_a(&RNA_Image)) { + /* image data */ + BL::Image b_image(b_id); + int frame = builtin_image_frame(builtin_name); + + const int width = b_image.size()[0]; + const int height = b_image.size()[1]; + const int channels = b_image.channels(); + + float *image_pixels; + image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile); + const size_t num_pixels = ((size_t)width) * height; + + if (image_pixels && num_pixels * channels == pixels_size) { + memcpy(pixels, image_pixels, pixels_size * sizeof(float)); + } + else { + if (channels == 1) { + memset(pixels, 0, num_pixels * sizeof(float)); + } + else { + const size_t num_pixels_safe = pixels_size / channels; + float *fp = pixels; + for (int i = 0; i < num_pixels_safe; i++, fp += channels) { + fp[0] = 1.0f; + fp[1] = 0.0f; + fp[2] = 1.0f; + if (channels == 4) { + fp[3] = 1.0f; + } + } + } + } + + if (image_pixels) { + MEM_freeN(image_pixels); + } + + /* Free image buffers to save memory during render. */ + if (free_cache) { + b_image.buffers_free(); + } + + return true; + } + else if (b_id.is_a(&RNA_Object)) { + /* smoke volume data */ + BL::Object b_ob(b_id); + BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); + + if (!b_domain) { + return false; + } +#if WITH_FLUID + int3 resolution = get_int3(b_domain.domain_resolution()); + int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1; + + /* Velocity and heat data is always low-resolution. */ + if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { + amplify = 1; + } + + const int width = resolution.x * amplify; + const int height = resolution.y * amplify; + const int depth = resolution.z * amplify; + const size_t num_pixels = ((size_t)width) * height * depth; + + if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) { + FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + FluidDomainSettings_density_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) { + /* this is in range 0..1, and interpreted by the OpenGL smoke viewer + * as 1500..3000 K with the first part faded to zero density */ + FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + FluidDomainSettings_flame_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) { + /* the RGB is "premultiplied" by density for better interpolation results */ + FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels * 4) { + FluidDomainSettings_color_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) { + FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels * 3) { + FluidDomainSettings_velocity_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { + FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + FluidDomainSettings_heat_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) { + FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + FluidDomainSettings_temperature_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else { + fprintf( + stderr, "Cycles error: unknown volume attribute %s, skipping\n", builtin_name.c_str()); + pixels[0] = 0.0f; + return false; + } +#endif + fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n"); + } + else { + /* We originally were passing view_layer here but in reality we need a + * a depsgraph to pass to the RE_point_density_minmax() function. + */ + /* 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_depsgraph, &length, &pixels); + } + } + + return false; +} + +void BlenderSession::builtin_images_load() +{ + /* Force builtin images to be loaded along with Blender data sync. This + * is needed because we may be reading from depsgraph evaluated data which + * can be freed by Blender before Cycles reads it. + * + * TODO: the assumption that no further access to builtin image data will + * happen is really weak, and likely to break in the future. We should find + * a better solution to hand over the data directly to the image manager + * instead of through callbacks whose timing is difficult to control. */ + ImageManager *manager = session->scene->image_manager; + Device *device = session->device; + manager->device_load_builtin(device, session->scene, session->progress); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_light.cpp b/intern/cycles/blender/blender_light.cpp new file mode 100644 index 00000000000..a8e28a011d7 --- /dev/null +++ b/intern/cycles/blender/blender_light.cpp @@ -0,0 +1,213 @@ + + +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/light.h" + +#include "blender/blender_sync.h" +#include "blender/blender_util.h" + +#include "util/util_hash.h" + +CCL_NAMESPACE_BEGIN + +void BlenderSync::sync_light(BL::Object &b_parent, + int persistent_id[OBJECT_PERSISTENT_ID_SIZE], + BL::Object &b_ob, + BL::Object &b_ob_instance, + int random_id, + Transform &tfm, + bool *use_portal) +{ + /* test if we need to sync */ + Light *light; + ObjectKey key(b_parent, persistent_id, b_ob_instance, false); + BL::Light b_light(b_ob.data()); + + /* Update if either object or light data changed. */ + if (!light_map.sync(&light, b_ob, b_parent, key)) { + Shader *shader; + if (!shader_map.sync(&shader, b_light)) { + if (light->is_portal) + *use_portal = true; + return; + } + } + + /* type */ + switch (b_light.type()) { + case BL::Light::type_POINT: { + BL::PointLight b_point_light(b_light); + light->size = b_point_light.shadow_soft_size(); + light->type = LIGHT_POINT; + break; + } + case BL::Light::type_SPOT: { + BL::SpotLight b_spot_light(b_light); + light->size = b_spot_light.shadow_soft_size(); + light->type = LIGHT_SPOT; + light->spot_angle = b_spot_light.spot_size(); + light->spot_smooth = b_spot_light.spot_blend(); + break; + } + /* Hemi were removed from 2.8 */ + // case BL::Light::type_HEMI: { + // light->type = LIGHT_DISTANT; + // light->size = 0.0f; + // break; + // } + case BL::Light::type_SUN: { + BL::SunLight b_sun_light(b_light); + light->angle = b_sun_light.angle(); + light->type = LIGHT_DISTANT; + break; + } + case BL::Light::type_AREA: { + BL::AreaLight b_area_light(b_light); + light->size = 1.0f; + light->axisu = transform_get_column(&tfm, 0); + light->axisv = transform_get_column(&tfm, 1); + light->sizeu = b_area_light.size(); + switch (b_area_light.shape()) { + case BL::AreaLight::shape_SQUARE: + light->sizev = light->sizeu; + light->round = false; + break; + case BL::AreaLight::shape_RECTANGLE: + light->sizev = b_area_light.size_y(); + light->round = false; + break; + case BL::AreaLight::shape_DISK: + light->sizev = light->sizeu; + light->round = true; + break; + case BL::AreaLight::shape_ELLIPSE: + light->sizev = b_area_light.size_y(); + light->round = true; + break; + } + light->type = LIGHT_AREA; + break; + } + } + + /* strength */ + light->strength = get_float3(b_light.color()); + light->strength *= BL::PointLight(b_light).energy(); + + /* location and (inverted!) direction */ + light->co = transform_get_column(&tfm, 3); + light->dir = -transform_get_column(&tfm, 2); + light->tfm = tfm; + + /* shader */ + vector used_shaders; + find_shader(b_light, used_shaders, scene->default_light); + light->shader = used_shaders[0]; + + /* shadow */ + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles"); + light->cast_shadow = get_boolean(clight, "cast_shadow"); + light->use_mis = get_boolean(clight, "use_multiple_importance_sampling"); + + int samples = get_int(clight, "samples"); + if (get_boolean(cscene, "use_square_samples")) + light->samples = samples * samples; + else + light->samples = samples; + + light->max_bounces = get_int(clight, "max_bounces"); + + if (b_ob != b_ob_instance) { + light->random_id = random_id; + } + else { + light->random_id = hash_uint2(hash_string(b_ob.name().c_str()), 0); + } + + if (light->type == LIGHT_AREA) + light->is_portal = get_boolean(clight, "is_portal"); + else + light->is_portal = false; + + if (light->is_portal) + *use_portal = true; + + /* visibility */ + uint visibility = object_ray_visibility(b_ob); + light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0; + light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0; + light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0; + light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0; + + /* tag */ + light->tag_update(scene); +} + +void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal) +{ + BL::World b_world = b_scene.world(); + + if (b_world) { + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); + + enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM }; + int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC); + bool sample_as_light = (sampling_method != SAMPLING_NONE); + + if (sample_as_light || use_portal) { + /* test if we need to sync */ + Light *light; + ObjectKey key(b_world, 0, b_world, false); + + if (light_map.sync(&light, b_world, b_world, key) || world_recalc || + b_world.ptr.data != world_map) { + light->type = LIGHT_BACKGROUND; + if (sampling_method == SAMPLING_MANUAL) { + light->map_resolution = get_int(cworld, "sample_map_resolution"); + } + else { + light->map_resolution = 0; + } + light->shader = scene->default_background; + light->use_mis = sample_as_light; + light->max_bounces = get_int(cworld, "max_bounces"); + + /* force enable light again when world is resynced */ + light->is_enabled = true; + + int samples = get_int(cworld, "samples"); + if (get_boolean(cscene, "use_square_samples")) + light->samples = samples * samples; + else + light->samples = samples; + + light->tag_update(scene); + light_map.set_recalc(b_world); + } + } + } + + world_map = b_world.ptr.data; + world_recalc = false; + viewport_parameters = BlenderViewportParameters(b_v3d); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index d3dac3c6151..00faafe29ee 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -278,54 +278,6 @@ static void mikk_compute_tangents( genTangSpaceDefault(&context); } -/* Create Volume Attribute */ - -static void create_mesh_volume_attribute( - BL::Object &b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame) -{ - BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob); - - if (!b_domain) - return; - - mesh->volume_isovalue = b_domain.clipping(); - - Attribute *attr = mesh->attributes.add(std); - VoxelAttribute *volume_data = attr->data_voxel(); - ImageMetaData metadata; - bool animated = false; - - volume_data->manager = image_manager; - volume_data->slot = image_manager->add_image(Attribute::standard_name(std), - b_ob.ptr.data, - animated, - frame, - INTERPOLATION_LINEAR, - EXTENSION_CLIP, - IMAGE_ALPHA_AUTO, - u_colorspace_raw, - metadata); -} - -static void create_mesh_volume_attributes(Scene *scene, BL::Object &b_ob, Mesh *mesh, float frame) -{ - /* for smoke volume rendering */ - if (mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY, frame); - if (mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR, frame); - if (mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_FLAME, frame); - if (mesh->need_attribute(scene, ATTR_STD_VOLUME_HEAT)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_HEAT, frame); - if (mesh->need_attribute(scene, ATTR_STD_VOLUME_TEMPERATURE)) - create_mesh_volume_attribute( - b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_TEMPERATURE, frame); - if (mesh->need_attribute(scene, ATTR_STD_VOLUME_VELOCITY)) - create_mesh_volume_attribute( - b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_VELOCITY, frame); -} - /* Create vertex color attributes. */ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) { @@ -767,6 +719,7 @@ static void create_mesh(Scene *scene, /* allocate memory */ mesh->reserve_mesh(numverts, numtris); mesh->reserve_subd_faces(numfaces, numngons, numcorners); + mesh->geometry_flags |= Mesh::GEOMETRY_TRIANGLES; /* create vertex coordinates and normals */ BL::Mesh::vertices_iterator v; @@ -859,9 +812,9 @@ static void create_mesh(Scene *scene, attr_create_uv_map(scene, mesh, b_mesh); } - /* for volume objects, create a matrix to transform from object space to + /* For volume objects, create a matrix to transform from object space to * mesh texture space. this does not work with deformations but that can - * probably only be done well with a volume grid mapping of coordinates */ + * probably only be done well with a volume grid mapping of coordinates. */ if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM); Transform *tfm = attr->data_transform(); @@ -930,7 +883,7 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh) if (scene->need_motion() == Scene::MOTION_NONE) return; - BL::FluidDomainSettings b_fluid_domain = object_fluid_domain_find(b_ob); + BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob); if (!b_fluid_domain) return; @@ -963,82 +916,8 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh) } } -Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph, - BL::Object &b_ob, - BL::Object &b_ob_instance, - bool object_updated, - bool use_particle_hair) +void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh) { - /* test if we can instance or if the object is modified */ - BL::ID b_ob_data = b_ob.data(); - BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data; - MeshKey key(b_key_id.ptr.data, use_particle_hair); - BL::Material material_override = view_layer.material_override; - - /* find shader indices */ - vector used_shaders; - - BL::Object::material_slots_iterator slot; - for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { - if (material_override) { - find_shader(material_override, used_shaders, scene->default_surface); - } - else { - BL::ID b_material(slot->material()); - find_shader(b_material, used_shaders, scene->default_surface); - } - } - - if (used_shaders.size() == 0) { - if (material_override) - find_shader(material_override, used_shaders, scene->default_surface); - else - used_shaders.push_back(scene->default_surface); - } - - /* test if we need to sync */ - int requested_geometry_flags = Mesh::GEOMETRY_NONE; - if (view_layer.use_surfaces) { - requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES; - } - if (view_layer.use_hair) { - requested_geometry_flags |= Mesh::GEOMETRY_CURVES; - } - Mesh *mesh; - - if (!mesh_map.sync(&mesh, b_key_id, key)) { - /* 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 - * does not get tagged for recalc */ - else if (mesh->used_shaders != used_shaders) - ; - else if (requested_geometry_flags != mesh->geometry_flags) - ; - else { - /* even if not tagged for recalc, we may need to sync anyway - * because the shader needs different mesh attributes */ - bool attribute_recalc = false; - - foreach (Shader *shader, mesh->used_shaders) - if (shader->need_update_mesh) - attribute_recalc = true; - - if (!attribute_recalc) - return mesh; - } - } - - /* ensure we only sync instanced meshes once */ - if (mesh_synced.find(mesh) != mesh_synced.end()) - return mesh; - - progress.set_sync_status("Synchronizing object", b_ob.name()); - - mesh_synced.insert(mesh); - - /* create derived mesh */ array oldtriangles; array oldsubd_faces; array oldsubd_face_corners; @@ -1046,152 +925,64 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph, oldsubd_faces.steal_data(mesh->subd_faces); oldsubd_face_corners.steal_data(mesh->subd_face_corners); - /* compares curve_keys rather than strands in order to handle quick hair - * adjustments in dynamic BVH - other methods could probably do this better*/ - array oldcurve_keys; - array oldcurve_radius; - oldcurve_keys.steal_data(mesh->curve_keys); - oldcurve_radius.steal_data(mesh->curve_radius); - - /* ensure bvh rebuild (instead of refit) if has_voxel_attributes() changed */ - bool oldhas_voxel_attributes = mesh->has_voxel_attributes(); + mesh->subdivision_type = Mesh::SUBDIVISION_NONE; - mesh->clear(); - mesh->used_shaders = used_shaders; - mesh->name = ustring(b_ob_data.name().c_str()); - - if (requested_geometry_flags != Mesh::GEOMETRY_NONE) { + if (view_layer.use_surfaces) { /* Adaptive subdivision setup. Not for baking since that requires * exact mapping to the Blender mesh. */ - if (scene->bake_manager->get_baking()) { - mesh->subdivision_type = Mesh::SUBDIVISION_NONE; - } - else { + if (!scene->bake_manager->get_baking()) { mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); } /* For some reason, meshes do not need this... */ bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); - BL::Mesh b_mesh = object_to_mesh( b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type); if (b_mesh) { /* Sync mesh itself. */ - if (view_layer.use_surfaces && !use_particle_hair) { - if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) - create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions); - else - create_mesh(scene, mesh, b_mesh, used_shaders, false); - - create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); - } - - /* Sync hair curves. */ - if (view_layer.use_hair && use_particle_hair && - mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { - sync_particle_hair(mesh, b_mesh, b_ob, false); - } + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) + create_subd_mesh( + scene, mesh, b_ob, b_mesh, mesh->used_shaders, dicing_rate, max_subdivisions); + else + create_mesh(scene, mesh, b_mesh, mesh->used_shaders, false); free_object_to_mesh(b_data, b_ob, b_mesh); } } - mesh->geometry_flags = requested_geometry_flags; /* mesh fluid motion mantaflow */ - if (!use_particle_hair) { - sync_mesh_fluid_motion(b_ob, scene, mesh); - } + sync_mesh_fluid_motion(b_ob, scene, mesh); /* tag update */ bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) || - (oldsubd_face_corners != mesh->subd_face_corners) || - (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius) || - (oldhas_voxel_attributes != mesh->has_voxel_attributes()); + (oldsubd_face_corners != mesh->subd_face_corners); mesh->tag_update(scene, rebuild); - - return mesh; } -void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph, - BL::Object &b_ob, - Object *object, - float motion_time) +void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, + BL::Object b_ob, + Mesh *mesh, + int motion_step) { - /* ensure we only sync instanced meshes once */ - Mesh *mesh = object->mesh; - - if (mesh_motion_synced.find(mesh) != mesh_motion_synced.end()) - return; - - mesh_motion_synced.insert(mesh); - - /* ensure we only motion sync meshes that also had mesh synced, to avoid - * unnecessary work and to ensure that its attributes were clear */ - if (mesh_synced.find(mesh) == mesh_synced.end()) - return; - - /* Find time matching motion step required by mesh. */ - int motion_step = mesh->motion_step(motion_time); - if (motion_step < 0) { + /* Skip if no vertices were exported. */ + size_t numverts = mesh->verts.size(); + if (numverts == 0) { return; } - /* skip empty meshes */ - const size_t numverts = mesh->verts.size(); - const size_t numkeys = mesh->curve_keys.size(); - - if (!numverts && !numkeys) - return; - - /* skip objects without deforming modifiers. this is not totally reliable, - * would need a more extensive check to see which objects are animated */ + /* Skip objects without deforming modifiers. this is not totally reliable, + * would need a more extensive check to see which objects are animated. */ BL::Mesh b_mesh(PointerRNA_NULL); - - /* manta motion is exported immediate with mesh, skip here */ - BL::FluidDomainSettings b_fluid_domain = object_fluid_domain_find(b_ob); - if (b_fluid_domain) - return; - 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_depsgraph, false, Mesh::SUBDIVISION_NONE); } - if (!b_mesh) { - /* if we have no motion blur on this frame, but on other frames, copy */ - if (numverts) { - /* triangles */ - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if (attr_mP) { - Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); - float3 *P = &mesh->verts[0]; - float3 *N = (attr_N) ? attr_N->data_float3() : NULL; - - memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts); - if (attr_mN) - memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts); - } - } - - if (numkeys) { - /* curves */ - Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if (attr_mP) { - float3 *keys = &mesh->curve_keys[0]; - memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys); - } - } - - return; - } - /* TODO(sergey): Perform preliminary check for number of vertices. */ - if (numverts) { + if (b_mesh) { + /* Export deformed coordinates. */ /* Find attributes. */ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); @@ -1256,14 +1047,24 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph, } } } + + free_object_to_mesh(b_data, b_ob, b_mesh); + return; } - /* hair motion */ - if (numkeys) - sync_particle_hair(mesh, b_mesh, b_ob, true, motion_step); + /* No deformation on this frame, copy coordinates if other frames did have it. */ + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - /* free derived mesh */ - free_object_to_mesh(b_data, b_ob, b_mesh); + if (attr_mP) { + Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); + float3 *P = &mesh->verts[0]; + float3 *N = (attr_N) ? attr_N->data_float3() : NULL; + + memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts); + if (attr_mN) + memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts); + } } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index c397a95fa71..13dfd0867ba 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -88,207 +88,6 @@ bool BlenderSync::object_is_light(BL::Object &b_ob) return (b_ob_data && b_ob_data.is_a(&RNA_Light)); } -static uint object_ray_visibility(BL::Object &b_ob) -{ - PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility"); - uint flag = 0; - - flag |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0; - flag |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0; - flag |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0; - flag |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0; - flag |= get_boolean(cvisibility, "shadow") ? PATH_RAY_SHADOW : 0; - flag |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0; - - return flag; -} - -/* Light */ - -void BlenderSync::sync_light(BL::Object &b_parent, - int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::Object &b_ob, - BL::Object &b_ob_instance, - int random_id, - Transform &tfm, - bool *use_portal) -{ - /* test if we need to sync */ - Light *light; - ObjectKey key(b_parent, persistent_id, b_ob_instance, false); - BL::Light b_light(b_ob.data()); - - /* Update if either object or light data changed. */ - if (!light_map.sync(&light, b_ob, b_parent, key)) { - Shader *shader; - if (!shader_map.sync(&shader, b_light)) { - if (light->is_portal) - *use_portal = true; - return; - } - } - - /* type */ - switch (b_light.type()) { - case BL::Light::type_POINT: { - BL::PointLight b_point_light(b_light); - light->size = b_point_light.shadow_soft_size(); - light->type = LIGHT_POINT; - break; - } - case BL::Light::type_SPOT: { - BL::SpotLight b_spot_light(b_light); - light->size = b_spot_light.shadow_soft_size(); - light->type = LIGHT_SPOT; - light->spot_angle = b_spot_light.spot_size(); - light->spot_smooth = b_spot_light.spot_blend(); - break; - } - /* Hemi were removed from 2.8 */ - // case BL::Light::type_HEMI: { - // light->type = LIGHT_DISTANT; - // light->size = 0.0f; - // break; - // } - case BL::Light::type_SUN: { - BL::SunLight b_sun_light(b_light); - light->angle = b_sun_light.angle(); - light->type = LIGHT_DISTANT; - break; - } - case BL::Light::type_AREA: { - BL::AreaLight b_area_light(b_light); - light->size = 1.0f; - light->axisu = transform_get_column(&tfm, 0); - light->axisv = transform_get_column(&tfm, 1); - light->sizeu = b_area_light.size(); - switch (b_area_light.shape()) { - case BL::AreaLight::shape_SQUARE: - light->sizev = light->sizeu; - light->round = false; - break; - case BL::AreaLight::shape_RECTANGLE: - light->sizev = b_area_light.size_y(); - light->round = false; - break; - case BL::AreaLight::shape_DISK: - light->sizev = light->sizeu; - light->round = true; - break; - case BL::AreaLight::shape_ELLIPSE: - light->sizev = b_area_light.size_y(); - light->round = true; - break; - } - light->type = LIGHT_AREA; - break; - } - } - - /* strength */ - light->strength = get_float3(b_light.color()); - light->strength *= BL::PointLight(b_light).energy(); - - /* location and (inverted!) direction */ - light->co = transform_get_column(&tfm, 3); - light->dir = -transform_get_column(&tfm, 2); - light->tfm = tfm; - - /* shader */ - vector used_shaders; - find_shader(b_light, used_shaders, scene->default_light); - light->shader = used_shaders[0]; - - /* shadow */ - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles"); - light->cast_shadow = get_boolean(clight, "cast_shadow"); - light->use_mis = get_boolean(clight, "use_multiple_importance_sampling"); - - int samples = get_int(clight, "samples"); - if (get_boolean(cscene, "use_square_samples")) - light->samples = samples * samples; - else - light->samples = samples; - - light->max_bounces = get_int(clight, "max_bounces"); - - if (b_ob != b_ob_instance) { - light->random_id = random_id; - } - else { - light->random_id = hash_uint2(hash_string(b_ob.name().c_str()), 0); - } - - if (light->type == LIGHT_AREA) - light->is_portal = get_boolean(clight, "is_portal"); - else - light->is_portal = false; - - if (light->is_portal) - *use_portal = true; - - /* visibility */ - uint visibility = object_ray_visibility(b_ob); - light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0; - light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0; - light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0; - light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0; - - /* tag */ - light->tag_update(scene); -} - -void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal) -{ - BL::World b_world = b_scene.world(); - - if (b_world) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); - - enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM }; - int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC); - bool sample_as_light = (sampling_method != SAMPLING_NONE); - - if (sample_as_light || use_portal) { - /* test if we need to sync */ - Light *light; - ObjectKey key(b_world, 0, b_world, false); - - if (light_map.sync(&light, b_world, b_world, key) || world_recalc || - b_world.ptr.data != world_map) { - light->type = LIGHT_BACKGROUND; - if (sampling_method == SAMPLING_MANUAL) { - light->map_resolution = get_int(cworld, "sample_map_resolution"); - } - else { - light->map_resolution = 0; - } - light->shader = scene->default_background; - light->use_mis = sample_as_light; - light->max_bounces = get_int(cworld, "max_bounces"); - - /* force enable light again when world is resynced */ - light->is_enabled = true; - - int samples = get_int(cworld, "samples"); - if (get_boolean(cscene, "use_square_samples")) - light->samples = samples * samples; - else - light->samples = samples; - - light->tag_update(scene); - light_map.set_recalc(b_world); - } - } - } - - world_map = b_world.ptr.data; - world_recalc = false; - viewport_parameters = BlenderViewportParameters(b_v3d); -} - /* Object */ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, @@ -393,7 +192,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* mesh deformation */ if (object->mesh) - sync_mesh_motion(b_depsgraph, b_ob, object, motion_time); + sync_geometry_motion(b_depsgraph, b_ob, object, motion_time, use_particle_hair); } return object; @@ -406,7 +205,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, object_updated = true; /* mesh sync */ - object->mesh = sync_mesh(b_depsgraph, b_ob, b_ob_instance, object_updated, use_particle_hair); + object->mesh = sync_geometry( + b_depsgraph, b_ob, b_ob_instance, object_updated, use_particle_hair); /* special case not tracked by object update flags */ diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp index 74f8fb1dc53..bebecb364eb 100644 --- a/intern/cycles/blender/blender_object_cull.cpp +++ b/intern/cycles/blender/blender_object_cull.cpp @@ -19,6 +19,7 @@ #include "render/camera.h" #include "blender/blender_object_cull.h" +#include "blender/blender_util.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 335d4daf09c..816b4552fff 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -21,6 +21,7 @@ #include "blender/blender_device.h" #include "blender/blender_sync.h" #include "blender/blender_session.h" +#include "blender/blender_util.h" #include "render/denoising.h" #include "render/merge.h" diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index e2dea24fdd1..663f3d72110 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -1112,341 +1112,6 @@ void BlenderSession::test_cancel() session->progress.set_cancel("Cancelled"); } -/* builtin image file name is actually an image datablock name with - * absolute sequence frame number concatenated via '@' character - * - * this function splits frame from builtin name - */ -int BlenderSession::builtin_image_frame(const string &builtin_name) -{ - int last = builtin_name.find_last_of('@'); - return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); -} - -void BlenderSession::builtin_image_info(const string &builtin_name, - void *builtin_data, - ImageMetaData &metadata) -{ - /* empty image */ - metadata.width = 1; - metadata.height = 1; - - if (!builtin_data) - return; - - /* recover ID pointer */ - PointerRNA ptr; - RNA_id_pointer_create((ID *)builtin_data, &ptr); - BL::ID b_id(ptr); - - if (b_id.is_a(&RNA_Image)) { - /* image data */ - BL::Image b_image(b_id); - - metadata.builtin_free_cache = !b_image.has_data(); - metadata.is_float = b_image.is_float(); - metadata.width = b_image.size()[0]; - metadata.height = b_image.size()[1]; - metadata.depth = 1; - metadata.channels = b_image.channels(); - - if (metadata.is_float) { - /* Float images are already converted on the Blender side, - * no need to do anything in Cycles. */ - metadata.colorspace = u_colorspace_raw; - } - } - else if (b_id.is_a(&RNA_Object)) { - /* smoke volume data */ - BL::Object b_ob(b_id); - BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob); - - metadata.is_float = true; - metadata.depth = 1; - metadata.channels = 1; - - if (!b_domain) - return; - - if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) - metadata.channels = 1; - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) - metadata.channels = 4; - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) - metadata.channels = 3; - else - return; - - int3 resolution = get_int3(b_domain.domain_resolution()); - int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1; - - /* Velocity and heat data is always low-resolution. */ - if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { - amplify = 1; - } - - metadata.width = resolution.x * amplify; - metadata.height = resolution.y * amplify; - metadata.depth = resolution.z * amplify; - } - 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); - metadata.channels = 4; - metadata.width = b_point_density_node.resolution(); - metadata.height = metadata.width; - metadata.depth = metadata.width; - metadata.is_float = true; - } - } -} - -bool BlenderSession::builtin_image_pixels(const string &builtin_name, - void *builtin_data, - int tile, - unsigned char *pixels, - const size_t pixels_size, - const bool associate_alpha, - const bool free_cache) -{ - if (!builtin_data) { - return false; - } - - const int frame = builtin_image_frame(builtin_name); - - PointerRNA ptr; - RNA_id_pointer_create((ID *)builtin_data, &ptr); - BL::Image b_image(ptr); - - const int width = b_image.size()[0]; - const int height = b_image.size()[1]; - const int channels = b_image.channels(); - - unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile); - const size_t num_pixels = ((size_t)width) * height; - - if (image_pixels && num_pixels * channels == pixels_size) { - memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char)); - } - else { - if (channels == 1) { - memset(pixels, 0, pixels_size * sizeof(unsigned char)); - } - else { - const size_t num_pixels_safe = pixels_size / channels; - unsigned char *cp = pixels; - for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) { - cp[0] = 255; - cp[1] = 0; - cp[2] = 255; - if (channels == 4) { - cp[3] = 255; - } - } - } - } - - if (image_pixels) { - MEM_freeN(image_pixels); - } - - /* Free image buffers to save memory during render. */ - if (free_cache) { - b_image.buffers_free(); - } - - if (associate_alpha) { - /* Premultiply, byte images are always straight for Blender. */ - unsigned char *cp = pixels; - for (size_t i = 0; i < num_pixels; i++, cp += channels) { - cp[0] = (cp[0] * cp[3]) >> 8; - cp[1] = (cp[1] * cp[3]) >> 8; - cp[2] = (cp[2] * cp[3]) >> 8; - } - } - return true; -} - -bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, - void *builtin_data, - int tile, - float *pixels, - const size_t pixels_size, - const bool, - const bool free_cache) -{ - if (!builtin_data) { - return false; - } - - PointerRNA ptr; - RNA_id_pointer_create((ID *)builtin_data, &ptr); - BL::ID b_id(ptr); - - if (b_id.is_a(&RNA_Image)) { - /* image data */ - BL::Image b_image(b_id); - int frame = builtin_image_frame(builtin_name); - - const int width = b_image.size()[0]; - const int height = b_image.size()[1]; - const int channels = b_image.channels(); - - float *image_pixels; - image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile); - const size_t num_pixels = ((size_t)width) * height; - - if (image_pixels && num_pixels * channels == pixels_size) { - memcpy(pixels, image_pixels, pixels_size * sizeof(float)); - } - else { - if (channels == 1) { - memset(pixels, 0, num_pixels * sizeof(float)); - } - else { - const size_t num_pixels_safe = pixels_size / channels; - float *fp = pixels; - for (int i = 0; i < num_pixels_safe; i++, fp += channels) { - fp[0] = 1.0f; - fp[1] = 0.0f; - fp[2] = 1.0f; - if (channels == 4) { - fp[3] = 1.0f; - } - } - } - } - - if (image_pixels) { - MEM_freeN(image_pixels); - } - - /* Free image buffers to save memory during render. */ - if (free_cache) { - b_image.buffers_free(); - } - - return true; - } - else if (b_id.is_a(&RNA_Object)) { - /* smoke volume data */ - BL::Object b_ob(b_id); - BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob); - - if (!b_domain) { - return false; - } -#if WITH_FLUID - int3 resolution = get_int3(b_domain.domain_resolution()); - int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1; - - /* Velocity and heat data is always low-resolution. */ - if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { - amplify = 1; - } - - const int width = resolution.x * amplify; - const int height = resolution.y * amplify; - const int depth = resolution.z * amplify; - const size_t num_pixels = ((size_t)width) * height * depth; - - if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) { - FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels) { - FluidDomainSettings_density_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) { - /* this is in range 0..1, and interpreted by the OpenGL smoke viewer - * as 1500..3000 K with the first part faded to zero density */ - FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels) { - FluidDomainSettings_flame_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) { - /* the RGB is "premultiplied" by density for better interpolation results */ - FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels * 4) { - FluidDomainSettings_color_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) { - FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels * 3) { - FluidDomainSettings_velocity_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { - FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels) { - FluidDomainSettings_heat_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) { - FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length); - if (length == num_pixels) { - FluidDomainSettings_temperature_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else { - fprintf( - stderr, "Cycles error: unknown volume attribute %s, skipping\n", builtin_name.c_str()); - pixels[0] = 0.0f; - return false; - } -#endif - fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n"); - } - else { - /* We originally were passing view_layer here but in reality we need a - * a depsgraph to pass to the RE_point_density_minmax() function. - */ - /* 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_depsgraph, &length, &pixels); - } - } - - return false; -} - -void BlenderSession::builtin_images_load() -{ - /* Force builtin images to be loaded along with Blender data sync. This - * is needed because we may be reading from depsgraph evaluated data which - * can be freed by Blender before Cycles reads it. - * - * TODO: the assumption that no further access to builtin image data will - * happen is really weak, and likely to break in the future. We should find - * a better solution to hand over the data directly to the image manager - * instead of through callbacks whose timing is difficult to control. */ - ImageManager *manager = session->scene->image_manager; - Device *device = session->device; - manager->device_load_builtin(device, session->scene, session->progress); -} - void BlenderSession::update_resumable_tile_manager(int num_samples) { const int num_resumable_chunks = BlenderSession::num_resumable_chunks, diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 07dccdc5a73..295d9d2e307 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -22,7 +22,7 @@ #include "RNA_access.h" #include "RNA_blender_cpp.h" -#include "blender/blender_util.h" +#include "blender/blender_id_map.h" #include "blender/blender_viewport.h" #include "render/scene.h" @@ -118,19 +118,13 @@ class BlenderSync { void **python_thread_state); void sync_film(BL::SpaceView3D &b_v3d); void sync_view(); + + /* Shader */ void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all); void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d); - void sync_curve_settings(); - void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree); - Mesh *sync_mesh(BL::Depsgraph &b_depsgrpah, - BL::Object &b_ob, - BL::Object &b_ob_instance, - bool object_updated, - bool use_particle_hair); - bool object_has_particle_hair(BL::Object b_ob); - void sync_particle_hair( - Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); + + /* Object */ Object *sync_object(BL::Depsgraph &b_depsgraph, BL::ViewLayer &b_view_layer, BL::DepsgraphObjectInstance &b_instance, @@ -139,6 +133,39 @@ class BlenderSync { bool show_lights, BlenderObjectCulling &culling, bool *use_portal); + + /* Volume */ + void sync_volume(BL::Object &b_ob, Mesh *mesh); + + /* Mesh */ + void sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh); + void sync_mesh_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step); + + /* Hair */ + void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh); + void sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step); + void sync_particle_hair( + Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); + void sync_curve_settings(); + bool object_has_particle_hair(BL::Object b_ob); + + /* Camera */ + void sync_camera_motion( + BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time); + + /* Geometry */ + Mesh *sync_geometry(BL::Depsgraph &b_depsgrpah, + BL::Object &b_ob, + BL::Object &b_ob_instance, + bool object_updated, + bool use_particle_hair); + void sync_geometry_motion(BL::Depsgraph &b_depsgraph, + BL::Object &b_ob, + Object *object, + float motion_time, + bool use_particle_hair); + + /* Light */ void sync_light(BL::Object &b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object &b_ob, @@ -147,14 +174,8 @@ class BlenderSync { Transform &tfm, bool *use_portal); void sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal); - void sync_mesh_motion(BL::Depsgraph &b_depsgraph, - BL::Object &b_ob, - Object *object, - float motion_time); - void sync_camera_motion( - BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time); - /* particles */ + /* Particles */ bool sync_dupli_particle(BL::Object &b_ob, BL::DepsgraphObjectInstance &b_instance, Object *object); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 6d6dd75db6b..cb7d1c62f60 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -531,7 +531,7 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ return use_deform_motion; } -static inline BL::FluidDomainSettings object_fluid_domain_find(BL::Object &b_ob) +static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object &b_ob) { BL::Object::modifiers_iterator b_mod; @@ -539,8 +539,28 @@ static inline BL::FluidDomainSettings object_fluid_domain_find(BL::Object &b_ob) if (b_mod->is_a(&RNA_FluidModifier)) { BL::FluidModifier b_mmd(*b_mod); - if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN) + if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN && + b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_LIQUID) { return b_mmd.domain_settings(); + } + } + } + + return BL::FluidDomainSettings(PointerRNA_NULL); +} + +static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob) +{ + BL::Object::modifiers_iterator b_mod; + + for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) { + if (b_mod->is_a(&RNA_FluidModifier)) { + BL::FluidModifier b_mmd(*b_mod); + + if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN && + b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS) { + return b_mmd.domain_settings(); + } } } @@ -573,248 +593,20 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, return Mesh::SUBDIVISION_NONE; } -/* ID Map - * - * Utility class to keep in sync with blender data. - * Used for objects, meshes, lights and shaders. */ - -template class id_map { - public: - id_map(vector *scene_data_) - { - scene_data = scene_data_; - } - - T *find(const BL::ID &id) - { - return find(id.ptr.owner_id); - } - - T *find(const K &key) - { - if (b_map.find(key) != b_map.end()) { - T *data = b_map[key]; - return data; - } - - return NULL; - } - - void set_recalc(const BL::ID &id) - { - b_recalc.insert(id.ptr.data); - } - - void set_recalc(void *id_ptr) - { - b_recalc.insert(id_ptr); - } - - bool has_recalc() - { - return !(b_recalc.empty()); - } - - void pre_sync() - { - used_set.clear(); - } - - bool sync(T **r_data, const BL::ID &id) - { - return sync(r_data, id, id, id.ptr.owner_id); - } - - bool sync(T **r_data, const BL::ID &id, const K &key) - { - return sync(r_data, id, id, key); - } - - bool sync(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key) - { - T *data = find(key); - bool recalc; - - if (!data) { - /* add data if it didn't exist yet */ - data = new T(); - scene_data->push_back(data); - b_map[key] = data; - recalc = true; - } - else { - recalc = (b_recalc.find(id.ptr.data) != b_recalc.end()); - if (parent.ptr.data && parent.ptr.data != id.ptr.data) { - recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end()); - } - } - - used(data); - - *r_data = data; - return recalc; - } - - bool is_used(const K &key) - { - T *data = find(key); - return (data) ? used_set.find(data) != used_set.end() : false; - } - - void used(T *data) - { - /* tag data as still in use */ - used_set.insert(data); - } - - void set_default(T *data) - { - b_map[NULL] = data; - } - - bool post_sync(bool do_delete = true) - { - /* remove unused data */ - vector new_scene_data; - typename vector::iterator it; - bool deleted = false; - - for (it = scene_data->begin(); it != scene_data->end(); it++) { - T *data = *it; - - if (do_delete && used_set.find(data) == used_set.end()) { - delete data; - deleted = true; - } - else - new_scene_data.push_back(data); - } - - *scene_data = new_scene_data; - - /* update mapping */ - map new_map; - typedef pair TMapPair; - typename map::iterator jt; - - for (jt = b_map.begin(); jt != b_map.end(); jt++) { - TMapPair &pair = *jt; - - if (used_set.find(pair.second) != used_set.end()) - new_map[pair.first] = pair.second; - } - - used_set.clear(); - b_recalc.clear(); - b_map = new_map; - - return deleted; - } - - const map &key_to_scene_data() - { - return b_map; - } - - protected: - vector *scene_data; - map b_map; - set used_set; - set b_recalc; -}; - -/* Object Key */ - -enum { OBJECT_PERSISTENT_ID_SIZE = 16 }; - -struct ObjectKey { - void *parent; - int id[OBJECT_PERSISTENT_ID_SIZE]; - void *ob; - bool use_particle_hair; - - ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_) - : parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_) - { - if (id_) - memcpy(id, id_, sizeof(id)); - else - memset(id, 0, sizeof(id)); - } - - bool operator<(const ObjectKey &k) const - { - if (ob < k.ob) { - return true; - } - else if (ob == k.ob) { - if (parent < k.parent) { - return true; - } - else if (parent == k.parent) { - if (use_particle_hair < k.use_particle_hair) { - return true; - } - else if (use_particle_hair == k.use_particle_hair) { - return memcmp(id, k.id, sizeof(id)) < 0; - } - } - } - - return false; - } -}; - -/* Mesh Key */ - -struct MeshKey { - void *id; - bool use_particle_hair; - - MeshKey(void *id, bool use_particle_hair) : id(id), use_particle_hair(use_particle_hair) - { - } - - bool operator<(const MeshKey &k) const - { - if (id < k.id) { - return true; - } - else if (id == k.id) { - if (use_particle_hair < k.use_particle_hair) { - return true; - } - } - - return false; - } -}; - -/* Particle System Key */ - -struct ParticleSystemKey { - void *ob; - int id[OBJECT_PERSISTENT_ID_SIZE]; - - ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_) - { - if (id_) - memcpy(id, id_, sizeof(id)); - else - memset(id, 0, sizeof(id)); - } +static inline uint object_ray_visibility(BL::Object &b_ob) +{ + PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility"); + uint flag = 0; - bool operator<(const ParticleSystemKey &k) const - { - /* first id is particle index, we don't compare that */ - if (ob < k.ob) - return true; - else if (ob == k.ob) - return memcmp(id + 1, k.id + 1, sizeof(int) * (OBJECT_PERSISTENT_ID_SIZE - 1)) < 0; + flag |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0; + flag |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0; + flag |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0; + flag |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0; + flag |= get_boolean(cvisibility, "shadow") ? PATH_RAY_SHADOW : 0; + flag |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0; - return false; - } -}; + return flag; +} class EdgeMap { public: diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp new file mode 100644 index 00000000000..87fb9620725 --- /dev/null +++ b/intern/cycles/blender/blender_volume.cpp @@ -0,0 +1,95 @@ + +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/colorspace.h" +#include "render/mesh.h" +#include "render/object.h" + +#include "blender/blender_sync.h" +#include "blender/blender_util.h" + +CCL_NAMESPACE_BEGIN + +static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float frame) +{ + BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); + if (!b_domain) { + return; + } + + ImageManager *image_manager = scene->image_manager; + AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY, + ATTR_STD_VOLUME_COLOR, + ATTR_STD_VOLUME_FLAME, + ATTR_STD_VOLUME_HEAT, + ATTR_STD_VOLUME_TEMPERATURE, + ATTR_STD_VOLUME_VELOCITY, + ATTR_STD_NONE}; + + for (int i = 0; attributes[i] != ATTR_STD_NONE; i++) { + AttributeStandard std = attributes[i]; + if (!mesh->need_attribute(scene, std)) { + continue; + } + + mesh->volume_isovalue = b_domain.clipping(); + + Attribute *attr = mesh->attributes.add(std); + VoxelAttribute *volume_data = attr->data_voxel(); + ImageMetaData metadata; + bool animated = false; + + volume_data->manager = image_manager; + volume_data->slot = image_manager->add_image(Attribute::standard_name(std), + b_ob.ptr.data, + animated, + frame, + INTERPOLATION_LINEAR, + EXTENSION_CLIP, + IMAGE_ALPHA_AUTO, + u_colorspace_raw, + metadata); + } + + /* Create a matrix to transform from object space to mesh texture space. + * This does not work with deformations but that can probably only be done + * well with a volume grid mapping of coordinates. */ + if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) { + Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM); + Transform *tfm = attr->data_transform(); + + BL::Mesh b_mesh(b_ob.data()); + float3 loc, size; + mesh_texture_space(b_mesh, loc, size); + + *tfm = transform_translate(-loc) * transform_scale(size); + } +} + +void BlenderSync::sync_volume(BL::Object &b_ob, Mesh *mesh) +{ + bool old_has_voxel_attributes = mesh->has_voxel_attributes(); + + /* Smoke domain. */ + sync_smoke_volume(scene, b_ob, mesh, b_scene.frame_current()); + + /* Tag update. */ + bool rebuild = (old_has_voxel_attributes != mesh->has_voxel_attributes()); + mesh->tag_update(scene, rebuild); +} + +CCL_NAMESPACE_END -- cgit v1.2.3