diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index b3e58905996..4c18bc04851 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1078,16 +1078,17 @@ class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel): dof = cam.dof layout.active = dof.use_dof - split = layout.split() - - col = split.column() - col.prop(dof, "focus_object", text="Focus Object") - if dof.focus_object and dof.focus_object.type == 'ARMATURE': - col.prop_search(dof, "focus_subtarget", dof.focus_object.data, "bones", text="Focus Bone") - - sub = col.row() - sub.active = dof.focus_object is None - sub.prop(dof, "focus_distance", text="Distance") + col = layout.column() + if dof.focus_collection is None: + col.prop(dof, "focus_object", text="Focus on Object") + if dof.focus_object and dof.focus_object.type == 'ARMATURE': + col.prop_search(dof, "focus_subtarget", dof.focus_object.data, "bones", text="Focus on Bone") + if dof.focus_object is None: + sub = col.column() + sub.prop(dof, "focus_collection", text="Focus on Collection") + if dof.focus_object is None and dof.focus_collection is None: + sub = sub.column() + sub.prop(dof, "focus_distance", text="Focus Distance") class CYCLES_CAMERA_PT_dof_aperture(CyclesButtonsPanel, Panel): diff --git a/intern/cycles/blender/camera.cpp b/intern/cycles/blender/camera.cpp index 59a129ae567..3db4f6f980b 100644 --- a/intern/cycles/blender/camera.cpp +++ b/intern/cycles/blender/camera.cpp @@ -135,17 +135,49 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings &b_rende bcam->full_height = bcam->render_height; } +static void sum_obj_positions(float3 &pos, int &count, BL::Collection &coll) +{ + for (BL::Object obj : coll.objects) { + Transform dofmat = get_transform(obj.matrix_world()); + float3 curr = transform_get_column(&dofmat, 3); + pos.x += curr.x; + pos.y += curr.y; + pos.z += curr.z; + count += 1; + } + for (BL::Collection child : coll.children) { + sum_obj_positions(pos, count, child); + } +} + static float blender_camera_focal_distance(BL::RenderEngine &b_engine, BL::Object &b_ob, BL::Camera &b_camera, BlenderCamera *bcam) { BL::Object b_dof_object = b_camera.dof().focus_object(); + BL::Collection b_dof_collection = b_camera.dof().focus_collection(); - if (!b_dof_object) { + if (!b_dof_object && !b_dof_collection) { return b_camera.dof().focus_distance(); } + if (b_dof_collection) { + int count = 0; + float3 pos = {}; + sum_obj_positions(pos, count, b_dof_collection); + float den = static_cast(count); + pos.x /= den; + pos.y /= den; + pos.z /= den; + BL::Array b_ob_matrix; + b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix); + Transform obmat = transform_clear_scale(get_transform(b_ob_matrix)); + float3 view_dir = normalize(transform_get_column(&obmat, 2)); + float3 dof_dir = transform_get_column(&obmat, 3) - pos; + return fabsf(dot(view_dir, dof_dir)); + } + Transform dofmat = get_transform(b_dof_object.matrix_world()); string focus_subtarget = b_camera.dof().focus_subtarget(); diff --git a/scripts/startup/bl_ui/properties_data_camera.py b/scripts/startup/bl_ui/properties_data_camera.py index 77512370159..596b3496b79 100644 --- a/scripts/startup/bl_ui/properties_data_camera.py +++ b/scripts/startup/bl_ui/properties_data_camera.py @@ -251,12 +251,16 @@ class DATA_PT_camera_dof(CameraButtonsPanel, Panel): layout.active = dof.use_dof col = layout.column() - col.prop(dof, "focus_object", text="Focus on Object") - if dof.focus_object and dof.focus_object.type == 'ARMATURE': - col.prop_search(dof, "focus_subtarget", dof.focus_object.data, "bones", text="Focus on Bone") - sub = col.column() - sub.active = (dof.focus_object is None) - sub.prop(dof, "focus_distance", text="Focus Distance") + if dof.focus_collection is None: + col.prop(dof, "focus_object", text="Focus on Object") + if dof.focus_object and dof.focus_object.type == 'ARMATURE': + col.prop_search(dof, "focus_subtarget", dof.focus_object.data, "bones", text="Focus on Bone") + if dof.focus_object is None: + sub = col.column() + sub.prop(dof, "focus_collection", text="Focus on Collection") + if dof.focus_object is None and dof.focus_collection is None: + sub = sub.column() + sub.prop(dof, "focus_distance", text="Focus Distance") class DATA_PT_camera_dof_aperture(CameraButtonsPanel, Panel): diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 04f0c551577..a7081a69290 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -2895,7 +2895,7 @@ class VIEW3D_MT_object_context_menu(Menu): props.input_scale = 0.01 props.header_text = rpt_("Camera Lens Scale: %.3f") - if not obj.data.dof.focus_object: + if not obj.data.dof.focus_object and not obj.data.dof.focus_collection: if view and view.camera == obj and view.region_3d.view_perspective == 'CAMERA': props = layout.operator("ui.eyedropper_depth", text="DOF Distance (Pick)") else: diff --git a/source/blender/blenkernel/intern/camera.cc b/source/blender/blenkernel/intern/camera.cc index 877397f2bfd..18e4d156d06 100644 --- a/source/blender/blenkernel/intern/camera.cc +++ b/source/blender/blenkernel/intern/camera.cc @@ -15,6 +15,7 @@ #include "DNA_ID.h" #include "DNA_camera_types.h" +#include "DNA_collection_types.h" #include "DNA_defaults.h" #include "DNA_light_types.h" #include "DNA_object_types.h" @@ -101,6 +102,7 @@ static void camera_foreach_id(ID *id, LibraryForeachIDData *data) const int flag = BKE_lib_query_foreachid_process_flags_get(data); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, camera->dof.focus_object, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, camera->dof.focus_collection, IDWALK_CB_NOP); LISTBASE_FOREACH (CameraBGImage *, bgpic, &camera->bg_images) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, bgpic->ima, IDWALK_CB_USER); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, bgpic->clip, IDWALK_CB_USER); @@ -276,12 +278,50 @@ void *BKE_camera_add(Main *bmain, const char *name) return cam; } +static void sum_obj_positions(float pos[3], int *count, Collection *c) +{ + ListBase *gobject = &(c->gobject); + ListBase *children = &(c->children); + *count += BLI_listbase_count(gobject); + LISTBASE_FOREACH (LinkData *, current, gobject) { + Object *o = static_cast(current->data); + const blender::float3 &cpos = o->object_to_world().location(); + add_v3_v3v3(pos, pos, cpos); + printf("Name: %s, Pos: %f, %f, %f, Total: %f, %f, %f\n", + o->id.name, + cpos.x, + cpos.y, + cpos.z, + pos[0], + pos[1], + pos[2]); // DEBUG + } + LISTBASE_FOREACH (LinkData *, current, children) { + Collection *child = static_cast(current->data); + sum_obj_positions(pos, count, child); + } +} + float BKE_camera_object_dof_distance(const Object *ob) { const Camera *cam = (const Camera *)ob->data; if (ob->type != OB_CAMERA) { return 0.0f; } + if (cam->dof.focus_collection) { + float view_dir[3], dof_dir[3]; + normalize_v3_v3(view_dir, ob->object_to_world().ptr()[2]); + + float pos[3] = {0.0f, 0.0f, 0.0f}; + int count = 0; + sum_obj_positions(pos, &count, cam->dof.focus_collection); + float scale = 1.0f / static_cast(count); + mul_v3_fl(pos, scale); + printf("Nobjects: %d, AVG Pos: %f, %f, %f\n", count, pos[0], pos[1], pos[2]); // DEBUG + + sub_v3_v3v3(dof_dir, ob->object_to_world().location(), pos); + return fabsf(dot_v3v3(view_dir, dof_dir)); + } if (cam->dof.focus_object) { float view_dir[3], dof_dir[3]; normalize_v3_v3(view_dir, ob->object_to_world().ptr()[2]); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 38cefdff685..b497b7b5a77 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -1874,6 +1874,9 @@ void DepsgraphNodeBuilder::build_camera(Camera *camera) if (camera->dof.focus_object != nullptr) { build_object(-1, camera->dof.focus_object, DEG_ID_LINKED_INDIRECTLY, false); } + if (camera->dof.focus_collection != nullptr) { + build_collection(nullptr, camera->dof.focus_collection); + } } void DepsgraphNodeBuilder::build_light(Light *lamp) diff --git a/source/blender/editors/object/object_relations.cc b/source/blender/editors/object/object_relations.cc index eb7ae8a0e52..c74fe9040ed 100644 --- a/source/blender/editors/object/object_relations.cc +++ b/source/blender/editors/object/object_relations.cc @@ -1888,6 +1888,7 @@ static void single_obdata_users( nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS))); ID_NEW_REMAP(cam->dof.focus_object); + ID_NEW_REMAP(cam->dof.focus_collection); break; case OB_MESH: /* Needed to remap texcomesh below. */ diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h index 3d97a17cb88..1c55a79d536 100644 --- a/source/blender/makesdna/DNA_camera_types.h +++ b/source/blender/makesdna/DNA_camera_types.h @@ -51,6 +51,7 @@ typedef struct CameraBGImage { typedef struct CameraDOFSettings { /** Focal distance for depth of field. */ struct Object *focus_object; + struct Collection *focus_collection; char focus_subtarget[64]; float focus_distance; float aperture_fstop; diff --git a/source/blender/makesrna/intern/rna_camera.cc b/source/blender/makesrna/intern/rna_camera.cc index 90a1181d9b8..7d1436dfe37 100644 --- a/source/blender/makesrna/intern/rna_camera.cc +++ b/source/blender/makesrna/intern/rna_camera.cc @@ -522,6 +522,15 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna) prop, "Focus Object", "Use this object to define the depth of field focal point"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update"); + prop = RNA_def_property(srna, "focus_collection", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Collection"); + RNA_def_property_pointer_sdna(prop, nullptr, "focus_collection"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_ui_text( + prop, "Focus Collection", "Use this object to define the depth of field focal point"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update"); + prop = RNA_def_property(srna, "focus_subtarget", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, nullptr, "focus_subtarget"); RNA_def_property_ui_text(