Cleanup: split Cycles export into smaller files
This commit is contained in:
@@ -18,6 +18,9 @@ set(INC_SYS
|
|||||||
set(SRC
|
set(SRC
|
||||||
blender_camera.cpp
|
blender_camera.cpp
|
||||||
blender_device.cpp
|
blender_device.cpp
|
||||||
|
blender_image.cpp
|
||||||
|
blender_geometry.cpp
|
||||||
|
blender_light.cpp
|
||||||
blender_mesh.cpp
|
blender_mesh.cpp
|
||||||
blender_object.cpp
|
blender_object.cpp
|
||||||
blender_object_cull.cpp
|
blender_object_cull.cpp
|
||||||
@@ -30,9 +33,11 @@ set(SRC
|
|||||||
blender_sync.cpp
|
blender_sync.cpp
|
||||||
blender_texture.cpp
|
blender_texture.cpp
|
||||||
blender_viewport.cpp
|
blender_viewport.cpp
|
||||||
|
blender_volume.cpp
|
||||||
|
|
||||||
CCL_api.h
|
CCL_api.h
|
||||||
blender_device.h
|
blender_device.h
|
||||||
|
blender_id_map.h
|
||||||
blender_object_cull.h
|
blender_object_cull.h
|
||||||
blender_sync.h
|
blender_sync.h
|
||||||
blender_session.h
|
blender_session.h
|
||||||
|
@@ -1160,6 +1160,63 @@ void BlenderSync::sync_particle_hair(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mesh->compute_bounds();
|
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
|
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);
|
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. */
|
/* Create vertex color attributes. */
|
||||||
static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
|
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 */
|
/* allocate memory */
|
||||||
mesh->reserve_mesh(numverts, numtris);
|
mesh->reserve_mesh(numverts, numtris);
|
||||||
mesh->reserve_subd_faces(numfaces, numngons, numcorners);
|
mesh->reserve_subd_faces(numfaces, numngons, numcorners);
|
||||||
|
mesh->geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
|
||||||
|
|
||||||
/* create vertex coordinates and normals */
|
/* create vertex coordinates and normals */
|
||||||
BL::Mesh::vertices_iterator v;
|
BL::Mesh::vertices_iterator v;
|
||||||
@@ -859,9 +812,9 @@ static void create_mesh(Scene *scene,
|
|||||||
attr_create_uv_map(scene, mesh, b_mesh);
|
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
|
* 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)) {
|
if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
|
||||||
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
|
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
|
||||||
Transform *tfm = attr->data_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)
|
if (scene->need_motion() == Scene::MOTION_NONE)
|
||||||
return;
|
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)
|
if (!b_fluid_domain)
|
||||||
return;
|
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,
|
void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh)
|
||||||
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;
|
|
||||||
|
|
||||||
/* 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<int> oldtriangles;
|
||||||
array<Mesh::SubdFace> oldsubd_faces;
|
array<Mesh::SubdFace> oldsubd_faces;
|
||||||
array<int> oldsubd_face_corners;
|
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_faces.steal_data(mesh->subd_faces);
|
||||||
oldsubd_face_corners.steal_data(mesh->subd_face_corners);
|
oldsubd_face_corners.steal_data(mesh->subd_face_corners);
|
||||||
|
|
||||||
/* compares curve_keys rather than strands in order to handle quick hair
|
mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
|
||||||
* 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);
|
|
||||||
|
|
||||||
/* ensure bvh rebuild (instead of refit) if has_voxel_attributes() changed */
|
if (view_layer.use_surfaces) {
|
||||||
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) {
|
|
||||||
/* Adaptive subdivision setup. Not for baking since that requires
|
/* Adaptive subdivision setup. Not for baking since that requires
|
||||||
* exact mapping to the Blender mesh. */
|
* exact mapping to the Blender mesh. */
|
||||||
if (scene->bake_manager->get_baking()) {
|
if (!scene->bake_manager->get_baking()) {
|
||||||
mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
|
mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For some reason, meshes do not need this... */
|
/* For some reason, meshes do not need this... */
|
||||||
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
|
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
|
||||||
|
|
||||||
BL::Mesh b_mesh = object_to_mesh(
|
BL::Mesh b_mesh = object_to_mesh(
|
||||||
b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type);
|
b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type);
|
||||||
|
|
||||||
if (b_mesh) {
|
if (b_mesh) {
|
||||||
/* Sync mesh itself. */
|
/* Sync mesh itself. */
|
||||||
if (view_layer.use_surfaces && !use_particle_hair) {
|
if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
|
||||||
if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
|
create_subd_mesh(
|
||||||
create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions);
|
scene, mesh, b_ob, b_mesh, mesh->used_shaders, dicing_rate, max_subdivisions);
|
||||||
else
|
else
|
||||||
create_mesh(scene, mesh, b_mesh, used_shaders, false);
|
create_mesh(scene, mesh, b_mesh, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mesh->geometry_flags = requested_geometry_flags;
|
|
||||||
|
|
||||||
/* mesh fluid motion mantaflow */
|
/* mesh fluid motion mantaflow */
|
||||||
if (!use_particle_hair) {
|
sync_mesh_fluid_motion(b_ob, scene, mesh);
|
||||||
sync_mesh_fluid_motion(b_ob, scene, mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tag update */
|
/* tag update */
|
||||||
bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) ||
|
bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) ||
|
||||||
(oldsubd_face_corners != mesh->subd_face_corners) ||
|
(oldsubd_face_corners != mesh->subd_face_corners);
|
||||||
(oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius) ||
|
|
||||||
(oldhas_voxel_attributes != mesh->has_voxel_attributes());
|
|
||||||
|
|
||||||
mesh->tag_update(scene, rebuild);
|
mesh->tag_update(scene, rebuild);
|
||||||
|
|
||||||
return mesh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph,
|
void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||||
BL::Object &b_ob,
|
BL::Object b_ob,
|
||||||
Object *object,
|
Mesh *mesh,
|
||||||
float motion_time)
|
int motion_step)
|
||||||
{
|
{
|
||||||
/* ensure we only sync instanced meshes once */
|
/* Skip if no vertices were exported. */
|
||||||
Mesh *mesh = object->mesh;
|
size_t numverts = mesh->verts.size();
|
||||||
|
if (numverts == 0) {
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip empty meshes */
|
/* Skip objects without deforming modifiers. this is not totally reliable,
|
||||||
const size_t numverts = mesh->verts.size();
|
* would need a more extensive check to see which objects are animated. */
|
||||||
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 */
|
|
||||||
BL::Mesh b_mesh(PointerRNA_NULL);
|
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)) {
|
if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
|
||||||
/* get derived mesh */
|
/* get derived mesh */
|
||||||
b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
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. */
|
/* TODO(sergey): Perform preliminary check for number of vertices. */
|
||||||
if (numverts) {
|
if (b_mesh) {
|
||||||
|
/* Export deformed coordinates. */
|
||||||
/* Find attributes. */
|
/* Find attributes. */
|
||||||
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||||
Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
|
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 */
|
/* No deformation on this frame, copy coordinates if other frames did have it. */
|
||||||
if (numkeys)
|
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||||
sync_particle_hair(mesh, b_mesh, b_ob, true, motion_step);
|
|
||||||
|
|
||||||
/* free derived mesh */
|
if (attr_mP) {
|
||||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
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
|
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));
|
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 */
|
||||||
|
|
||||||
Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||||
@@ -393,7 +192,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||||||
|
|
||||||
/* mesh deformation */
|
/* mesh deformation */
|
||||||
if (object->mesh)
|
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;
|
return object;
|
||||||
@@ -406,7 +205,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||||||
object_updated = true;
|
object_updated = true;
|
||||||
|
|
||||||
/* mesh sync */
|
/* 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 */
|
/* special case not tracked by object update flags */
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#include "render/camera.h"
|
#include "render/camera.h"
|
||||||
|
|
||||||
#include "blender/blender_object_cull.h"
|
#include "blender/blender_object_cull.h"
|
||||||
|
#include "blender/blender_util.h"
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include "blender/blender_device.h"
|
#include "blender/blender_device.h"
|
||||||
#include "blender/blender_sync.h"
|
#include "blender/blender_sync.h"
|
||||||
#include "blender/blender_session.h"
|
#include "blender/blender_session.h"
|
||||||
|
#include "blender/blender_util.h"
|
||||||
|
|
||||||
#include "render/denoising.h"
|
#include "render/denoising.h"
|
||||||
#include "render/merge.h"
|
#include "render/merge.h"
|
||||||
|
@@ -1112,341 +1112,6 @@ void BlenderSession::test_cancel()
|
|||||||
session->progress.set_cancel("Cancelled");
|
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)
|
void BlenderSession::update_resumable_tile_manager(int num_samples)
|
||||||
{
|
{
|
||||||
const int num_resumable_chunks = BlenderSession::num_resumable_chunks,
|
const int num_resumable_chunks = BlenderSession::num_resumable_chunks,
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
#include "RNA_access.h"
|
#include "RNA_access.h"
|
||||||
#include "RNA_blender_cpp.h"
|
#include "RNA_blender_cpp.h"
|
||||||
|
|
||||||
#include "blender/blender_util.h"
|
#include "blender/blender_id_map.h"
|
||||||
#include "blender/blender_viewport.h"
|
#include "blender/blender_viewport.h"
|
||||||
|
|
||||||
#include "render/scene.h"
|
#include "render/scene.h"
|
||||||
@@ -118,19 +118,13 @@ class BlenderSync {
|
|||||||
void **python_thread_state);
|
void **python_thread_state);
|
||||||
void sync_film(BL::SpaceView3D &b_v3d);
|
void sync_film(BL::SpaceView3D &b_v3d);
|
||||||
void sync_view();
|
void sync_view();
|
||||||
|
|
||||||
|
/* Shader */
|
||||||
void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
|
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_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
|
||||||
void sync_curve_settings();
|
|
||||||
|
|
||||||
void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
|
void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
|
||||||
Mesh *sync_mesh(BL::Depsgraph &b_depsgrpah,
|
|
||||||
BL::Object &b_ob,
|
/* Object */
|
||||||
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 *sync_object(BL::Depsgraph &b_depsgraph,
|
Object *sync_object(BL::Depsgraph &b_depsgraph,
|
||||||
BL::ViewLayer &b_view_layer,
|
BL::ViewLayer &b_view_layer,
|
||||||
BL::DepsgraphObjectInstance &b_instance,
|
BL::DepsgraphObjectInstance &b_instance,
|
||||||
@@ -139,6 +133,39 @@ class BlenderSync {
|
|||||||
bool show_lights,
|
bool show_lights,
|
||||||
BlenderObjectCulling &culling,
|
BlenderObjectCulling &culling,
|
||||||
bool *use_portal);
|
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,
|
void sync_light(BL::Object &b_parent,
|
||||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
||||||
BL::Object &b_ob,
|
BL::Object &b_ob,
|
||||||
@@ -147,14 +174,8 @@ class BlenderSync {
|
|||||||
Transform &tfm,
|
Transform &tfm,
|
||||||
bool *use_portal);
|
bool *use_portal);
|
||||||
void sync_background_light(BL::SpaceView3D &b_v3d, 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,
|
bool sync_dupli_particle(BL::Object &b_ob,
|
||||||
BL::DepsgraphObjectInstance &b_instance,
|
BL::DepsgraphObjectInstance &b_instance,
|
||||||
Object *object);
|
Object *object);
|
||||||
|
@@ -531,7 +531,7 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
|
|||||||
return use_deform_motion;
|
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;
|
BL::Object::modifiers_iterator b_mod;
|
||||||
|
|
||||||
@@ -539,8 +539,28 @@ static inline BL::FluidDomainSettings object_fluid_domain_find(BL::Object &b_ob)
|
|||||||
if (b_mod->is_a(&RNA_FluidModifier)) {
|
if (b_mod->is_a(&RNA_FluidModifier)) {
|
||||||
BL::FluidModifier b_mmd(*b_mod);
|
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 b_mmd.domain_settings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BL::FluidDomainSettings(PointerRNA_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
|
||||||
|
{
|
||||||
|
BL::Object::modifiers_iterator b_mod;
|
||||||
|
|
||||||
|
for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
|
||||||
|
if (b_mod->is_a(&RNA_FluidModifier)) {
|
||||||
|
BL::FluidModifier b_mmd(*b_mod);
|
||||||
|
|
||||||
|
if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
|
||||||
|
b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS) {
|
||||||
|
return b_mmd.domain_settings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,248 +593,20 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
|
|||||||
return Mesh::SUBDIVISION_NONE;
|
return Mesh::SUBDIVISION_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ID Map
|
static inline uint object_ray_visibility(BL::Object &b_ob)
|
||||||
*
|
{
|
||||||
* Utility class to keep in sync with blender data.
|
PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
|
||||||
* Used for objects, meshes, lights and shaders. */
|
uint flag = 0;
|
||||||
|
|
||||||
template<typename K, typename T> class id_map {
|
flag |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0;
|
||||||
public:
|
flag |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0;
|
||||||
id_map(vector<T *> *scene_data_)
|
flag |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0;
|
||||||
{
|
flag |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
|
||||||
scene_data = scene_data_;
|
flag |= get_boolean(cvisibility, "shadow") ? PATH_RAY_SHADOW : 0;
|
||||||
}
|
flag |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
|
||||||
|
|
||||||
T *find(const BL::ID &id)
|
return flag;
|
||||||
{
|
}
|
||||||
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 {
|
class EdgeMap {
|
||||||
public:
|
public:
|
||||||
|
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