Geometry Nodes: new Camera Info Node

This adds a new Camera Info node to Geometry Nodes. It provides information
about the passed in camera like its projection matrix and focus distance.

This can be used for camera culling which was must more complex before.
It also allows building other view-dependent effects.

Pull Request: https://projects.blender.org/blender/blender/pulls/135311
This commit is contained in:
Cartesian Caramel
2025-03-28 22:54:13 +01:00
committed by Jacques Lucke
parent 98c4d107ea
commit ade8576bf7
8 changed files with 127 additions and 4 deletions

View File

@@ -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")

View File

@@ -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)

View File

@@ -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");

View File

@@ -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");
}
}

View File

@@ -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);
};

View File

@@ -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

View File

@@ -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<decl::Matrix>("Projection Matrix").description("Camera projection matrix");
b.add_output<decl::Float>("Focal Length").description("Perspective camera focal length");
b.add_output<decl::Vector>("Sensor").description("Size of the camera sensor");
b.add_output<decl::Vector>("Shift").description("Camera shift");
b.add_output<decl::Float>("Clip Start").description("Camera near clipping distance");
b.add_output<decl::Float>("Clip End").description("Camera far clipping distance");
b.add_output<decl::Float>("Focus Distance")
.description("Distance to the focus point for depth of field");
b.add_output<decl::Bool>("Is Orthographic")
.description("Whether the camera is using orthographic projection");
b.add_output<decl::Float>("Orthographic Scale")
.description("Orthographic camera scale (similar to zoom)");
b.add_input<decl::Object>("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<Object *>("Camera");
if (!camera_obj || camera_obj->type != OB_CAMERA) {
params.set_default_remaining_outputs();
return;
}
Camera *camera = static_cast<Camera *>(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

View File

@@ -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");