Refactor: Cycles: Remove use of RNA C++ API: object.cpp

This one is a little less trivial than the other similar changes
recently, because it migrates depsgraph iteration from the RNA API to
the C++ depsgraph API, which is a bit more unruly. Previously we passed
around `BL::DepsgraphObjectInstance`, now we pass `::Object` and
`::DEGObjectIterData`.

Another thing to note is the duplication of `ED_mesh_split_faces` into
`mesh_split_edges_for_corner_normals`. I did that because we shouldn't
call the editors modules from Cycles, and because the splitting logic
is much more related to how Cycles decided to upload normals than any
Blender-internal logic.

Part of #130989
This commit is contained in:
Hans Goudey 2025-12-19 10:42:41 -05:00 • committed by Hans Goudey
parent 7abf0f32fa
commit 244b154bb6
15 changed files with 382 additions and 295 deletions

View file

@ -57,6 +57,7 @@ set(LIB
PRIVATE bf::blenlib
PRIVATE bf::dna
PRIVATE bf::imbuf
PRIVATE bf::geometry
PRIVATE bf::gpu
PRIVATE bf::intern::guardedalloc
PRIVATE bf::intern::clog

View file

@ -575,7 +575,7 @@ void BlenderSync::sync_particle_hair(
if (!b_ob_info.is_real_object_data()) {
return;
}
const ::Object &b_ob = *b_ob_info.real_object.ptr.data_as<::Object>();
const ::Object &b_ob = *b_ob_info.real_object;
/* obtain general settings */
if (b_ob.mode == OB_MODE_PARTICLE_EDIT || b_ob.mode == OB_MODE_EDIT) {
@ -1009,7 +1009,7 @@ void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, con
/* Convert Blender hair to Cycles curves. */
const blender::bke::CurvesGeometry &b_curves(
static_cast<const ::Curves *>(b_ob_info.object_data.ptr.data)->geometry.wrap());
blender::id_cast<const ::Curves *>(b_ob_info.object_data)->geometry.wrap());
if (motion) {
export_hair_curves_motion(hair, b_curves, motion_step);
}
@ -1037,13 +1037,13 @@ void BlenderSync::sync_hair(BObjectInfo &b_ob_info, Hair *hair)
new_hair.set_used_shaders(used_shaders);
if (view_layer.use_hair) {
if (b_ob_info.object_data.is_a(&RNA_Curves)) {
if (GS(b_ob_info.object_data->name) == ID_CV) {
/* Hair object. */
sync_hair(&new_hair, b_ob_info, false);
}
else {
/* Particle hair. */
::Mesh *b_mesh = object_to_mesh(b_ob_info).ptr.data_as<::Mesh>();
::Mesh *b_mesh = object_to_mesh(b_ob_info);
if (b_mesh) {
sync_particle_hair(&new_hair, *b_mesh, b_ob_info, false);
@ -1083,15 +1083,15 @@ void BlenderSync::sync_hair_motion(BObjectInfo &b_ob_info, Hair *hair, const int
}
/* Export deformed coordinates. */
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
if (b_ob_info.object_data.is_a(&RNA_Curves)) {
if (ccl::BKE_object_is_deform_modified(b_ob_info, *b_scene.ptr.data_as<::Scene>(), preview)) {
if (GS(b_ob_info.object_data->name) == ID_CV) {
/* Hair object. */
sync_hair(hair, b_ob_info, true, motion_step);
return;
}
/* Particle hair. */
::Mesh *b_mesh = object_to_mesh(b_ob_info).ptr.data_as<::Mesh>();
::Mesh *b_mesh = object_to_mesh(b_ob_info);
if (b_mesh) {
sync_particle_hair(hair, *b_mesh, b_ob_info, true, motion_step);
free_object_to_mesh(b_ob_info, *b_mesh);

View file

@ -22,22 +22,22 @@ CCL_NAMESPACE_BEGIN
static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
{
if (b_ob_info.object_data.is_a(&RNA_Light)) {
if (GS(b_ob_info.object_data->name) == ID_LA) {
return Geometry::LIGHT;
}
if (b_ob_info.object_data.is_a(&RNA_Curves) || use_particle_hair) {
if (GS(b_ob_info.object_data->name) == ID_CV || use_particle_hair) {
return Geometry::HAIR;
}
if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
if (GS(b_ob_info.object_data->name) == ID_PT) {
return Geometry::POINTCLOUD;
}
if (b_ob_info.object_data.is_a(&RNA_Volume) ||
if (GS(b_ob_info.object_data->name) == ID_VO ||
(b_ob_info.object_data ==
object_get_data(b_ob_info.real_object, b_ob_info.use_adaptive_subdivision) &&
object_fluid_gas_domain_find(*b_ob_info.real_object.ptr.data_as<::Object>())))
object_get_data(*b_ob_info.real_object, b_ob_info.use_adaptive_subdivision) &&
object_fluid_gas_domain_find(*b_ob_info.real_object)))
{
return Geometry::VOLUME;
}
@ -88,13 +88,13 @@ Geometry *BlenderSync::sync_geometry(BObjectInfo &b_ob_info,
/* Test if we can instance or if the object is modified. */
const Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair);
::ID *const b_key_id = (b_ob_info.is_real_object_data() &&
BKE_object_is_modified(b_ob_info.real_object)) ?
b_ob_info.real_object.ptr.data_as<::ID>() :
b_ob_info.object_data.ptr.data_as<::ID>();
BKE_object_is_modified(*b_ob_info.real_object)) ?
&b_ob_info.real_object->id :
b_ob_info.object_data;
const GeometryKey key(b_key_id, geom_type);
/* Find shader indices. */
array<Node *> used_shaders = find_used_shaders(*b_ob_info.iter_object.ptr.data_as<::Object>());
array<Node *> used_shaders = find_used_shaders(*b_ob_info.iter_object);
/* Ensure we only sync instanced geometry once. */
Geometry *geom = geometry_map.find(key);
@ -160,7 +160,7 @@ Geometry *BlenderSync::sync_geometry(BObjectInfo &b_ob_info,
geometry_synced.insert(geom);
geom->name = ustring(b_ob_info.object_data.name().c_str());
geom->name = ustring(BKE_id_name(*b_ob_info.object_data));
/* Store the shaders immediately for the object attribute code. */
geom->set_used_shaders(used_shaders);
@ -170,7 +170,7 @@ Geometry *BlenderSync::sync_geometry(BObjectInfo &b_ob_info,
return;
}
progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name());
progress.set_sync_status("Synchronizing object", BKE_id_name(b_ob_info.real_object->id));
if (geom_type == Geometry::LIGHT) {
Light *light = static_cast<Light *>(geom);
@ -258,16 +258,16 @@ void BlenderSync::sync_geometry_motion(BObjectInfo &b_ob_info,
return;
}
if (b_ob_info.object_data.is_a(&RNA_Curves) || use_particle_hair) {
if (GS(b_ob_info.object_data->name) == ID_CV || use_particle_hair) {
Hair *hair = static_cast<Hair *>(geom);
sync_hair_motion(b_ob_info, hair, motion_step);
}
else if (b_ob_info.object_data.is_a(&RNA_Volume) ||
object_fluid_gas_domain_find(*b_ob_info.real_object.ptr.data_as<::Object>()))
else if (GS(b_ob_info.object_data->name) == ID_VO ||
object_fluid_gas_domain_find(*b_ob_info.real_object))
{
/* No volume motion blur support yet. */
}
else if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
else if (GS(b_ob_info.object_data->name) == ID_PT) {
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
sync_pointcloud_motion(pointcloud, b_ob_info, motion_step);
}

View file

@ -220,7 +220,10 @@ struct ObjectKey {
void *ob;
bool use_particle_hair;
ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_)
ObjectKey(void *parent_,
const int id_[OBJECT_PERSISTENT_ID_SIZE],
void *ob_,
bool use_particle_hair_)
: parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_)
{
if (id_) {
@ -286,7 +289,7 @@ struct ParticleSystemKey {
void *ob;
int id[OBJECT_PERSISTENT_ID_SIZE];
ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_)
ParticleSystemKey(void *ob_, const int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_)
{
if (id_) {
memcpy(id, id_, sizeof(id));

View file

@ -15,7 +15,7 @@ CCL_NAMESPACE_BEGIN
void BlenderSync::sync_light(BObjectInfo &b_ob_info, Light *light)
{
::Light &b_light = *static_cast<::Light *>(b_ob_info.object_data.ptr.data);
::Light &b_light = *blender::id_cast<::Light *>(b_ob_info.object_data);
light->name = b_light.id.name + 2;

View file

@ -33,8 +33,43 @@
#include "BKE_customdata.hh"
#include "BKE_mesh.hh"
#include "GEO_mesh_split_edges.hh"
CCL_NAMESPACE_BEGIN
void mesh_split_edges_for_corner_normals(::Mesh &mesh)
{
using namespace blender;
const OffsetIndices polys = mesh.faces();
const Span<int> corner_edges = mesh.corner_edges();
const bke::AttributeAccessor attributes = mesh.attributes();
const VArray<bool> mesh_sharp_edges = *attributes.lookup_or_default<bool>(
"sharp_edge", bke::AttrDomain::Edge, false);
const VArraySpan<bool> sharp_faces = *attributes.lookup<bool>("sharp_face",
bke::AttrDomain::Face);
Array<bool> sharp_edges(mesh.edges_num);
mesh_sharp_edges.materialize(sharp_edges);
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int face_i : range) {
if (!sharp_faces.is_empty() && sharp_faces[face_i]) {
for (const int edge : corner_edges.slice(polys[face_i])) {
sharp_edges[edge] = true;
}
}
}
});
IndexMaskMemory memory;
const IndexMask split_mask = IndexMask::from_bools(sharp_edges, memory);
if (split_mask.is_empty()) {
return;
}
geometry::split_edges(mesh, split_mask, {});
}
static void attr_create_motion_from_velocity(Mesh *mesh,
const blender::Span<blender::float3> b_attr,
const float motion_scale)
@ -802,7 +837,7 @@ static void create_subd_mesh(Scene *scene,
const float dicing_rate,
const int max_subdivisions)
{
const ::Object *b_ob = b_ob_info.real_object.ptr.data_as<::Object>();
const ::Object *b_ob = b_ob_info.real_object;
const auto &subsurf_mod = *reinterpret_cast<const ::SubsurfModifierData *>(b_ob->modifiers.last);
@ -876,8 +911,9 @@ void BlenderSync::sync_mesh(BObjectInfo &b_ob_info, Mesh *mesh)
new_mesh.set_used_shaders(used_shaders);
if (view_layer.use_surfaces) {
object_subdivision_to_mesh(b_ob_info.real_object, new_mesh, preview, use_adaptive_subdivision);
const ::Mesh *b_mesh = object_to_mesh(b_ob_info).ptr.data_as<::Mesh>();
object_subdivision_to_mesh(
*b_ob_info.real_object, new_mesh, preview, use_adaptive_subdivision);
const ::Mesh *b_mesh = object_to_mesh(b_ob_info);
if (b_mesh) {
/* Motion blur attribute is relative to seconds, we need it relative to frames. */
@ -951,12 +987,12 @@ void BlenderSync::sync_mesh_motion(BObjectInfo &b_ob_info, Mesh *mesh, const int
/* Skip objects without deforming modifiers. this is not totally reliable,
* would need a more extensive check to see which objects are animated. */
const ::Mesh *b_mesh = nullptr;
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
if (ccl::BKE_object_is_deform_modified(b_ob_info, *b_scene.ptr.data_as<::Scene>(), preview)) {
/* get derived mesh */
b_mesh = object_to_mesh(b_ob_info).ptr.data_as<::Mesh>();
b_mesh = object_to_mesh(b_ob_info);
}
const std::string ob_name = b_ob_info.real_object.name();
const std::string ob_name = BKE_id_name(b_ob_info.real_object->id);
/* TODO(sergey): Perform preliminary check for number of vertices. */
if (b_mesh) {

View file

@ -23,6 +23,11 @@
#include "util/task.h"
#include "BKE_duplilist.hh"
#include "BKE_layer.hh"
#include "BKE_material.hh"
#include "BKE_object.hh"
#include "DEG_depsgraph_query.hh"
#include "RE_engine.h"
@ -30,21 +35,22 @@ CCL_NAMESPACE_BEGIN
/* Utilities */
bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
bool BlenderSync::BKE_object_is_modified(::Object &b_ob)
{
/* test if we can instance or if the object is modified */
if (b_ob.type() == BL::Object::type_META) {
if (b_ob.type == OB_MBALL) {
/* Multi-user and dupli meta-balls are fused, can't instance. */
return true;
}
if (ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
const int settings = preview ? eModifierMode_Realtime : eModifierMode_Render;
if ((::BKE_object_is_modified(b_scene.ptr.data_as<::Scene>(), &b_ob) & settings) != 0) {
/* modifiers */
return true;
}
/* object level material links */
for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
if (b_slot.link() == BL::MaterialSlot::link_OBJECT) {
for (const int i : blender::IndexRange(BKE_object_material_count_eval(&b_ob))) {
if (b_ob.matbits[i] != 0) {
return true;
}
}
@ -54,57 +60,55 @@ bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
bool BlenderSync::object_is_geometry(BObjectInfo &b_ob_info)
{
BL::ID b_ob_data = b_ob_info.object_data;
::ID *b_ob_data = b_ob_info.object_data;
if (!b_ob_data) {
return false;
}
const BL::Object::type_enum type = b_ob_info.iter_object.type();
const ObjectType type = ObjectType(b_ob_info.iter_object->type);
if (type == BL::Object::type_VOLUME || type == BL::Object::type_CURVES ||
type == BL::Object::type_POINTCLOUD || type == BL::Object::type_LIGHT)
{
if (type == OB_VOLUME || type == OB_CURVES || type == OB_POINTCLOUD || type == OB_LAMP) {
/* Will be exported as geometry. */
return true;
}
return b_ob_data.is_a(&RNA_Mesh);
return GS(b_ob_data->name) == ID_ME;
}
bool BlenderSync::object_can_have_geometry(BL::Object &b_ob)
bool BlenderSync::object_can_have_geometry(::Object &b_ob)
{
const BL::Object::type_enum type = b_ob.type();
const ObjectType type = ObjectType(b_ob.type);
switch (type) {
case BL::Object::type_MESH:
case BL::Object::type_CURVE:
case BL::Object::type_SURFACE:
case BL::Object::type_META:
case BL::Object::type_FONT:
case BL::Object::type_CURVES:
case BL::Object::type_POINTCLOUD:
case BL::Object::type_VOLUME:
case OB_MESH:
case OB_CURVES_LEGACY:
case OB_SURF:
case OB_MBALL:
case OB_FONT:
case OB_CURVES:
case OB_POINTCLOUD:
case OB_VOLUME:
return true;
default:
return false;
}
}
bool BlenderSync::object_is_light(BL::Object &b_ob)
bool BlenderSync::object_is_light(::Object &b_ob)
{
BL::ID b_ob_data = object_get_data(b_ob, true);
::ID *b_ob_data = object_get_data(b_ob, true);
return (b_ob_data && b_ob_data.is_a(&RNA_Light));
return (b_ob_data && GS(b_ob_data->name) == ID_LA);
}
bool BlenderSync::object_is_camera(BL::Object &b_ob)
bool BlenderSync::object_is_camera(::Object &b_ob)
{
BL::ID b_ob_data = object_get_data(b_ob, true);
::ID *b_ob_data = object_get_data(b_ob, true);
return (b_ob_data && b_ob_data.is_a(&RNA_Camera));
return (b_ob_data && GS(b_ob_data->name) == ID_CA);
}
void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
void BlenderSync::sync_object_motion_init(::Object &b_parent, ::Object &b_ob, Object *object)
{
/* Initialize motion blur for object, detecting if it's enabled and creating motion
* steps array if so. */
@ -121,9 +125,7 @@ void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob
const Scene::MotionType need_motion = scene->need_motion();
if (need_motion == Scene::MOTION_BLUR) {
motion_steps = object_motion_steps(*b_parent.ptr.data_as<::Object>(),
*b_ob.ptr.data_as<::Object>(),
Object::MAX_MOTION_STEPS);
motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
use_motion_blur = true;
}
@ -148,34 +150,32 @@ void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob
}
}
Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
BL::DepsgraphObjectInstance &b_instance,
Object *BlenderSync::sync_object(::ViewLayer &b_view_layer,
::Object &b_ob,
::DEGObjectIterData &b_deg_iter_data,
const float motion_time,
bool use_particle_hair,
bool show_lights,
BlenderObjectCulling &culling,
TaskPool *geom_task_pool)
{
const bool is_instance = b_instance.is_instance();
BL::Object b_ob = b_instance.object();
BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object();
BL::Object b_real_object = is_instance ? b_instance.instance_object() : b_ob;
const bool is_instance = b_deg_iter_data.dupli_object_current;
::Object *b_parent = is_instance ? b_deg_iter_data.dupli_parent : &b_ob;
::Object *b_real_object = is_instance ? b_deg_iter_data.dupli_object_current->ob : &b_ob;
const bool use_adaptive_subdiv = object_subdivision_type(
b_real_object, preview, use_adaptive_subdivision) !=
*b_real_object, preview, use_adaptive_subdivision) !=
Mesh::SUBDIVISION_NONE;
BObjectInfo b_ob_info{
b_ob, b_real_object, object_get_data(b_ob, use_adaptive_subdiv), use_adaptive_subdiv};
&b_ob, b_real_object, object_get_data(b_ob, use_adaptive_subdiv), use_adaptive_subdiv};
const bool motion = motion_time != 0.0f;
/*const*/ Transform tfm = get_transform(b_ob.matrix_world());
int *persistent_id = nullptr;
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array;
/*const*/ Transform tfm = get_transform(b_ob.object_to_world());
const int *persistent_id = nullptr;
if (is_instance) {
persistent_id_array = b_instance.persistent_id();
persistent_id = persistent_id_array.data;
persistent_id = b_deg_iter_data.dupli_object_current->persistent_id;
if (!motion && !b_ob_info.is_real_object_data()) {
/* Remember which object data the geometry is coming from, so that we can sync it when the
* object has changed. */
instance_geometries_by_object[b_ob_info.real_object.ptr.data].insert(b_ob_info.object_data);
instance_geometries_by_object[b_ob_info.real_object].insert(b_ob_info.object_data);
}
}
@ -195,12 +195,15 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
}
/* Visibility flags for both parent and child. */
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
const bool use_holdout = b_parent.holdout_get(PointerRNA_NULL, b_view_layer);
PointerRNA b_ob_rna_ptr = RNA_id_pointer_create(&b_ob.id);
PointerRNA cobject = RNA_pointer_get(&b_ob_rna_ptr, "cycles");
const Base *base_parent = BKE_view_layer_base_find(&b_view_layer, b_parent);
const bool use_holdout = ((base_parent->flag & BASE_HOLDOUT) != 0) ||
((b_parent->visibility_flag & OB_HOLDOUT) != 0);
uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY;
if (b_parent.ptr.data != b_ob.ptr.data) {
visibility &= object_ray_visibility(b_parent);
if (b_parent != &b_ob) {
visibility &= object_ray_visibility(*b_parent);
}
/* TODO: make holdout objects on excluded layer invisible for non-camera rays. */
@ -211,8 +214,7 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
#endif
/* Clear camera visibility for indirect only objects. */
const bool use_indirect_only = !use_holdout &&
b_parent.indirect_only_get(PointerRNA_NULL, b_view_layer);
const bool use_indirect_only = !use_holdout && ((base_parent->flag & BASE_INDIRECT_ONLY) != 0);
if (use_indirect_only) {
visibility &= ~PATH_RAY_CAMERA;
}
@ -254,10 +256,7 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
}
/* test if we need to sync */
bool object_updated = object_map.add_or_update(&object,
&b_ob.ptr.data_as<::Object>()->id,
&b_parent.ptr.data_as<::Object>()->id,
key) ||
bool object_updated = object_map.add_or_update(&object, &b_ob.id, &b_parent->id, key) ||
(tfm != object->get_tfm());
/* mesh sync */
@ -267,7 +266,7 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
/* special case not tracked by object update flags */
if (sync_object_attributes(b_instance, object)) {
if (sync_object_attributes(b_ob, b_deg_iter_data, object)) {
object_updated = true;
}
@ -276,15 +275,17 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
object->set_visibility(visibility);
object->set_is_shadow_catcher(b_ob.is_shadow_catcher() || b_parent.is_shadow_catcher());
object->set_is_shadow_catcher((b_ob.visibility_flag & OB_SHADOW_CATCHER) != 0 ||
(b_parent->visibility_flag & OB_SHADOW_CATCHER) != 0);
object->set_shadow_terminator_shading_offset(b_ob.shadow_terminator_shading_offset());
object->set_shadow_terminator_shading_offset(b_ob.shadow_terminator_shading_offset);
object->set_shadow_terminator_geometry_offset(b_ob.shadow_terminator_geometry_offset());
object->set_shadow_terminator_geometry_offset(b_ob.shadow_terminator_geometry_offset);
float ao_distance = get_float(cobject, "ao_distance");
if (ao_distance == 0.0f && b_parent.ptr.data != b_ob.ptr.data) {
PointerRNA cparent = RNA_pointer_get(&b_parent.ptr, "cycles");
if (ao_distance == 0.0f && b_parent != &b_ob) {
PointerRNA b_parent_rna_ptr = RNA_id_pointer_create(&b_parent->id);
PointerRNA cparent = RNA_pointer_get(&b_parent_rna_ptr, "cycles");
ao_distance = get_float(cparent, "ao_distance");
}
object->set_ao_distance(ao_distance);
@ -298,16 +299,16 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
object->set_is_bake_target(b_ob_info.real_object == b_bake_target);
/* sync the asset name for Cryptomatte */
BL::Object parent = b_ob.parent();
::Object *parent = b_ob.parent;
ustring parent_name;
if (parent) {
while (parent.parent()) {
parent = parent.parent();
while (parent->parent) {
parent = parent->parent;
}
parent_name = parent.name();
parent_name = BKE_id_name(parent->id);
}
else {
parent_name = b_ob.name();
parent_name = BKE_id_name(b_ob.id);
}
object->set_asset_name(parent_name);
@ -317,19 +318,21 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
const bool do_sync = object->is_modified() || object_updated ||
(object->get_geometry() && object->get_geometry()->is_modified());
if (do_sync) {
object->name = b_ob.name().c_str();
object->set_pass_id(b_ob.pass_index());
const BL::Array<float, 4> object_color = b_ob.color();
object->set_color(get_float3(object_color));
object->name = BKE_id_name(b_ob.id);
object->set_pass_id(b_ob.index);
const float *object_color = b_ob.color;
object->set_color(make_float3(object_color[0], object_color[1], object_color[2]));
object->set_alpha(object_color[3]);
object->set_tfm(tfm);
/* dupli texture coordinates and random_id */
if (is_instance) {
object->set_dupli_generated(0.5f * get_float3(b_instance.orco()) -
const float *orco = b_deg_iter_data.dupli_object_current->orco;
object->set_dupli_generated(0.5f * make_float3(orco[0], orco[1], orco[2]) -
make_float3(0.5f, 0.5f, 0.5f));
object->set_dupli_uv(get_float2(b_instance.uv()));
object->set_random_id(b_instance.random_id());
const float *uv = b_deg_iter_data.dupli_object_current->uv;
object->set_dupli_uv(make_float2(uv[0], uv[1]));
object->set_random_id(b_deg_iter_data.dupli_object_current->random_id);
}
else {
object->set_dupli_generated(zero_float3());
@ -338,23 +341,19 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
}
/* Light group and linking. */
string lightgroup = b_ob.lightgroup();
string lightgroup = b_ob.lightgroup ? b_ob.lightgroup->name : "";
if (lightgroup.empty()) {
lightgroup = b_parent.lightgroup();
lightgroup = b_parent->lightgroup ? b_parent->lightgroup->name : "";
}
object->set_lightgroup(ustring(lightgroup));
object->set_light_set_membership(BlenderLightLink::get_light_set_membership(
b_parent.ptr.data_as<::Object>(), *b_ob.ptr.data_as<::Object>()));
object->set_receiver_light_set(BlenderLightLink::get_receiver_light_set(
b_parent.ptr.data_as<::Object>(), *b_ob.ptr.data_as<::Object>()));
object->set_shadow_set_membership(BlenderLightLink::get_shadow_set_membership(
b_parent.ptr.data_as<::Object>(), *b_ob.ptr.data_as<::Object>()));
object->set_blocker_shadow_set(BlenderLightLink::get_blocker_shadow_set(
b_parent.ptr.data_as<::Object>(), *b_ob.ptr.data_as<::Object>()));
object->set_light_set_membership(BlenderLightLink::get_light_set_membership(b_parent, b_ob));
object->set_receiver_light_set(BlenderLightLink::get_receiver_light_set(b_parent, b_ob));
object->set_shadow_set_membership(BlenderLightLink::get_shadow_set_membership(b_parent, b_ob));
object->set_blocker_shadow_set(BlenderLightLink::get_blocker_shadow_set(b_parent, b_ob));
}
sync_object_motion_init(b_parent, b_ob, object);
sync_object_motion_init(*b_parent, b_ob, object);
if (do_sync || object->motion_is_modified()) {
object->tag_update(scene);
@ -362,7 +361,7 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
if (is_instance) {
/* Sync possible particle data. */
sync_dupli_particle(b_parent, b_instance, object);
sync_dupli_particle(*b_parent, b_deg_iter_data, b_ob, object);
}
return object;
@ -370,27 +369,29 @@ Object *BlenderSync::sync_object(BL::ViewLayer &b_view_layer,
extern "C" DupliObject *rna_hack_DepsgraphObjectInstance_dupli_object_get(PointerRNA *ptr);
static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance,
static float4 lookup_instance_property(::Object &ob,
::DEGObjectIterData &b_deg_iter_data,
const string &name,
bool use_instancer)
{
::Object *ob = (::Object *)b_instance.object().ptr.data;
::DupliObject *dupli = nullptr;
::Object *dupli_parent = nullptr;
/* If requesting instance data, check the parent particle system and object. */
if (use_instancer && b_instance.is_instance()) {
dupli = rna_hack_DepsgraphObjectInstance_dupli_object_get(&b_instance.ptr);
dupli_parent = (::Object *)b_instance.parent().ptr.data;
if (use_instancer && b_deg_iter_data.dupli_object_current) {
dupli = b_deg_iter_data.dupli_object_current;
dupli_parent = b_deg_iter_data.dupli_parent;
}
float4 value;
BKE_object_dupli_find_rgba_attribute(ob, dupli, dupli_parent, name.c_str(), &value.x);
BKE_object_dupli_find_rgba_attribute(&ob, dupli, dupli_parent, name.c_str(), &value.x);
return value;
}
bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object)
bool BlenderSync::sync_object_attributes(::Object &b_ob,
::DEGObjectIterData &b_deg_iter_data,
Object *object)
{
/* Find which attributes are needed. */
AttributeRequestSet requests = object->get_geometry()->needed_attributes();
@ -415,7 +416,7 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance
if (type == SHD_ATTRIBUTE_OBJECT || type == SHD_ATTRIBUTE_INSTANCER) {
const bool use_instancer = (type == SHD_ATTRIBUTE_INSTANCER);
float4 value = lookup_instance_property(b_instance, real_name, use_instancer);
float4 value = lookup_instance_property(b_ob, b_deg_iter_data, real_name, use_instancer);
/* Try finding the existing attribute value. */
ParamValue *param = nullptr;
@ -447,9 +448,9 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance
/* Object Loop */
void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
void BlenderSync::sync_objects(::Depsgraph &b_depsgraph,
::bScreen *b_screen,
BL::SpaceView3D &b_v3d,
::View3D *b_v3d,
const float motion_time)
{
/* Task pool for multithreaded geometry sync. */
@ -481,39 +482,50 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
/* object loop */
bool cancel = false;
const bool show_lights = BlenderViewportParameters(
b_screen, b_v3d.ptr.data_as<::View3D>(), use_developer_ui)
.use_scene_lights;
const bool show_lights =
BlenderViewportParameters(b_screen, b_v3d, use_developer_ui).use_scene_lights;
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
BL::Depsgraph::object_instances_iterator b_instance_iter;
::ViewLayer &b_view_layer = *DEG_get_evaluated_view_layer(&b_depsgraph);
for (b_depsgraph.object_instances.begin(b_instance_iter);
b_instance_iter != b_depsgraph.object_instances.end() && !cancel;
++b_instance_iter)
BKE_view_layer_synced_ensure(b_scene.ptr.data_as<::Scene>(), &b_view_layer);
::DEGObjectIterSettings deg_iter_settings{};
deg_iter_settings.depsgraph = &b_depsgraph;
deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS;
DEGObjectIterData deg_iter_data{};
deg_iter_data.settings = &deg_iter_settings;
deg_iter_data.graph = deg_iter_settings.depsgraph;
deg_iter_data.flag = deg_iter_settings.flags;
ITER_BEGIN (DEG_iterator_objects_begin,
DEG_iterator_objects_next,
DEG_iterator_objects_end,
&deg_iter_data,
::Object *,
b_ob)
{
BL::DepsgraphObjectInstance b_instance = *b_instance_iter;
BL::Object b_ob = b_instance.object();
/* Viewport visibility. */
const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d);
const bool show_in_viewport = !b_v3d || BKE_object_is_visible_in_viewport(b_v3d, b_ob);
if (show_in_viewport == false) {
continue;
}
/* Load per-object culling data. */
culling.init_object(scene, b_ob);
culling.init_object(scene, *b_ob);
const int ob_visibility = BKE_object_visibility(b_ob, deg_iter_data.eval_mode);
/* Ensure the object geom supporting the hair is processed before adding
* the hair processing task to the task pool, calling .to_mesh() on the
* same object in parallel does not work. */
const bool sync_hair = b_instance.show_particles() &&
object_has_particle_hair(b_ob.ptr.data_as<::Object>());
const bool sync_hair = (ob_visibility & OB_VISIBLE_PARTICLES) != 0 &&
object_has_particle_hair(b_ob);
/* Object itself. */
if (b_instance.show_self()) {
if ((ob_visibility & OB_VISIBLE_SELF) != 0) {
sync_object(b_view_layer,
b_instance,
*b_ob,
deg_iter_data,
motion_time,
false,
show_lights,
@ -523,12 +535,22 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
/* Particle hair as separate object. */
if (sync_hair) {
sync_object(
b_view_layer, b_instance, motion_time, true, show_lights, culling, &geom_task_pool);
sync_object(b_view_layer,
*b_ob,
deg_iter_data,
motion_time,
true,
show_lights,
culling,
&geom_task_pool);
}
cancel = progress.get_cancel();
if (cancel) {
break;
}
}
ITER_END;
geom_task_pool.wait_work();
@ -536,7 +558,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
if (!cancel && !motion) {
/* After object for world_use_portal. */
sync_background_light(b_screen, b_v3d.ptr.data_as<::View3D>());
sync_background_light(b_screen, b_v3d);
/* Handle removed data and modified pointers, as this may free memory, delete Nodes in the
* right order to ensure that dependent data is freed after their users. Objects should be
@ -552,11 +574,11 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
}
}
void BlenderSync::sync_motion(BL::RenderSettings &b_render,
BL::Depsgraph &b_depsgraph,
void BlenderSync::sync_motion(::RenderData &b_render,
::Depsgraph &b_depsgraph,
::bScreen *b_screen,
BL::SpaceView3D &b_v3d,
BL::RegionView3D &b_rv3d,
::View3D *b_v3d,
::RegionView3D *b_rv3d,
const int width,
const int height,
void **python_thread_state)
@ -566,8 +588,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
}
/* get camera object here to deal with camera switch */
::Object *b_cam = get_camera_object(b_v3d.ptr.data_as<::View3D>(),
b_rv3d.ptr.data_as<::RegionView3D>());
::Object *b_cam = get_camera_object(b_v3d, b_rv3d);
const int frame_center = b_scene.frame_current();
const float subframe_center = b_scene.frame_subframe();
@ -592,7 +613,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
RE_engine_frame_set(b_engine, frame, subframe);
python_thread_state_save(python_thread_state);
if (b_cam) {
sync_camera_motion(*b_render.ptr.data_as<::RenderData>(), b_cam, width, height, 0.0f);
sync_camera_motion(b_render, b_cam, width, height, 0.0f);
}
sync_objects(b_depsgraph, b_screen, b_v3d);
}
@ -638,7 +659,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
python_thread_state_save(python_thread_state);
/* Syncs camera motion if relative_time is one of the camera's motion times. */
sync_camera_motion(*b_render.ptr.data_as<::RenderData>(), b_cam, width, height, relative_time);
sync_camera_motion(b_render, b_cam, width, height, relative_time);
/* sync object */
sync_objects(b_depsgraph, b_screen, b_v3d, relative_time);

View file

@ -6,6 +6,8 @@
#include "scene/camera.h"
#include "BLI_bounds.hh"
#include "blender/object_cull.h"
#include "blender/util.h"
@ -39,13 +41,14 @@ BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene &b_scene)
}
}
void BlenderObjectCulling::init_object(Scene *scene, BL::Object &b_ob)
void BlenderObjectCulling::init_object(Scene *scene, ::Object &b_ob)
{
if (!use_scene_camera_cull_ && !use_scene_distance_cull_) {
return;
}
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
PointerRNA b_ob_rna_ptr = RNA_id_pointer_create(&b_ob.id);
PointerRNA cobject = RNA_pointer_get(&b_ob_rna_ptr, "cycles");
use_camera_cull_ = use_scene_camera_cull_ && get_boolean(cobject, "use_camera_cull");
use_distance_cull_ = use_scene_distance_cull_ && get_boolean(cobject, "use_distance_cull");
@ -56,7 +59,7 @@ void BlenderObjectCulling::init_object(Scene *scene, BL::Object &b_ob)
}
}
bool BlenderObjectCulling::test(Scene *scene, BL::Object &b_ob, Transform &tfm)
bool BlenderObjectCulling::test(Scene *scene, ::Object &b_ob, Transform &tfm)
{
if (!use_camera_cull_ && !use_distance_cull_) {
return false;
@ -64,9 +67,17 @@ bool BlenderObjectCulling::test(Scene *scene, BL::Object &b_ob, Transform &tfm)
/* Compute world space bounding box corners. */
float3 bb[8];
BL::Array<float, 24> boundbox = b_ob.bound_box();
std::array<blender::float3, 8> boundbox;
if (const std::optional<blender::Bounds<blender::float3>> bounds =
BKE_object_boundbox_eval_cached_get(&b_ob))
{
boundbox = blender::bounds::corners(*bounds);
}
else {
boundbox.fill(blender::float3(0));
}
for (int i = 0; i < 8; ++i) {
const float3 p = make_float3(boundbox[3 * i + 0], boundbox[3 * i + 1], boundbox[3 * i + 2]);
const float3 p = make_float3(boundbox[i].x, boundbox[i].y, boundbox[i].z);
bb[i] = transform_point(&tfm, p);
}

View file

@ -15,8 +15,8 @@ class BlenderObjectCulling {
public:
BlenderObjectCulling(Scene *scene, BL::Scene &b_scene);
void init_object(Scene *scene, BL::Object &b_ob);
bool test(Scene *scene, BL::Object &b_ob, Transform &tfm);
void init_object(Scene *scene, ::Object &b_ob);
bool test(Scene *scene, ::Object &b_ob, Transform &tfm);
private:
bool test_camera(Scene *scene, const float3 bb[8]);

View file

@ -9,16 +9,21 @@
#include "blender/sync.h"
#include "blender/util.h"
#include "DNA_particle_types.h"
#include "DEG_depsgraph_query.hh"
CCL_NAMESPACE_BEGIN
/* Utilities */
bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
BL::DepsgraphObjectInstance &b_instance,
bool BlenderSync::sync_dupli_particle(::Object &b_parent,
::DEGObjectIterData &b_deg_iter_data,
::Object &b_ob,
Object *object)
{
/* Test if this dupli was generated from a particle system. */
BL::ParticleSystem b_psys = b_instance.particle_system();
::ParticleSystem *b_psys = b_deg_iter_data.dupli_object_current->particle_system;
if (!b_psys) {
return false;
}
@ -31,22 +36,18 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
}
/* don't handle child particles yet */
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_instance.persistent_id();
const int *persistent_id = b_deg_iter_data.dupli_object_current->persistent_id;
if (persistent_id[0] >= b_psys.particles.length()) {
if (persistent_id[0] >= b_psys->totpart) {
return false;
}
/* find particle system */
const ParticleSystemKey key(b_ob, persistent_id);
const ParticleSystemKey key(&b_parent, persistent_id);
ParticleSystem *psys;
const bool first_use = !particle_system_map.is_used(key);
const bool need_update = particle_system_map.add_or_update(
&psys,
&b_ob.ptr.data_as<::Object>()->id,
&b_instance.object().ptr.data_as<::Object>()->id,
key);
const bool need_update = particle_system_map.add_or_update(&psys, &b_parent.id, &b_ob.id, key);
/* no update needed? */
if (!need_update && !object->get_geometry()->is_modified() &&
@ -62,17 +63,18 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
}
/* add particle */
BL::Particle b_pa = b_psys.particles[persistent_id[0]];
::ParticleData &b_pa = b_psys->particles[persistent_id[0]];
Particle pa;
pa.index = persistent_id[0];
pa.age = b_scene.frame_current_final() - b_pa.birth_time();
pa.lifetime = b_pa.lifetime();
pa.location = get_float3(b_pa.location());
pa.rotation = get_float4(b_pa.rotation());
pa.size = b_pa.size();
pa.velocity = get_float3(b_pa.velocity());
pa.angular_velocity = get_float3(b_pa.angular_velocity());
pa.age = b_scene.frame_current_final() - b_pa.time;
pa.lifetime = b_pa.lifetime;
pa.location = make_float3(b_pa.state.co[0], b_pa.state.co[1], b_pa.state.co[2]);
pa.rotation = make_float4(
b_pa.state.rot[0], b_pa.state.rot[1], b_pa.state.rot[2], b_pa.state.rot[3]);
pa.size = b_pa.size;
pa.velocity = make_float3(b_pa.state.vel[0], b_pa.state.vel[1], b_pa.state.vel[2]);
pa.angular_velocity = make_float3(b_pa.state.ave[0], b_pa.state.ave[1], b_pa.state.ave[2]);
psys->particles.push_back_slow(pa);

View file

@ -194,7 +194,7 @@ void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info
new_pointcloud.set_used_shaders(used_shaders);
/* TODO: add option to filter out points in the view layer. */
const ::PointCloud *b_pointcloud = b_ob_info.object_data.ptr.data_as<::PointCloud>();
const ::PointCloud *b_pointcloud = blender::id_cast<::PointCloud *>(b_ob_info.object_data);
/* Motion blur attribute is relative to seconds, we need it relative to frames. */
const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
const float motion_scale = (need_motion) ?
@ -231,9 +231,9 @@ void BlenderSync::sync_pointcloud_motion(PointCloud *pointcloud,
}
/* Export deformed coordinates. */
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
if (ccl::BKE_object_is_deform_modified(b_ob_info, *b_scene.ptr.data_as<::Scene>(), preview)) {
/* PointCloud object. */
const ::PointCloud *b_pointcloud = b_ob_info.object_data.ptr.data_as<::PointCloud>();
const ::PointCloud *b_pointcloud = blender::id_cast<::PointCloud *>(b_ob_info.object_data);
export_pointcloud_motion(pointcloud, *b_pointcloud, motion_step);
}
else {

View file

@ -129,8 +129,8 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph,
/* Object */
else if (b_id.is_a(&RNA_Object)) {
BL::Object b_ob(b_id);
const bool can_have_geometry = object_can_have_geometry(b_ob);
const bool is_light = !can_have_geometry && object_is_light(b_ob);
const bool can_have_geometry = object_can_have_geometry(*b_ob.ptr.data_as<::Object>());
const bool is_light = !can_have_geometry && object_is_light(*b_ob.ptr.data_as<::Object>());
if (b_ob.is_instancer() && b_update.is_updated_shading()) {
/* Needed for object color updates on instancer, among other things. */
@ -147,23 +147,24 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph,
object_map.set_recalc(b_ob);
}
const bool use_adaptive_subdiv = object_subdivision_type(
b_ob, preview, use_adaptive_subdivision) !=
const bool use_adaptive_subdiv = object_subdivision_type(*b_ob.ptr.data_as<::Object>(),
preview,
use_adaptive_subdivision) !=
Mesh::SUBDIVISION_NONE;
/* Need to recompute geometry if the geometry changed, or the transform changed
* and using adaptive subdivision. */
if (updated_geometry || (updated_transform && use_adaptive_subdiv)) {
BL::ID const key = BKE_object_is_modified(b_ob) ?
b_ob :
object_get_data(b_ob, use_adaptive_subdiv);
::ID *key = BKE_object_is_modified(*b_ob.ptr.data_as<::Object>()) ?
&b_ob.ptr.data_as<::Object>()->id :
object_get_data(*b_ob.ptr.data_as<::Object>(), use_adaptive_subdiv);
geometry_map.set_recalc(key);
/* Sync all contained geometry instances as well when the object changed.. */
const map<void *, set<BL::ID>>::const_iterator instance_geometries =
const map<void *, set<::ID *>>::const_iterator instance_geometries =
instance_geometries_by_object.find(b_ob.ptr.data);
if (instance_geometries != instance_geometries_by_object.end()) {
for (BL::ID const &geometry : instance_geometries->second) {
for (::ID *geometry : instance_geometries->second) {
geometry_map.set_recalc(geometry);
}
}
@ -190,7 +191,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph,
}
}
}
else if (object_is_camera(b_ob)) {
else if (object_is_camera(*b_ob.ptr.data_as<::Object>())) {
shader_map.set_recalc(b_ob);
}
@ -320,9 +321,16 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE ||
scene->camera->get_motion_position() == MOTION_POSITION_CENTER)
{
sync_objects(b_depsgraph, b_screen, b_v3d);
sync_objects(*b_depsgraph.ptr.data_as<::Depsgraph>(), b_screen, b_v3d.ptr.data_as<::View3D>());
}
sync_motion(b_render, b_depsgraph, b_screen, b_v3d, b_rv3d, width, height, python_thread_state);
sync_motion(*b_render.ptr.data_as<::RenderData>(),
*b_depsgraph.ptr.data_as<::Depsgraph>(),
b_screen,
b_v3d.ptr.data_as<::View3D>(),
b_rv3d.ptr.data_as<::RegionView3D>(),
width,
height,
python_thread_state);
geometry_synced.clear();

View file

@ -17,6 +17,8 @@
#include "util/map.h"
#include "util/set.h"
struct DEGObjectIterData;
CCL_NAMESPACE_BEGIN
class Background;
@ -108,15 +110,15 @@ class BlenderSync {
/* sync */
void sync_lights(::Depsgraph &b_depsgraph, bool update_all);
void sync_materials(::Depsgraph &b_depsgraph, bool update_all);
void sync_objects(BL::Depsgraph &b_depsgraph,
void sync_objects(::Depsgraph &b_depsgraph,
::bScreen *b_screen,
BL::SpaceView3D &b_v3d,
::View3D *b_v3d,
const float motion_time = 0.0f);
void sync_motion(BL::RenderSettings &b_render,
BL::Depsgraph &b_depsgraph,
void sync_motion(::RenderData &b_render,
::Depsgraph &b_depsgraph,
::bScreen *b_screen,
BL::SpaceView3D &b_v3d,
BL::RegionView3D &b_rv3d,
::View3D *b_v3d,
::RegionView3D *b_rv3d,
const int width,
const int height,
void **python_thread_state);
@ -136,20 +138,23 @@ class BlenderSync {
void resolve_view_layer_attributes(Shader *shader, ShaderGraph *graph, ::Depsgraph &b_depsgraph);
/* Object */
Object *sync_object(BL::ViewLayer &b_view_layer,
BL::DepsgraphObjectInstance &b_instance,
Object *sync_object(::ViewLayer &b_view_layer,
::Object &b_ob,
::DEGObjectIterData &b_deg_iter_data,
const float motion_time,
bool use_particle_hair,
bool show_lights,
BlenderObjectCulling &culling,
TaskPool *geom_task_pool);
void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
void sync_object_motion_init(::Object &b_parent, ::Object &b_ob, Object *object);
void sync_procedural(BL::Object &b_ob,
BL::MeshSequenceCacheModifier &b_mesh_cache,
bool has_subdivision);
bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
bool sync_object_attributes(::Object &b_ob,
::DEGObjectIterData &b_deg_iter_data,
Object *object);
/* Volume */
void sync_volume(BObjectInfo &b_ob_info, Volume *volume);
@ -199,8 +204,9 @@ class BlenderSync {
void sync_background_light(::bScreen *b_screen, ::View3D *b_v3d);
/* Particles */
bool sync_dupli_particle(BL::Object &b_ob,
BL::DepsgraphObjectInstance &b_instance,
bool sync_dupli_particle(::Object &b_parent,
::DEGObjectIterData &b_deg_iter_data,
::Object &b_ob,
Object *object);
/* Images. */
@ -208,11 +214,11 @@ class BlenderSync {
/* util */
void find_shader(const ::ID *id, array<Node *> &used_shaders, Shader *default_shader);
bool BKE_object_is_modified(BL::Object &b_ob);
bool BKE_object_is_modified(::Object &b_ob);
bool object_is_geometry(BObjectInfo &b_ob_info);
bool object_can_have_geometry(BL::Object &b_ob);
bool object_is_light(BL::Object &b_ob);
bool object_is_camera(BL::Object &b_ob);
bool object_can_have_geometry(::Object &b_ob);
bool object_is_light(::Object &b_ob);
bool object_is_camera(::Object &b_ob);
::Object *get_camera_object(::View3D *b_v3d, ::RegionView3D *b_rv3d);
::Object *get_dicing_camera_object(::View3D *b_v3d, ::RegionView3D *b_rv3d);
@ -234,7 +240,7 @@ class BlenderSync {
set<Geometry *> geometry_motion_synced;
set<Geometry *> geometry_motion_attribute_synced;
/** Remember which geometries come from which objects to be able to sync them after changes. */
map<void *, set<BL::ID>> instance_geometries_by_object;
map<void *, set<::ID *>> instance_geometries_by_object;
set<float> motion_times;
void *world_map;
bool world_recalc;

View file

@ -36,35 +36,32 @@
#include "BKE_mesh.h"
#include "BKE_mesh_types.hh"
#include "BKE_mesh_wrapper.hh"
#include "BKE_object.hh"
CCL_NAMESPACE_BEGIN
static inline BL::ID object_get_data(const BL::Object &b_ob, const bool use_adaptive_subdivision)
static inline ::ID *object_get_data(const ::Object &b_ob, const bool use_adaptive_subdivision)
{
::Object *object = reinterpret_cast<::Object *>(b_ob.ptr.data);
if (!use_adaptive_subdivision && object->type == OB_MESH) {
::Mesh *mesh = static_cast<::Mesh *>(object->data);
mesh = BKE_mesh_wrapper_ensure_subdivision(mesh);
return BL::ID(RNA_id_pointer_create(&mesh->id));
if (!use_adaptive_subdivision && b_ob.type == OB_MESH) {
return &BKE_mesh_wrapper_ensure_subdivision(static_cast<::Mesh *>(b_ob.data))->id;
}
return BL::ID(RNA_id_pointer_create(reinterpret_cast<ID *>(object->data)));
return reinterpret_cast<ID *>(b_ob.data);
}
struct BObjectInfo {
/* Object directly provided by the depsgraph iterator. This object is only valid during one
* iteration and must not be accessed afterwards. Transforms and visibility should be checked on
* this object. */
BL::Object iter_object;
::Object *iter_object;
/* This object remains alive even after the object iterator is done. It corresponds to one
* original object. It is the object that owns the object data below. */
BL::Object real_object;
::Object *real_object;
/* The object-data referenced by the iter object. This is still valid after the depsgraph
* iterator is done. It might have a different type compared to object_get_data(real_object). */
BL::ID object_data;
::ID *object_data;
/* Object will use adaptive subdivision. */
bool use_adaptive_subdivision;
@ -73,17 +70,15 @@ struct BObjectInfo {
* geometry instance that does not have a 1-to-1 relationship with an object. */
bool is_real_object_data() const
{
return object_get_data(const_cast<BL::Object &>(real_object), use_adaptive_subdivision) ==
object_data;
return object_get_data(*real_object, use_adaptive_subdivision) == object_data;
}
};
static inline BL::Mesh object_copy_mesh_data(const BObjectInfo &b_ob_info)
static inline ::Mesh *object_copy_mesh_data(const BObjectInfo &b_ob_info)
{
::Object *object = static_cast<::Object *>(b_ob_info.real_object.ptr.data);
::Mesh *mesh = BKE_mesh_new_from_object(
nullptr, object, false, false, !b_ob_info.use_adaptive_subdivision);
return BL::Mesh(RNA_id_pointer_create(&mesh->id));
nullptr, b_ob_info.real_object, false, false, !b_ob_info.use_adaptive_subdivision);
return mesh;
}
int blender_attribute_name_split_type(ustring name, string *r_real_name);
@ -91,23 +86,25 @@ int blender_attribute_name_split_type(ustring name, string *r_real_name);
void python_thread_state_save(void **python_thread_state);
void python_thread_state_restore(void **python_thread_state);
static bool mesh_use_corner_normals(const BObjectInfo &b_ob_info, BL::Mesh &mesh)
static bool mesh_use_corner_normals(const BObjectInfo &b_ob_info, ::Mesh *mesh)
{
return mesh && !b_ob_info.use_adaptive_subdivision &&
(static_cast<const ::Mesh *>(mesh.ptr.data)->normals_domain(true) ==
blender::bke::MeshNormalDomain::Corner);
(mesh->normals_domain(true) == blender::bke::MeshNormalDomain::Corner);
}
static inline BL::Mesh object_to_mesh(BObjectInfo &b_ob_info)
void mesh_split_edges_for_corner_normals(::Mesh &mesh);
static inline ::Mesh *object_to_mesh(BObjectInfo &b_ob_info)
{
BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) :
BL::Mesh(PointerRNA_NULL);
::Mesh *mesh = (GS(b_ob_info.object_data->name) == ID_ME) ?
blender::id_cast<::Mesh *>(b_ob_info.object_data) :
nullptr;
bool use_corner_normals = false;
if (b_ob_info.is_real_object_data()) {
if (mesh) {
if (mesh.is_editmode()) {
if (mesh->runtime->edit_mesh) {
/* Flush edit-mesh to mesh, including all data layers. */
mesh = object_copy_mesh_data(b_ob_info);
use_corner_normals = mesh_use_corner_normals(b_ob_info, mesh);
@ -130,11 +127,11 @@ static inline BL::Mesh object_to_mesh(BObjectInfo &b_ob_info)
if (mesh) {
if (use_corner_normals) {
mesh.split_faces();
mesh_split_edges_for_corner_normals(*mesh);
}
if (b_ob_info.use_adaptive_subdivision) {
mesh.calc_loop_triangles();
mesh->corner_tris();
}
}
@ -147,8 +144,8 @@ static inline void free_object_to_mesh(BObjectInfo &b_ob_info, ::Mesh &mesh)
return;
}
/* Free mesh if we didn't just use the existing one. */
BL::Object object = b_ob_info.real_object;
if (object_get_data(object, b_ob_info.use_adaptive_subdivision).ptr.data != &mesh) {
::Object *object = b_ob_info.real_object;
if (object_get_data(*object, b_ob_info.use_adaptive_subdivision) != &mesh.id) {
BKE_id_free(nullptr, &mesh.id);
}
}
@ -299,12 +296,7 @@ static inline void curvemapping_color_to_array(const ::CurveMapping &cumap,
}
}
static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview)
{
return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
}
static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
static inline bool BKE_object_is_deform_modified(BObjectInfo &self, ::Scene &scene, bool preview)
{
if (!self.is_real_object_data()) {
/* Comes from geometry nodes, can't use heuristic to guess if it's animated. */
@ -312,8 +304,8 @@ static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &s
}
/* Use heuristic to quickly check if object is potentially animated. */
return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
false;
const int settings = preview ? eModifierMode_Realtime : eModifierMode_Render;
return (::BKE_object_is_deform_modified(&scene, self.real_object) & settings) != 0;
}
static inline int render_resolution_x(const ::RenderData &b_render)
@ -648,17 +640,19 @@ static inline uint object_motion_steps(::Object &b_parent,
}
/* object uses deformation motion blur */
static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
static inline bool object_use_deform_motion(::Object &b_parent, ::Object &b_ob)
{
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
PointerRNA b_ob_rna_ptr = RNA_id_pointer_create(&b_ob.id);
PointerRNA cobject = RNA_pointer_get(&b_ob_rna_ptr, "cycles");
bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
/* If motion blur is enabled for the object we also check
* whether it's enabled for the parent object as well.
*
* This way we can control motion blur from the dupli-group
* duplicator much easier. */
if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
if (use_deform_motion && &b_parent != &b_ob) {
PointerRNA b_parent_rna_ptr = RNA_id_pointer_create(&b_parent.id);
PointerRNA parent_cobject = RNA_pointer_get(&b_parent_rna_ptr, "cycles");
use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
}
return use_deform_motion;
@ -708,24 +702,27 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
}
static BL::SubsurfModifier object_subdivision_modifier(BL::Object &b_ob, const bool preview)
static ::SubsurfModifierData *object_subdivision_modifier(::Object &b_ob, const bool preview)
{
if (!b_ob.modifiers.empty()) {
BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
const bool enabled = preview ? mod.show_viewport() : mod.show_render();
if (enabled && mod.type() == BL::Modifier::type_SUBSURF) {
BL::SubsurfModifier subsurf(mod);
if (subsurf.use_adaptive_subdivision()) {
return subsurf;
}
}
ModifierData *md = static_cast<ModifierData *>(b_ob.modifiers.last);
if (!md) {
return nullptr;
}
return PointerRNA_NULL;
if (md->type != eModifierType_Subsurf) {
return nullptr;
}
const ModifierMode enabled_mode = preview ? eModifierMode_Render : eModifierMode_Realtime;
if ((md->mode & enabled_mode) == 0) {
return nullptr;
}
SubsurfModifierData *subsurf = reinterpret_cast<SubsurfModifierData *>(md);
if ((subsurf->flags & eSubsurfModifierFlag_UseAdaptiveSubdivision) == 0) {
return nullptr;
}
return subsurf;
}
static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
static inline Mesh::SubdivisionType object_subdivision_type(::Object &b_ob,
const bool preview,
const bool use_adaptive_subdivision)
{
@ -733,10 +730,10 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
return Mesh::SUBDIVISION_NONE;
}
BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview);
::SubsurfModifierData *subsurf = object_subdivision_modifier(b_ob, preview);
if (subsurf) {
if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
if (subsurf->subdivType == SUBSURF_TYPE_CATMULL_CLARK) {
return Mesh::SUBDIVISION_CATMULL_CLARK;
}
return Mesh::SUBDIVISION_LINEAR;
@ -745,7 +742,7 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
return Mesh::SUBDIVISION_NONE;
}
static inline void object_subdivision_to_mesh(BL::Object &b_ob,
static inline void object_subdivision_to_mesh(::Object &b_ob,
Mesh &mesh,
const bool preview,
const bool use_adaptive_subdivision)
@ -755,61 +752,63 @@ static inline void object_subdivision_to_mesh(BL::Object &b_ob,
return;
}
BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview);
::SubsurfModifierData *subsurf = object_subdivision_modifier(b_ob, preview);
if (!subsurf) {
mesh.set_subdivision_type(Mesh::SUBDIVISION_NONE);
return;
}
if (subsurf.subdivision_type() != BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
if (subsurf->subdivType != SUBSURF_TYPE_CATMULL_CLARK) {
mesh.set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
return;
}
mesh.set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
switch (subsurf.boundary_smooth()) {
case BL::SubsurfModifier::boundary_smooth_PRESERVE_CORNERS:
switch (subsurf->boundary_smooth) {
case SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS:
mesh.set_subdivision_boundary_interpolation(Mesh::SUBDIVISION_BOUNDARY_EDGE_AND_CORNER);
break;
case BL::SubsurfModifier::boundary_smooth_ALL:
case SUBSURF_BOUNDARY_SMOOTH_ALL:
mesh.set_subdivision_boundary_interpolation(Mesh::SUBDIVISION_BOUNDARY_EDGE_ONLY);
break;
}
switch (subsurf.uv_smooth()) {
case BL::SubsurfModifier::uv_smooth_NONE:
switch (subsurf->uv_smooth) {
case SUBSURF_UV_SMOOTH_NONE:
mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_ALL);
break;
case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS:
case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS:
mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_ONLY);
break;
case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS_AND_JUNCTIONS:
case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS:
mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_PLUS1);
break;
case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_PLUS2);
break;
case BL::SubsurfModifier::uv_smooth_PRESERVE_BOUNDARIES:
case SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES:
mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_BOUNDARIES);
break;
case BL::SubsurfModifier::uv_smooth_SMOOTH_ALL:
case SUBSURF_UV_SMOOTH_ALL:
mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_NONE);
break;
}
}
static inline uint object_ray_visibility(BL::Object &b_ob)
static inline uint object_ray_visibility(::Object &b_ob)
{
uint flag = 0;
flag |= b_ob.visible_camera() ? PATH_RAY_CAMERA : PathRayFlag(0);
flag |= b_ob.visible_diffuse() ? PATH_RAY_DIFFUSE : PathRayFlag(0);
flag |= b_ob.visible_glossy() ? PATH_RAY_GLOSSY : PathRayFlag(0);
flag |= b_ob.visible_transmission() ? PATH_RAY_TRANSMIT : PathRayFlag(0);
flag |= b_ob.visible_shadow() ? PATH_RAY_SHADOW : PathRayFlag(0);
flag |= b_ob.visible_volume_scatter() ? PATH_RAY_VOLUME_SCATTER : PathRayFlag(0);
flag |= ((b_ob.visibility_flag & OB_HIDE_CAMERA) == 0) ? PATH_RAY_CAMERA : PathRayFlag(0);
flag |= ((b_ob.visibility_flag & OB_HIDE_DIFFUSE) == 0) ? PATH_RAY_DIFFUSE : PathRayFlag(0);
flag |= ((b_ob.visibility_flag & OB_HIDE_GLOSSY) == 0) ? PATH_RAY_GLOSSY : PathRayFlag(0);
flag |= ((b_ob.visibility_flag & OB_HIDE_TRANSMISSION) == 0) ? PATH_RAY_TRANSMIT :
PathRayFlag(0);
flag |= ((b_ob.visibility_flag & OB_HIDE_SHADOW) == 0) ? PATH_RAY_SHADOW : PathRayFlag(0);
flag |= ((b_ob.visibility_flag & OB_HIDE_VOLUME_SCATTER) == 0) ? PATH_RAY_VOLUME_SCATTER :
PathRayFlag(0);
return flag;
}
@ -836,7 +835,8 @@ static inline bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *s
* - Motion attribute expects non-zero time steps.
*
* Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
PointerRNA b_ob_rna_ptr = RNA_id_pointer_create(&b_ob_info.real_object->id);
PointerRNA cobject = RNA_pointer_get(&b_ob_rna_ptr, "cycles");
const bool use_motion = get_boolean(cobject, "use_motion_blur");
if (!use_motion) {
return false;

View file

@ -179,8 +179,7 @@ static void sync_smoke_volume(
if (!b_ob_info.is_real_object_data()) {
return;
}
::FluidDomainSettings *b_domain = object_fluid_gas_domain_find(
*b_ob_info.real_object.ptr.data_as<::Object>());
::FluidDomainSettings *b_domain = object_fluid_gas_domain_find(*b_ob_info.real_object);
if (!b_domain) {
return;
}
@ -222,7 +221,7 @@ static void sync_smoke_volume(
}
unique_ptr<ImageLoader> loader = make_unique<BlenderSmokeLoader>(
*b_ob_info.real_object.ptr.data_as<::Object>(), std, clipping);
*b_ob_info.real_object, std, clipping);
ImageParams params;
params.frame = frame;
@ -283,7 +282,7 @@ class BlenderVolumeLoader : public VDBImageLoader {
static void sync_volume_object(
::Main &b_data, ::Scene &b_scene, BObjectInfo &b_ob_info, Scene *scene, Volume *volume)
{
::Volume &b_volume = *static_cast<::Volume *>(b_ob_info.object_data.ptr.data);
::Volume &b_volume = *blender::id_cast<::Volume *>(b_ob_info.object_data);
BKE_volume_load(&b_volume, &b_data);
::VolumeRender &b_render = b_volume.render;
@ -374,7 +373,7 @@ void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
volume->clear(true);
if (view_layer.use_volumes) {
if (b_ob_info.object_data.is_a(&RNA_Volume)) {
if (GS(b_ob_info.object_data->name) == ID_VO) {
/* Volume object. Create only attributes, bounding mesh will then
* be automatically generated later. */
sync_volume_object(*b_data.ptr.data_as<::Main>(),