Cleanup: split Cycles export into smaller files

This commit is contained in:
2020-02-02 13:09:18 +01:00
parent 7b66f73558
commit 47402dcb91
14 changed files with 1274 additions and 1038 deletions

View File

@@ -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

View File

@@ -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<float3> oldcurve_keys;
array<float> 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

View File

@@ -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<Shader *> 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

View File

@@ -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 <string.h>
#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<typename K, typename T> class id_map {
public:
id_map(vector<T *> *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<T *> new_scene_data;
typename vector<T *>::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<K, T *> new_map;
typedef pair<const K, T *> TMapPair;
typename map<K, T *>::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<K, T *> &key_to_scene_data()
{
return b_map;
}
protected:
vector<T *> *scene_data;
map<K, T *> b_map;
set<T *> used_set;
set<void *> 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__ */

View File

@@ -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

View File

@@ -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<Shader *> 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

View File

@@ -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<Shader *> 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<int> oldtriangles;
array<Mesh::SubdFace> oldsubd_faces;
array<int> 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<float3> oldcurve_keys;
array<float> oldcurve_radius;
oldcurve_keys.steal_data(mesh->curve_keys);
oldcurve_radius.steal_data(mesh->curve_radius);
mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
/* ensure bvh rebuild (instead of refit) if has_voxel_attributes() changed */
bool oldhas_voxel_attributes = mesh->has_voxel_attributes();
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);
create_subd_mesh(
scene, mesh, b_ob, b_mesh, 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);
}
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);
}
/* 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

View File

@@ -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<Shader *> 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 */

View File

@@ -19,6 +19,7 @@
#include "render/camera.h"
#include "blender/blender_object_cull.h"
#include "blender/blender_util.h"
CCL_NAMESPACE_BEGIN

View File

@@ -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"

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,10 +539,30 @@ 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();
}
}
}
return BL::FluidDomainSettings(PointerRNA_NULL);
}
@@ -573,249 +593,21 @@ 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<typename K, typename T> class id_map {
public:
id_map(vector<T *> *scene_data_)
static inline uint object_ray_visibility(BL::Object &b_ob)
{
scene_data = scene_data_;
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;
}
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<T *> new_scene_data;
typename vector<T *>::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<K, T *> new_map;
typedef pair<const K, T *> TMapPair;
typename map<K, T *>::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<K, T *> &key_to_scene_data()
{
return b_map;
}
protected:
vector<T *> *scene_data;
map<K, T *> b_map;
set<T *> used_set;
set<void *> 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));
}
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;
}
};
class EdgeMap {
public:
EdgeMap()

View File

@@ -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