diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index a4f3fa5e6a3..e21bcceff53 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -328,6 +328,7 @@ class NODE_MT_geometry_node_GEO_INPUT_SCENE(Menu): if context.space_data.geometry_nodes_type == 'TOOL': node_add_menu.add_node_type(layout, "GeometryNodeTool3DCursor") node_add_menu.add_node_type(layout, "GeometryNodeInputActiveCamera") + node_add_menu.add_node_type(layout, "GeometryNodeCameraInfo") node_add_menu.add_node_type(layout, "GeometryNodeCollectionInfo") node_add_menu.add_node_type(layout, "GeometryNodeImageInfo") node_add_menu.add_node_type(layout, "GeometryNodeIsViewport") diff --git a/source/blender/blenlib/BLI_struct_equality_utils.hh b/source/blender/blenlib/BLI_struct_equality_utils.hh index 6cec721ea9f..88f90d09bb2 100644 --- a/source/blender/blenlib/BLI_struct_equality_utils.hh +++ b/source/blender/blenlib/BLI_struct_equality_utils.hh @@ -53,3 +53,11 @@ return a.m1 == b.m1 && a.m2 == b.m2 && a.m3 == b.m3 && a.m4 == b.m4 && a.m5 == b.m5; \ } \ BLI_STRUCT_DERIVED_UNEQUAL_OPERATOR(Type) + +#define BLI_STRUCT_EQUALITY_OPERATORS_6(Type, m1, m2, m3, m4, m5, m6) \ + friend bool operator==(const Type &a, const Type &b) \ + { \ + return a.m1 == b.m1 && a.m2 == b.m2 && a.m3 == b.m3 && a.m4 == b.m4 && a.m5 == b.m5 && \ + a.m6 == b.m6; \ + } \ + BLI_STRUCT_DERIVED_UNEQUAL_OPERATOR(Type) diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index fd72e91ca9c..1cab68c8e03 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -12451,6 +12451,7 @@ static void rna_def_nodes(BlenderRNA *brna) define("GeometryNode", "GeometryNodeBake", rna_def_geo_bake); define("GeometryNode", "GeometryNodeBlurAttribute"); define("GeometryNode", "GeometryNodeBoundBox"); + define("GeometryNode", "GeometryNodeCameraInfo"); define("GeometryNode", "GeometryNodeCaptureAttribute", rna_def_geo_capture_attribute); define("GeometryNode", "GeometryNodeCollectionInfo"); define("GeometryNode", "GeometryNodeConvexHull"); diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index db14b8e6eb6..bbbfaf9fb3b 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -152,6 +152,11 @@ static void add_object_relation( DEG_add_customdata_mask(ctx->node, &object, &dependency_data_mask); } } + if (object.type == OB_CAMERA) { + if (info.camera_parameters) { + DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_PARAMETERS, "Nodes Modifier"); + } + } } static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) @@ -218,7 +223,9 @@ static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphCont } if (eval_deps.needs_active_camera) { DEG_add_scene_camera_relation(ctx->node, ctx->scene, DEG_OB_COMP_TRANSFORM, "Nodes Modifier"); - /* Active camera is a scene parameter that can change, so we need a relation for that, too. */ + } + /* Active camera is a scene parameter that can change, so we need a relation for that, too. */ + if (eval_deps.needs_active_camera || eval_deps.needs_scene_render_params) { DEG_add_scene_relation(ctx->node, ctx->scene, DEG_SCENE_COMP_PARAMETERS, "Nodes Modifier"); } } diff --git a/source/blender/nodes/NOD_geometry_nodes_dependencies.hh b/source/blender/nodes/NOD_geometry_nodes_dependencies.hh index f5511497acd..4d6c90d2095 100644 --- a/source/blender/nodes/NOD_geometry_nodes_dependencies.hh +++ b/source/blender/nodes/NOD_geometry_nodes_dependencies.hh @@ -24,10 +24,11 @@ struct GeometryNodesEvalDependencies { struct ObjectDependencyInfo { bool transform = false; bool geometry = false; + bool camera_parameters = false; - BLI_STRUCT_EQUALITY_OPERATORS_2(ObjectDependencyInfo, transform, geometry); + BLI_STRUCT_EQUALITY_OPERATORS_3(ObjectDependencyInfo, transform, geometry, camera_parameters); }; - static constexpr ObjectDependencyInfo all_object_deps{true, true}; + static constexpr ObjectDependencyInfo all_object_deps{true, true, true}; /** * Maps `session_uid` to the corresponding data-block. @@ -41,6 +42,7 @@ struct GeometryNodesEvalDependencies { bool needs_own_transform = false; bool needs_active_camera = false; + bool needs_scene_render_params = false; bool time_dependent = false; /** @@ -67,11 +69,12 @@ struct GeometryNodesEvalDependencies { */ void merge(const GeometryNodesEvalDependencies &other); - BLI_STRUCT_EQUALITY_OPERATORS_5(GeometryNodesEvalDependencies, + BLI_STRUCT_EQUALITY_OPERATORS_6(GeometryNodesEvalDependencies, ids, objects_info, needs_own_transform, needs_active_camera, + needs_scene_render_params, time_dependent); }; diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 8d9fcd00e24..34ba9d4da15 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -31,6 +31,7 @@ set(SRC nodes/node_geo_blur_attribute.cc nodes/node_geo_boolean.cc nodes/node_geo_bounding_box.cc + nodes/node_geo_camera_info.cc nodes/node_geo_collection_info.cc nodes/node_geo_common.cc nodes/node_geo_convex_hull.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_camera_info.cc b/source/blender/nodes/geometry/nodes/node_geo_camera_info.cc new file mode 100644 index 00000000000..2f1440cf1c3 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_camera_info.cc @@ -0,0 +1,85 @@ +#include "BKE_camera.h" + +#include "DEG_depsgraph_query.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_camera_info_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.use_custom_socket_order(); + + b.add_output("Projection Matrix").description("Camera projection matrix"); + b.add_output("Focal Length").description("Perspective camera focal length"); + b.add_output("Sensor").description("Size of the camera sensor"); + b.add_output("Shift").description("Camera shift"); + b.add_output("Clip Start").description("Camera near clipping distance"); + b.add_output("Clip End").description("Camera far clipping distance"); + b.add_output("Focus Distance") + .description("Distance to the focus point for depth of field"); + b.add_output("Is Orthographic") + .description("Whether the camera is using orthographic projection"); + b.add_output("Orthographic Scale") + .description("Orthographic camera scale (similar to zoom)"); + + b.add_input("Camera").hide_label(); +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Scene *scene = DEG_get_evaluated_scene(params.depsgraph()); + if (!scene) { + params.set_default_remaining_outputs(); + return; + } + + const Object *camera_obj = params.get_input("Camera"); + + if (!camera_obj || camera_obj->type != OB_CAMERA) { + params.set_default_remaining_outputs(); + return; + } + + Camera *camera = static_cast(camera_obj->data); + if (!camera) { + params.set_default_remaining_outputs(); + return; + } + + CameraParams camera_params; + BKE_camera_params_init(&camera_params); + BKE_camera_params_from_object(&camera_params, camera_obj); + BKE_camera_params_compute_viewplane( + &camera_params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); + BKE_camera_params_compute_matrix(&camera_params); + + const float4x4 projection_matrix(camera_params.winmat); + float focus_distance = BKE_camera_object_dof_distance(camera_obj); + + params.set_output("Projection Matrix", projection_matrix); + params.set_output("Focal Length", camera_params.lens); + params.set_output("Sensor", float3{camera_params.sensor_x, camera_params.sensor_y, 0.0f}); + params.set_output("Shift", float3{camera_params.shiftx, camera_params.shifty, 0.0f}); + params.set_output("Clip Start", camera_params.clip_start); + params.set_output("Clip End", camera_params.clip_end); + params.set_output("Focus Distance", focus_distance); + params.set_output("Is Orthographic", camera_params.is_ortho); + params.set_output("Orthographic Scale", camera_params.ortho_scale); +} + +static void node_register() +{ + static blender::bke::bNodeType ntype; + + geo_node_type_base(&ntype, "GeometryNodeCameraInfo"); + ntype.ui_name = "Camera Info"; + ntype.ui_description = "Retrieve information from a camera object"; + ntype.nclass = NODE_CLASS_INPUT; + ntype.geometry_node_execute = node_geo_exec; + ntype.declare = node_declare; + blender::bke::node_register_type(ntype); +} +NOD_REGISTER_NODE(node_register) + +} // namespace blender::nodes::node_geo_camera_info_cc diff --git a/source/blender/nodes/intern/geometry_nodes_dependencies.cc b/source/blender/nodes/intern/geometry_nodes_dependencies.cc index de3d584dde8..00996235a8c 100644 --- a/source/blender/nodes/intern/geometry_nodes_dependencies.cc +++ b/source/blender/nodes/intern/geometry_nodes_dependencies.cc @@ -44,6 +44,7 @@ void GeometryNodesEvalDependencies::add_object(Object *object, object_deps); deps.geometry |= object_deps.geometry; deps.transform |= object_deps.transform; + deps.camera_parameters |= object_deps.camera_parameters; } void GeometryNodesEvalDependencies::merge(const GeometryNodesEvalDependencies &other) @@ -58,6 +59,7 @@ void GeometryNodesEvalDependencies::merge(const GeometryNodesEvalDependencies &o } this->needs_own_transform |= other.needs_own_transform; this->needs_active_camera |= other.needs_active_camera; + this->needs_scene_render_params |= other.needs_scene_render_params; this->time_dependent |= other.time_dependent; } @@ -165,6 +167,20 @@ static void add_own_transform_dependencies(const bNodeTree &tree, deps.needs_own_transform |= needs_own_transform; } +static bool needs_scene_render_params(const bNodeTree &ntree) +{ + for (const bNode *node : ntree.nodes_by_type("GeometryNodeCameraInfo")) { + if (node->is_muted()) { + continue; + } + const bNodeSocket &projection_matrix_socket = node->output_by_identifier("Projection Matrix"); + if (projection_matrix_socket.is_logically_linked()) { + return true; + } + } + return false; +} + static void gather_geometry_nodes_eval_dependencies( const bNodeTree &ntree, GeometryNodesEvalDependencies &deps, @@ -175,6 +191,7 @@ static void gather_geometry_nodes_eval_dependencies( add_eval_dependencies_from_socket(*socket, deps); } deps.needs_active_camera |= has_enabled_nodes_of_type(ntree, "GeometryNodeInputActiveCamera"); + deps.needs_scene_render_params |= needs_scene_render_params(ntree); deps.time_dependent |= has_enabled_nodes_of_type(ntree, "GeometryNodeSimulationInput") || has_enabled_nodes_of_type(ntree, "GeometryNodeInputSceneTime");