1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-10 13:00:37 +00:00

Cleanup and simplify camera override API

- Harmonise the camera override 2D and 3D APIs
- Switch to using Camera2D/3D nodes to provide override functionality. This makes for simpler code, gets rid of much of copy-pasted camera code and makes code that relies on current viewport camera such as VisibleOnScreenNotifiers and object picking work out of the box.
- Make camera override code only accesible within DEBUG_ENABLED builds
This commit is contained in:
rxlecky
2025-05-30 21:42:11 +02:00
parent 825ef2387f
commit 02e1919514
4 changed files with 241 additions and 328 deletions

View File

@@ -49,12 +49,14 @@
<return type="Camera2D" /> <return type="Camera2D" />
<description> <description>
Returns the currently active 2D camera. Returns [code]null[/code] if there are no active cameras. Returns the currently active 2D camera. Returns [code]null[/code] if there are no active cameras.
[b]Note:[/b] If called while the [i]Camera Override[/i] system is active in editor, this will return the internally managed override camera. It is therefore advised to avoid caching the return value, or to check that the cached value is still a valid instance and is the current camera before use. See [method @GlobalScope.is_instance_valid] and [method Camera2D.is_current].
</description> </description>
</method> </method>
<method name="get_camera_3d" qualifiers="const"> <method name="get_camera_3d" qualifiers="const">
<return type="Camera3D" /> <return type="Camera3D" />
<description> <description>
Returns the currently active 3D camera. Returns the currently active 3D camera. Returns [code]null[/code] if there are no active cameras.
[b]Note:[/b] If called while the [i]Camera Override[/i] system is active in editor, this will return the internally managed override camera. It is therefore advised to avoid caching the return value, or to check that the cached value is a valid instance and is the current camera before use. See [method @GlobalScope.is_instance_valid] and [member Camera3D.current].
</description> </description>
</method> </method>
<method name="get_canvas_cull_mask_bit" qualifiers="const"> <method name="get_canvas_cull_mask_bit" qualifiers="const">

View File

