Cleanup: split Cycles export into smaller files
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
|
146
intern/cycles/blender/blender_geometry.cpp
Normal file
146
intern/cycles/blender/blender_geometry.cpp
Normal 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
|
279
intern/cycles/blender/blender_id_map.h
Normal file
279
intern/cycles/blender/blender_id_map.h
Normal 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__ */
|
360
intern/cycles/blender/blender_image.cpp
Normal file
360
intern/cycles/blender/blender_image.cpp
Normal 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
|
213
intern/cycles/blender/blender_light.cpp
Normal file
213
intern/cycles/blender/blender_light.cpp
Normal 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
|
||||
|
@@ -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
|
||||
|
@@ -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 */
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "render/camera.h"
|
||||
|
||||
#include "blender/blender_object_cull.h"
|
||||
#include "blender/blender_util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
|
@@ -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"
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
@@ -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()
|
||||
|
95
intern/cycles/blender/blender_volume.cpp
Normal file
95
intern/cycles/blender/blender_volume.cpp
Normal 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
|
Reference in New Issue
Block a user