@@ -38,6 +38,7 @@
#include "core/object/script_language.h" #include "core/object/script_language.h"
#include "core/os/time.h" #include "core/os/time.h"
#include "core/templates/local_vector.h" #include "core/templates/local_vector.h"
#include "scene/2d/camera_2d.h"
#include "scene/gui/popup_menu.h" #include "scene/gui/popup_menu.h"
#include "scene/main/canvas_layer.h" #include "scene/main/canvas_layer.h"
#include "scene/main/scene_tree.h" #include "scene/main/scene_tree.h"
@@ -196,7 +197,7 @@ Error SceneDebugger::_msg_override_cameras(const Array &p_args) {
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA); ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
bool enable = p_args[0]; bool enable = p_args[0];
bool from_editor = p_args[1]; bool from_editor = p_args[1];
SceneTree::get_singleton()->get_root()->enable_canvas_transform_override(enable); SceneTree::get_singleton()->get_root()->enable_camera_2d_override(enable);
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
SceneTree::get_singleton()->get_root()->enable_camera_3d_override(enable); SceneTree::get_singleton()->get_root()->enable_camera_3d_override(enable);
#endif // _3D_DISABLED #endif // _3D_DISABLED
@@ -206,8 +207,9 @@ Error SceneDebugger::_msg_override_cameras(const Array &p_args) {
Error SceneDebugger::_msg_transform_camera_2d(const Array &p_args) { Error SceneDebugger::_msg_transform_camera_2d(const Array &p_args) {
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA); ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
ERR_FAIL_COND_V(!SceneTree::get_singleton()->get_root()->is_camera_2d_override_enabled(), ERR_BUG);
Transform2D transform = p_args[0]; Transform2D transform = p_args[0];
SceneTree::get_singleton()->get_root()->set_canvas_transform_override(transform); SceneTree::get_singleton()->get_root()->get_override_camera_2d()->set_transform(transform);
RuntimeNodeSelect::get_singleton()->_queue_selection_update(); RuntimeNodeSelect::get_singleton()->_queue_selection_update();
return OK; return OK;
} }
@@ -215,17 +217,20 @@ Error SceneDebugger::_msg_transform_camera_2d(const Array &p_args) {
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
Error SceneDebugger::_msg_transform_camera_3d(const Array &p_args) { Error SceneDebugger::_msg_transform_camera_3d(const Array &p_args) {
ERR_FAIL_COND_V(p_args.size() < 5, ERR_INVALID_DATA); ERR_FAIL_COND_V(p_args.size() < 5, ERR_INVALID_DATA);
ERR_FAIL_COND_V(!SceneTree::get_singleton()->get_root()->is_camera_3d_override_enabled(), ERR_BUG);
Transform3D transform = p_args[0]; Transform3D transform = p_args[0];
bool is_perspective = p_args[1]; bool is_perspective = p_args[1];
float size_or_fov = p_args[2]; float size_or_fov = p_args[2];
float depth_near = p_args[3]; float depth_near = p_args[3];
float depth_far = p_args[4]; float depth_far = p_args[4];
Camera3D *override_camera = SceneTree::get_singleton()->get_root()->get_override_camera_3d();
if (is_perspective) { if (is_perspective) {
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(size_or_fov, depth_near, depth_far); override_camera->set_perspective(size_or_fov, depth_near, depth_far);
} else { } else {
SceneTree::get_singleton()->get_root()->set_camera_3d_override_orthogonal(size_or_fov, depth_near, depth_far); override_camera->set_orthogonal(size_or_fov, depth_near, depth_far);
} }
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(transform); override_camera->set_transform(transform);
RuntimeNodeSelect::get_singleton()->_queue_selection_update(); RuntimeNodeSelect::get_singleton()->_queue_selection_update();
return OK; return OK;
} }
@@ -1598,24 +1603,25 @@ void RuntimeNodeSelect::_select_set_mode(SelectMode p_mode) {
void RuntimeNodeSelect::_set_camera_override_enabled(bool p_enabled) { void RuntimeNodeSelect::_set_camera_override_enabled(bool p_enabled) {
camera_override = p_enabled; camera_override = p_enabled;
if (p_enabled) { Window *root = SceneTree::get_singleton()->get_root();
_update_view_2d();
}
#ifndef _3D_DISABLED
if (camera_first_override) { if (camera_first_override) {
_reset_camera_2d(); _reset_camera_2d();
#ifndef _3D_DISABLED
_reset_camera_3d(); _reset_camera_3d();
#endif // _3D_DISABLED
camera_first_override = false; camera_first_override = false;
} else if (p_enabled) { } else if (p_enabled) {
_update_view_2d(); _update_view_2d();
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform()); #ifndef _3D_DISABLED
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar); ERR_FAIL_COND(!root->is_camera_3d_override_enabled());
} Camera3D *override_camera = root->get_override_camera_3d();
override_camera->set_transform(_get_cursor_transform());
override_camera->set_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar);
#endif // _3D_DISABLED #endif // _3D_DISABLED
} }
}
void RuntimeNodeSelect::_root_window_input(const Ref<InputEvent> &p_event) { void RuntimeNodeSelect::_root_window_input(const Ref<InputEvent> &p_event) {
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
@@ -1756,13 +1762,16 @@ void RuntimeNodeSelect::_process_frame() {
} }
if (direction != Vector3()) { if (direction != Vector3()) {
Window *root = SceneTree::get_singleton()->get_root();
ERR_FAIL_COND(!root->is_camera_3d_override_enabled());
// Calculate the process time manually, as the time scale is frozen. // Calculate the process time manually, as the time scale is frozen.
const double process_time = (1.0 / Engine::get_singleton()->get_frames_per_second()) * Engine::get_singleton()->get_unfrozen_time_scale(); const double process_time = (1.0 / Engine::get_singleton()->get_frames_per_second()) * Engine::get_singleton()->get_unfrozen_time_scale();
const Vector3 motion = direction * speed * process_time; const Vector3 motion = direction * speed * process_time;
cursor.pos += motion; cursor.pos += motion;
cursor.eye_pos += motion; cursor.eye_pos += motion;
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform()); root->get_override_camera_3d()->set_transform(_get_cursor_transform());
} }
} }
#endif // _3D_DISABLED #endif // _3D_DISABLED
@@ -2091,8 +2100,6 @@ void RuntimeNodeSelect::_queue_selection_update() {
} }
void RuntimeNodeSelect::_update_selection() { void RuntimeNodeSelect::_update_selection() {
Window *root = SceneTree::get_singleton()->get_root();
RS::get_singleton()->canvas_item_clear(sbox_2d_ci); RS::get_singleton()->canvas_item_clear(sbox_2d_ci);
RS::get_singleton()->canvas_item_set_visible(sbox_2d_ci, selection_visible); RS::get_singleton()->canvas_item_set_visible(sbox_2d_ci, selection_visible);
@@ -2109,13 +2116,7 @@ void RuntimeNodeSelect::_update_selection() {
continue; continue;
} }
Transform2D xform; Transform2D xform = ci->get_global_transform_with_canvas();
// Cameras (overridden or not) don't affect `CanvasLayer`s.
if (root->is_canvas_transform_override_enabled() && !(ci->get_canvas_layer_node() && !ci->get_canvas_layer_node()->is_following_viewport())) {
xform = root->get_canvas_transform_override() * ci->get_global_transform();
} else {
xform = ci->get_global_transform_with_canvas();
}
// Fallback. // Fallback.
Rect2 rect = Rect2(Vector2(), Vector2(10, 10)); Rect2 rect = Rect2(Vector2(), Vector2(10, 10));
@@ -2247,27 +2248,8 @@ void RuntimeNodeSelect::_update_selection_drag(const Point2 &p_end_pos) {
return; return;
} }
Window *root = SceneTree::get_singleton()->get_root(); Rect2 selection_drawing = selection_drag_area.abs();
Rect2 selection_drawing; int thickness = 1;
int thickness;
if (root->is_canvas_transform_override_enabled()) {
Transform2D xform = root->get_canvas_transform_override();
RS::get_singleton()->canvas_item_set_transform(sel_drag_ci, xform);
RS::get_singleton()->canvas_item_reset_physics_interpolation(sel_drag_ci);
selection_drawing.position = xform.affine_inverse().xform(selection_drag_area.position);
selection_drawing.size = xform.affine_inverse().xform(p_end_pos);
thickness = MAX(1, Math::ceil(1 / view_2d_zoom));
} else {
RS::get_singleton()->canvas_item_set_transform(sel_drag_ci, Transform2D());
RS::get_singleton()->canvas_item_reset_physics_interpolation(sel_drag_ci);
selection_drawing.position = selection_drag_area.position;
selection_drawing.size = p_end_pos;
thickness = 1;
}
selection_drawing.size -= selection_drawing.position;
selection_drawing = selection_drawing.abs();
const Vector2 endpoints[4] = { const Vector2 endpoints[4] = {
selection_drawing.position, selection_drawing.position,
@@ -2352,9 +2334,10 @@ void RuntimeNodeSelect::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_n
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
Point2 pos; Point2 pos;
// Cameras (overridden or not) don't affect `CanvasLayer`s.
// Cameras don't affect `CanvasLayer`s.
if (!ci->get_canvas_layer_node() || ci->get_canvas_layer_node()->is_following_viewport()) { if (!ci->get_canvas_layer_node() || ci->get_canvas_layer_node()->is_following_viewport()) {
pos = (root->is_canvas_transform_override_enabled() ? root->get_canvas_transform_override() : root->get_canvas_transform()).affine_inverse().xform(p_pos); pos = root->get_canvas_transform().affine_inverse().xform(p_pos);
} else { } else {
pos = p_pos; pos = p_pos;
} }
@@ -2414,9 +2397,9 @@ void RuntimeNodeSelect::_find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
Rect2 rect; Rect2 rect;
// Cameras (overridden or not) don't affect `CanvasLayer`s. // Cameras don't affect `CanvasLayer`s.
if (!ci->get_canvas_layer_node() || ci->get_canvas_layer_node()->is_following_viewport()) { if (!ci->get_canvas_layer_node() || ci->get_canvas_layer_node()->is_following_viewport()) {
rect = (root->is_canvas_transform_override_enabled() ? root->get_canvas_transform_override() : root->get_canvas_transform()).affine_inverse().xform(p_rect); rect = root->get_canvas_transform().affine_inverse().xform(p_rect);
} else { } else {
rect = p_rect; rect = p_rect;
} }
@@ -2475,18 +2458,30 @@ void RuntimeNodeSelect::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Re
} }
void RuntimeNodeSelect::_reset_camera_2d() { void RuntimeNodeSelect::_reset_camera_2d() {
view_2d_offset = -SceneTree::get_singleton()->get_root()->get_canvas_transform().get_origin(); Window *root = SceneTree::get_singleton()->get_root();
Camera2D *game_camera = root->is_camera_2d_override_enabled() ? root->get_overridden_camera_2d() : root->get_camera_2d();
if (game_camera) {
// Ideally we should be using Camera2D::get_camera_transform() but it's not so this hack will have to do for now.
view_2d_offset = game_camera->get_camera_screen_center() - (0.5 * root->get_visible_rect().size);
} else {
view_2d_offset = Vector2();
}
view_2d_zoom = 1; view_2d_zoom = 1;
if (root->is_camera_2d_override_enabled()) {
_update_view_2d(); _update_view_2d();
} }
}
void RuntimeNodeSelect::_update_view_2d() { void RuntimeNodeSelect::_update_view_2d() {
Transform2D transform = Transform2D(); Window *root = SceneTree::get_singleton()->get_root();
transform.scale_basis(Size2(view_2d_zoom, view_2d_zoom)); ERR_FAIL_COND(!root->is_camera_2d_override_enabled());
transform.columns[2] = -view_2d_offset * view_2d_zoom;
SceneTree::get_singleton()->get_root()->set_canvas_transform_override(transform); Camera2D *override_camera = root->get_override_camera_2d();
override_camera->set_anchor_mode(Camera2D::ANCHOR_MODE_FIXED_TOP_LEFT);
override_camera->set_zoom(Vector2(view_2d_zoom, view_2d_zoom));
override_camera->set_position(view_2d_offset);
_queue_selection_update(); _queue_selection_update();
} }
@@ -2496,11 +2491,6 @@ void RuntimeNodeSelect::_find_3d_items_at_pos(const Point2 &p_pos, Vector<Select
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
Vector3 ray, pos, to; Vector3 ray, pos, to;
if (root->is_camera_3d_override_enabled()) {
ray = root->camera_3d_override_project_ray_normal(p_pos);
pos = root->camera_3d_override_project_ray_origin(p_pos);
to = pos + ray * root->get_camera_3d_override_properties()["z_far"];
} else {
Camera3D *camera = root->get_camera_3d(); Camera3D *camera = root->get_camera_3d();
if (!camera) { if (!camera) {
return; return;
@@ -2509,7 +2499,6 @@ void RuntimeNodeSelect::_find_3d_items_at_pos(const Point2 &p_pos, Vector<Select
ray = camera->project_ray_normal(p_pos); ray = camera->project_ray_normal(p_pos);
pos = camera->project_ray_origin(p_pos); pos = camera->project_ray_origin(p_pos);
to = pos + ray * camera->get_far(); to = pos + ray * camera->get_far();
}
#ifndef PHYSICS_3D_DISABLED #ifndef PHYSICS_3D_DISABLED
// Start with physical objects. // Start with physical objects.
@@ -2585,30 +2574,12 @@ void RuntimeNodeSelect::_find_3d_items_at_rect(const Rect2 &p_rect, Vector<Selec
return; return;
} }
bool cam_override = root->is_camera_3d_override_enabled(); Vector3 cam_pos = camera->get_global_position();
Vector3 cam_pos; Vector3 dist_pos = camera->project_ray_origin(p_rect.position + p_rect.size / 2);
Vector3 dist_pos;
if (cam_override) {
cam_pos = root->get_camera_3d_override_transform().origin;
dist_pos = root->camera_3d_override_project_ray_origin(p_rect.position + p_rect.size / 2);
} else {
cam_pos = camera->get_global_position();
dist_pos = camera->project_ray_origin(p_rect.position + p_rect.size / 2);
}
real_t znear, zfar = 0; real_t znear = camera->get_near();
real_t zofs = 5.0; real_t zfar = camera->get_far();
if (cam_override) { real_t zofs = MAX(0.0, 5.0 - znear);
HashMap<StringName, real_t> override_props = root->get_camera_3d_override_properties();
znear = override_props["z_near"];
zfar = override_props["z_far"];
zofs -= znear;
} else {
znear = camera->get_near();
zfar = camera->get_far();
zofs -= znear;
}
zofs = MAX(0.0, zofs);
const Point2 pos_end = p_rect.position + p_rect.size; const Point2 pos_end = p_rect.position + p_rect.size;
Vector3 box[4] = { Vector3 box[4] = {
@@ -2637,13 +2608,9 @@ void RuntimeNodeSelect::_find_3d_items_at_rect(const Rect2 &p_rect, Vector<Selec
frustum.push_back(Plane(a, b, cam_pos)); frustum.push_back(Plane(a, b, cam_pos));
} }
Plane near_plane;
// Get the camera normal. // Get the camera normal.
if (cam_override) { Plane near_plane = Plane(camera->get_global_transform().basis.get_column(2), cam_pos);
near_plane = Plane(root->get_camera_3d_override_transform().basis.get_column(2), cam_pos);
} else {
near_plane = Plane(camera->get_global_transform().basis.get_column(2), cam_pos);
}
near_plane.d -= znear; near_plane.d -= znear;
frustum.push_back(near_plane); frustum.push_back(near_plane);
@@ -2728,27 +2695,10 @@ Vector3 RuntimeNodeSelect::_get_screen_to_space(const Vector3 &p_vector3) {
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
Camera3D *camera = root->get_camera_3d(); Camera3D *camera = root->get_camera_3d();
Transform3D camera_transform = camera->get_camera_transform();
Size2 size = root->get_size(); Size2 size = root->get_size();
real_t znear = 0; real_t znear = camera->get_near();
Projection cm = Projection::create_perspective(camera->get_fov(), size.aspect(), znear + p_vector3.z, camera->get_far());
Projection cm;
Transform3D camera_transform;
if (root->is_camera_3d_override_enabled()) {
HashMap<StringName, real_t> override_props = root->get_camera_3d_override_properties();
znear = override_props["z_near"];
cm.set_perspective(override_props["fov"], size.aspect(), znear + p_vector3.z, override_props["z_far"]);
camera_transform.translate_local(cursor.pos);
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
camera_transform.translate_local(0, 0, cursor.distance);
} else {
znear = camera->get_near();
cm.set_perspective(camera->get_fov(), size.aspect(), znear + p_vector3.z, camera->get_far());
camera_transform = camera->get_camera_transform();
}
Vector2 screen_he = cm.get_viewport_half_extents(); Vector2 screen_he = cm.get_viewport_half_extents();
return camera_transform.xform(Vector3(((p_vector3.x / size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (p_vector3.y / size.height)) * 2.0 - 1.0) * screen_he.y, -(znear + p_vector3.z))); return camera_transform.xform(Vector3(((p_vector3.x / size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (p_vector3.y / size.height)) * 2.0 - 1.0) * screen_he.y, -(znear + p_vector3.z)));
} }
@@ -2808,20 +2758,23 @@ bool RuntimeNodeSelect::_handle_3d_input(const Ref<InputEvent> &p_event) {
} else if (k->is_ctrl_pressed()) { } else if (k->is_ctrl_pressed()) {
switch (k->get_physical_keycode()) { switch (k->get_physical_keycode()) {
case Key::EQUAL: { case Key::EQUAL: {
ERR_FAIL_COND_V(!SceneTree::get_singleton()->get_root()->is_camera_3d_override_enabled(), false);
cursor.fov_scale = CLAMP(cursor.fov_scale - 0.05, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE); cursor.fov_scale = CLAMP(cursor.fov_scale - 0.05, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE);
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar); SceneTree::get_singleton()->get_root()->get_override_camera_3d()->set_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar);
return true; return true;
} break; } break;
case Key::MINUS: { case Key::MINUS: {
ERR_FAIL_COND_V(!SceneTree::get_singleton()->get_root()->is_camera_3d_override_enabled(), false);
cursor.fov_scale = CLAMP(cursor.fov_scale + 0.05, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE); cursor.fov_scale = CLAMP(cursor.fov_scale + 0.05, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE);
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar); SceneTree::get_singleton()->get_root()->get_override_camera_3d()->set_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar);
return true; return true;
} break; } break;
case Key::KEY_0: { case Key::KEY_0: {
ERR_FAIL_COND_V(!SceneTree::get_singleton()->get_root()->is_camera_3d_override_enabled(), false);
cursor.fov_scale = 1; cursor.fov_scale = 1;
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov, camera_znear, camera_zfar); SceneTree::get_singleton()->get_root()->get_override_camera_3d()->set_perspective(camera_fov, camera_znear, camera_zfar);
return true; return true;
} break; } break;
@@ -2861,11 +2814,12 @@ void RuntimeNodeSelect::_set_camera_freelook_enabled(bool p_enabled) {
} }
void RuntimeNodeSelect::_cursor_scale_distance(real_t p_scale) { void RuntimeNodeSelect::_cursor_scale_distance(real_t p_scale) {
ERR_FAIL_COND(!SceneTree::get_singleton()->get_root()->is_camera_3d_override_enabled());
real_t min_distance = MAX(camera_znear * 4, VIEW_3D_MIN_ZOOM); real_t min_distance = MAX(camera_znear * 4, VIEW_3D_MIN_ZOOM);
real_t max_distance = MIN(camera_zfar / 4, VIEW_3D_MAX_ZOOM); real_t max_distance = MIN(camera_zfar / 4, VIEW_3D_MAX_ZOOM);
cursor.distance = CLAMP(cursor.distance * p_scale, min_distance, max_distance); cursor.distance = CLAMP(cursor.distance * p_scale, min_distance, max_distance);
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform()); SceneTree::get_singleton()->get_root()->get_override_camera_3d()->set_transform(_get_cursor_transform());
} }
void RuntimeNodeSelect::_scale_freelook_speed(real_t p_scale) { void RuntimeNodeSelect::_scale_freelook_speed(real_t p_scale) {
@@ -2880,6 +2834,8 @@ void RuntimeNodeSelect::_scale_freelook_speed(real_t p_scale) {
void RuntimeNodeSelect::_cursor_look(Ref<InputEventWithModifiers> p_event) { void RuntimeNodeSelect::_cursor_look(Ref<InputEventWithModifiers> p_event) {
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
ERR_FAIL_COND(!root->is_camera_3d_override_enabled());
const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(), root->get_size())); const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(), root->get_size()));
const Transform3D prev_camera_transform = _get_cursor_transform(); const Transform3D prev_camera_transform = _get_cursor_transform();
@@ -2900,11 +2856,13 @@ void RuntimeNodeSelect::_cursor_look(Ref<InputEventWithModifiers> p_event) {
Vector3 diff = prev_pos - pos; Vector3 diff = prev_pos - pos;
cursor.pos += diff; cursor.pos += diff;
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform()); root->get_override_camera_3d()->set_transform(_get_cursor_transform());
} }
void RuntimeNodeSelect::_cursor_pan(Ref<InputEventWithModifiers> p_event) { void RuntimeNodeSelect::_cursor_pan(Ref<InputEventWithModifiers> p_event) {
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
ERR_FAIL_COND(!root->is_camera_3d_override_enabled());
// Reduce all sides of the area by 1, so warping works when windows are maximized/fullscreen. // Reduce all sides of the area by 1, so warping works when windows are maximized/fullscreen.
const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(1, 1), root->get_size() - Vector2(2, 2))); const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(1, 1), root->get_size() - Vector2(2, 2)));
const real_t pan_speed = translation_sensitivity / 150.0; const real_t pan_speed = translation_sensitivity / 150.0;
@@ -2919,11 +2877,13 @@ void RuntimeNodeSelect::_cursor_pan(Ref<InputEventWithModifiers> p_event) {
camera_transform.translate_local(translation); camera_transform.translate_local(translation);
cursor.pos = camera_transform.origin; cursor.pos = camera_transform.origin;
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform()); root->get_override_camera_3d()->set_transform(_get_cursor_transform());
} }
void RuntimeNodeSelect::_cursor_orbit(Ref<InputEventWithModifiers> p_event) { void RuntimeNodeSelect::_cursor_orbit(Ref<InputEventWithModifiers> p_event) {
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
ERR_FAIL_COND(!root->is_camera_3d_override_enabled());
// Reduce all sides of the area by 1, so warping works when windows are maximized/fullscreen. // Reduce all sides of the area by 1, so warping works when windows are maximized/fullscreen.
const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(1, 1), root->get_size() - Vector2(2, 2))); const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(1, 1), root->get_size() - Vector2(2, 2)));
@@ -2941,7 +2901,7 @@ void RuntimeNodeSelect::_cursor_orbit(Ref<InputEventWithModifiers> p_event) {
cursor.y_rot += relative.x * orbit_sensitivity; cursor.y_rot += relative.x * orbit_sensitivity;
} }
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform()); root->get_override_camera_3d()->set_transform(_get_cursor_transform());
} }
Point2 RuntimeNodeSelect::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_event, Rect2 p_area) const { Point2 RuntimeNodeSelect::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_event, Rect2 p_area) const {
@@ -2969,22 +2929,25 @@ void RuntimeNodeSelect::_reset_camera_3d() {
cursor = Cursor(); cursor = Cursor();
Window *root = SceneTree::get_singleton()->get_root(); Window *root = SceneTree::get_singleton()->get_root();
Camera3D *camera = root->get_camera_3d(); Camera3D *game_camera = root->is_camera_3d_override_enabled() ? root->get_overridden_camera_3d() : root->get_camera_3d();
if (camera) { if (game_camera) {
Transform3D transform = camera->get_global_transform(); Transform3D transform = game_camera->get_camera_transform();
transform.translate_local(0, 0, -cursor.distance); transform.translate_local(0, 0, -cursor.distance);
cursor.pos = transform.origin; cursor.pos = transform.origin;
cursor.x_rot = -camera->get_global_rotation().x; cursor.x_rot = -game_camera->get_global_rotation().x;
cursor.y_rot = -camera->get_global_rotation().y; cursor.y_rot = -game_camera->get_global_rotation().y;
cursor.fov_scale = CLAMP(camera->get_fov() / camera_fov, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE); cursor.fov_scale = CLAMP(game_camera->get_fov() / camera_fov, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE);
} else { } else {
cursor.fov_scale = 1.0; cursor.fov_scale = 1.0;
} }
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform()); if (root->is_camera_3d_override_enabled()) {
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar); Camera3D *override_camera = root->get_override_camera_3d();
override_camera->set_transform(_get_cursor_transform());
override_camera->set_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar);
}
} }
#endif // _3D_DISABLED #endif // _3D_DISABLED

View File

@@ -1189,50 +1189,41 @@ void Viewport::canvas_parent_mark_dirty(Node *p_node) {
} }
} }
void Viewport::enable_canvas_transform_override(bool p_enable) { #if DEBUG_ENABLED
void Viewport::enable_camera_2d_override(bool p_enable) {
ERR_MAIN_THREAD_GUARD; ERR_MAIN_THREAD_GUARD;
if (override_canvas_transform == p_enable) {
return;
}
override_canvas_transform = p_enable;
if (p_enable) { if (p_enable) {
RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override); camera_2d_override.enable(this, camera_2d);
} else { } else {
RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform); camera_2d_override.disable(camera_2d);
} }
} }
bool Viewport::is_canvas_transform_override_enabled() const { bool Viewport::is_camera_2d_override_enabled() const {
ERR_READ_THREAD_GUARD_V(false); ERR_READ_THREAD_GUARD_V(false);
return override_canvas_transform; return camera_2d_override.is_enabled();
} }
void Viewport::set_canvas_transform_override(const Transform2D &p_transform) { Camera2D *Viewport::get_overridden_camera_2d() const {
ERR_MAIN_THREAD_GUARD; ERR_READ_THREAD_GUARD_V(nullptr);
if (canvas_transform_override == p_transform) { ERR_FAIL_COND_V(!camera_2d_override.is_enabled(), nullptr);
return; return camera_2d_override.get_overridden_camera();
} }
canvas_transform_override = p_transform; Camera2D *Viewport::get_override_camera_2d() const {
if (override_canvas_transform) { ERR_READ_THREAD_GUARD_V(nullptr);
RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override); ERR_FAIL_COND_V(!camera_2d_override.is_enabled(), nullptr);
} return camera_2d_override.is_enabled() ? get_camera_2d() : nullptr;
}
Transform2D Viewport::get_canvas_transform_override() const {
ERR_READ_THREAD_GUARD_V(Transform2D());
return canvas_transform_override;
} }
#endif // DEBUG_ENABLED
void Viewport::set_canvas_transform(const Transform2D &p_transform) { void Viewport::set_canvas_transform(const Transform2D &p_transform) {
ERR_MAIN_THREAD_GUARD; ERR_MAIN_THREAD_GUARD;
canvas_transform = p_transform; canvas_transform = p_transform;
if (!override_canvas_transform) {
RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform); RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
} }
}
Transform2D Viewport::get_canvas_transform() const { Transform2D Viewport::get_canvas_transform() const {
ERR_READ_THREAD_GUARD_V(Transform2D()); ERR_READ_THREAD_GUARD_V(Transform2D());
@@ -4220,6 +4211,13 @@ void Viewport::_audio_listener_2d_remove(AudioListener2D *p_audio_listener) {
} }
void Viewport::_camera_2d_set(Camera2D *p_camera_2d) { void Viewport::_camera_2d_set(Camera2D *p_camera_2d) {
#if DEBUG_ENABLED
if (is_camera_2d_override_enabled()) {
camera_2d_override.set_overridden_camera(p_camera_2d);
return;
}
#endif // DEBUG_ENABLED
camera_2d = p_camera_2d; camera_2d = p_camera_2d;
} }
@@ -4454,19 +4452,24 @@ void Viewport::_camera_3d_set(Camera3D *p_camera) {
return; return;
} }
#if DEBUG_ENABLED
if (is_camera_3d_override_enabled()) {
camera_3d_override.set_overridden_camera(p_camera);
return;
}
#endif // DEBUG_ENABLED
if (camera_3d) { if (camera_3d) {
camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT); camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
} }
camera_3d = p_camera; camera_3d = p_camera;
if (!camera_3d_override) {
if (camera_3d) { if (camera_3d) {
RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera()); RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
} else { } else {
RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID()); RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
} }
}
if (camera_3d) { if (camera_3d) {
camera_3d->notification(Camera3D::NOTIFICATION_BECAME_CURRENT); camera_3d->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
@@ -4504,77 +4507,34 @@ void Viewport::_camera_3d_make_next_current(Camera3D *p_exclude) {
} }
} }
#if DEBUG_ENABLED
void Viewport::enable_camera_3d_override(bool p_enable) { void Viewport::enable_camera_3d_override(bool p_enable) {
ERR_MAIN_THREAD_GUARD; ERR_MAIN_THREAD_GUARD;
if (p_enable == camera_3d_override) {
return;
}
if (p_enable) { if (p_enable) {
camera_3d_override.rid = RenderingServer::get_singleton()->camera_create(); camera_3d_override.enable(this, camera_3d);
} else { } else {
RenderingServer::get_singleton()->free(camera_3d_override.rid); camera_3d_override.disable(camera_3d);
camera_3d_override.rid = RID();
}
if (p_enable) {
RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d_override.rid);
} else if (camera_3d) {
RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
} else {
RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
} }
} }
void Viewport::set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) { bool Viewport::is_camera_3d_override_enabled() const {
ERR_MAIN_THREAD_GUARD; ERR_READ_THREAD_GUARD_V(false);
if (camera_3d_override) { return camera_3d_override.is_enabled();
if (camera_3d_override.fov == p_fovy_degrees && camera_3d_override.z_near == p_z_near &&
camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_PERSPECTIVE) {
return;
} }
camera_3d_override.fov = p_fovy_degrees; Camera3D *Viewport::get_overridden_camera_3d() const {
camera_3d_override.z_near = p_z_near; ERR_READ_THREAD_GUARD_V(nullptr);
camera_3d_override.z_far = p_z_far; ERR_FAIL_COND_V(!camera_3d_override.is_enabled(), nullptr);
camera_3d_override.projection = Camera3DOverrideData::PROJECTION_PERSPECTIVE; return camera_3d_override.get_overridden_camera();
RenderingServer::get_singleton()->camera_set_perspective(camera_3d_override.rid, camera_3d_override.fov, camera_3d_override.z_near, camera_3d_override.z_far);
}
} }
void Viewport::set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) { Camera3D *Viewport::get_override_camera_3d() const {
ERR_MAIN_THREAD_GUARD; ERR_READ_THREAD_GUARD_V(nullptr);
if (camera_3d_override) { ERR_FAIL_COND_V(!camera_3d_override.is_enabled(), nullptr);
if (camera_3d_override.size == p_size && camera_3d_override.z_near == p_z_near && return get_camera_3d();
camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
return;
}
camera_3d_override.size = p_size;
camera_3d_override.z_near = p_z_near;
camera_3d_override.z_far = p_z_far;
camera_3d_override.projection = Camera3DOverrideData::PROJECTION_ORTHOGONAL;
RenderingServer::get_singleton()->camera_set_orthogonal(camera_3d_override.rid, camera_3d_override.size, camera_3d_override.z_near, camera_3d_override.z_far);
}
}
HashMap<StringName, real_t> Viewport::get_camera_3d_override_properties() const {
HashMap<StringName, real_t> props;
props["size"] = 0;
props["fov"] = 0;
props["z_near"] = 0;
props["z_far"] = 0;
ERR_READ_THREAD_GUARD_V(props);
props["size"] = camera_3d_override.size;
props["fov"] = camera_3d_override.fov;
props["z_near"] = camera_3d_override.z_near;
props["z_far"] = camera_3d_override.z_far;
return props;
} }
#endif //DEBUG_ENABLED
void Viewport::set_disable_3d(bool p_disable) { void Viewport::set_disable_3d(bool p_disable) {
ERR_MAIN_THREAD_GUARD; ERR_MAIN_THREAD_GUARD;
@@ -4587,76 +4547,6 @@ bool Viewport::is_3d_disabled() const {
return disable_3d; return disable_3d;
} }
bool Viewport::is_camera_3d_override_enabled() const {
ERR_READ_THREAD_GUARD_V(false);
return camera_3d_override;
}
void Viewport::set_camera_3d_override_transform(const Transform3D &p_transform) {
ERR_MAIN_THREAD_GUARD;
if (camera_3d_override) {
camera_3d_override.transform = p_transform;
RenderingServer::get_singleton()->camera_set_transform(camera_3d_override.rid, p_transform);
}
}
Transform3D Viewport::get_camera_3d_override_transform() const {
ERR_READ_THREAD_GUARD_V(Transform3D());
if (camera_3d_override) {
return camera_3d_override.transform;
}
return Transform3D();
}
Vector3 Viewport::camera_3d_override_project_ray_normal(const Point2 &p_pos) const {
ERR_READ_THREAD_GUARD_V(Vector3());
Vector3 ray = camera_3d_override_project_local_ray_normal(p_pos);
return camera_3d_override.transform.basis.xform(ray).normalized();
}
Vector3 Viewport::camera_3d_override_project_local_ray_normal(const Point2 &p_pos) const {
ERR_READ_THREAD_GUARD_V(Vector3());
Size2 viewport_size = get_camera_rect_size();
Vector2 cpos = get_camera_coords(p_pos);
Vector3 ray;
if (camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
ray = Vector3(0, 0, -1);
} else {
Projection cm;
cm.set_perspective(camera_3d_override.fov, get_visible_rect().size.aspect(), camera_3d_override.z_near, camera_3d_override.z_far, false);
Vector2 screen_he = cm.get_viewport_half_extents();
ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -camera_3d_override.z_near).normalized();
}
return ray;
}
Vector3 Viewport::camera_3d_override_project_ray_origin(const Point2 &p_pos) const {
ERR_READ_THREAD_GUARD_V(Vector3());
Size2 viewport_size = get_camera_rect_size();
Vector2 cpos = get_camera_coords(p_pos);
ERR_FAIL_COND_V(viewport_size.y == 0, Vector3());
if (camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
Vector2 pos = cpos / viewport_size;
real_t vsize, hsize;
hsize = camera_3d_override.size * viewport_size.aspect();
vsize = camera_3d_override.size;
Vector3 ray;
ray.x = pos.x * (hsize)-hsize / 2;
ray.y = (1.0 - pos.y) * (vsize)-vsize / 2;
ray.z = -camera_3d_override.z_near;
ray = camera_3d_override.transform.xform(ray);
return ray;
} else {
return camera_3d_override.transform.origin;
};
}
Ref<World3D> Viewport::get_world_3d() const { Ref<World3D> Viewport::get_world_3d() const {
ERR_READ_THREAD_GUARD_V(Ref<World3D>()); ERR_READ_THREAD_GUARD_V(Ref<World3D>());
return world_3d; return world_3d;
@@ -5594,3 +5484,64 @@ void SubViewport::_validate_property(PropertyInfo &p_property) const {
SubViewport::SubViewport() { SubViewport::SubViewport() {
RS::get_singleton()->viewport_set_size(get_viewport_rid(), get_size().width, get_size().height); RS::get_singleton()->viewport_set_size(get_viewport_rid(), get_size().width, get_size().height);
} }
/////////////////////////////////
#if DEBUG_ENABLED
template <class T>
bool Viewport::CameraOverride<T>::is_enabled() const {
return enabled;
}
template <class T>
void Viewport::CameraOverride<T>::enable(Viewport *p_viewport, const T *p_current_camera) {
if (enabled) {
return;
}
T *override_camera = memnew(T);
override_camera->set_name(vformat("Override%s", T ::get_class_static()));
p_viewport->add_child(override_camera, false, Node::INTERNAL_MODE_BACK);
override_camera->make_current();
set_overridden_camera(p_current_camera);
// Call to make the override camera current must happen before we enable the override to prevent the override mechanism from kicking in.
enabled = true;
}
template <class T>
void Viewport::CameraOverride<T>::disable(T *p_current_camera) {
if (!enabled) {
return;
}
// Call to make the overridden camera current must happen after we disable the override to prevent the override mechanism from kicking in.
enabled = false;
T *overridden_camera = get_overridden_camera();
if (overridden_camera) {
overridden_camera->make_current();
} else {
p_current_camera->clear_current();
}
p_current_camera->queue_free();
overridden_camera_id = ObjectID();
}
template <class T>
void Viewport::CameraOverride<T>::set_overridden_camera(const T *p_camera) {
overridden_camera_id = p_camera ? p_camera->get_instance_id() : ObjectID();
}
template <class T>
T *Viewport::CameraOverride<T>::get_overridden_camera() const {
return ObjectDB::get_instance<T>(overridden_camera_id);
}
// Explicit template instantiation to allow template definitions inside cpp file
// and prevent instantiation using other than the desired camera types.
template class Viewport::CameraOverride<Camera2D>;
template class Viewport::CameraOverride<Camera3D>;
#endif // DEBUG_ENABLED

View File

@@ -248,9 +248,6 @@ private:
RID current_canvas; RID current_canvas;
RID subwindow_canvas; RID subwindow_canvas;
bool override_canvas_transform = false;
Transform2D canvas_transform_override;
Transform2D canvas_transform; Transform2D canvas_transform;
Transform2D global_canvas_transform; Transform2D global_canvas_transform;
Transform2D stretch_transform; Transform2D stretch_transform;
@@ -533,11 +530,12 @@ public:
Ref<World2D> get_world_2d() const; Ref<World2D> get_world_2d() const;
Ref<World2D> find_world_2d() const; Ref<World2D> find_world_2d() const;
void enable_canvas_transform_override(bool p_enable); #if DEBUG_ENABLED
bool is_canvas_transform_override_enabled() const; void enable_camera_2d_override(bool p_enable);
bool is_camera_2d_override_enabled() const;
void set_canvas_transform_override(const Transform2D &p_transform); Camera2D *get_overridden_camera_2d() const;
Transform2D get_canvas_transform_override() const; Camera2D *get_override_camera_2d() const;
#endif // DEBUG_ENABLED
void set_canvas_transform(const Transform2D &p_transform); void set_canvas_transform(const Transform2D &p_transform);
Transform2D get_canvas_transform() const; Transform2D get_canvas_transform() const;
@@ -737,6 +735,23 @@ public:
virtual bool is_sub_viewport() const { return false; } virtual bool is_sub_viewport() const { return false; }
private: private:
#if DEBUG_ENABLED
template <class T>
class CameraOverride {
private:
bool enabled = false;
ObjectID overridden_camera_id;
public:
bool is_enabled() const;
void enable(Viewport *p_viewport, const T *p_current_camera);
void disable(T *p_current_camera);
void set_overridden_camera(const T *p_camera);
T *get_overridden_camera() const;
};
#endif // DEBUG_ENABLED
// 2D audio, camera, and physics. (don't put World2D here because World2D is needed for Control nodes). // 2D audio, camera, and physics. (don't put World2D here because World2D is needed for Control nodes).
friend class AudioListener2D; // Needs _audio_listener_2d_set and _audio_listener_2d_remove friend class AudioListener2D; // Needs _audio_listener_2d_set and _audio_listener_2d_remove
AudioListener2D *audio_listener_2d = nullptr; AudioListener2D *audio_listener_2d = nullptr;
@@ -747,6 +762,9 @@ private:
friend class Camera2D; // Needs _camera_2d_set friend class Camera2D; // Needs _camera_2d_set
Camera2D *camera_2d = nullptr; Camera2D *camera_2d = nullptr;
#if DEBUG_ENABLED
CameraOverride<Camera2D> camera_2d_override;
#endif // DEBUG_ENABLED
void _camera_2d_set(Camera2D *p_camera_2d); void _camera_2d_set(Camera2D *p_camera_2d);
#ifndef PHYSICS_2D_DISABLED #ifndef PHYSICS_2D_DISABLED
@@ -786,26 +804,11 @@ private:
void _collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape); void _collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
#endif // PHYSICS_3D_DISABLED #endif // PHYSICS_3D_DISABLED
struct Camera3DOverrideData {
Transform3D transform;
enum Projection {
PROJECTION_PERSPECTIVE,
PROJECTION_ORTHOGONAL
};
Projection projection = Projection::PROJECTION_PERSPECTIVE;
real_t fov = 0.0;
real_t size = 0.0;
real_t z_near = 0.0;
real_t z_far = 0.0;
RID rid;
operator bool() const {
return rid != RID();
}
} camera_3d_override;
friend class Camera3D; friend class Camera3D;
Camera3D *camera_3d = nullptr; Camera3D *camera_3d = nullptr;
#if DEBUG_ENABLED
CameraOverride<Camera3D> camera_3d_override;
#endif // DEBUG_ENABLED
HashSet<Camera3D *> camera_3d_set; HashSet<Camera3D *> camera_3d_set;
void _camera_3d_transform_changed_notify(); void _camera_3d_transform_changed_notify();
void _camera_3d_set(Camera3D *p_camera); void _camera_3d_set(Camera3D *p_camera);
@@ -825,19 +828,13 @@ public:
bool is_audio_listener_3d() const; bool is_audio_listener_3d() const;
Camera3D *get_camera_3d() const; Camera3D *get_camera_3d() const;
#if DEBUG_ENABLED
void enable_camera_3d_override(bool p_enable); void enable_camera_3d_override(bool p_enable);
bool is_camera_3d_override_enabled() const; bool is_camera_3d_override_enabled() const;
Camera3D *get_overridden_camera_3d() const;
void set_camera_3d_override_transform(const Transform3D &p_transform); Camera3D *get_override_camera_3d() const;
Transform3D get_camera_3d_override_transform() const; #endif // DEBUG_ENABLED
void set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far);
void set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far);
HashMap<StringName, real_t> get_camera_3d_override_properties() const;
Vector3 camera_3d_override_project_ray_normal(const Point2 &p_pos) const;
Vector3 camera_3d_override_project_ray_origin(const Point2 &p_pos) const;
Vector3 camera_3d_override_project_local_ray_normal(const Point2 &p_pos) const;
void set_disable_3d(bool p_disable); void set_disable_3d(bool p_disable);
bool is_3d_disabled() const; bool is_3d_disabled() const;