Make Camera3D gizmo the same aspect ratio as its viewport

This commit is contained in:
Haoyu Qiu 2022-11-15 17:02:20 +08:00
parent 245e6454a0
commit 6c5dc78f59
4 changed files with 64 additions and 20 deletions

View File

@ -30,6 +30,7 @@
#include "node_3d_editor_gizmos.h" #include "node_3d_editor_gizmos.h"
#include "core/config/project_settings.h"
#include "core/math/convex_hull.h" #include "core/math/convex_hull.h"
#include "core/math/geometry_2d.h" #include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h" #include "core/math/geometry_3d.h"
@ -1732,6 +1733,24 @@ Camera3DGizmoPlugin::Camera3DGizmoPlugin() {
create_handle_material("handles"); create_handle_material("handles");
} }
Size2i Camera3DGizmoPlugin::_get_viewport_size(Camera3D *p_camera) {
Viewport *viewport = p_camera->get_viewport();
Window *window = Object::cast_to<Window>(viewport);
if (window) {
return window->get_size();
}
SubViewport *sub_viewport = Object::cast_to<SubViewport>(viewport);
ERR_FAIL_NULL_V(sub_viewport, Size2i());
if (sub_viewport == EditorNode::get_singleton()->get_scene_root()) {
return Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
}
return sub_viewport->get_size();
}
bool Camera3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { bool Camera3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<Camera3D>(p_spatial) != nullptr; return Object::cast_to<Camera3D>(p_spatial) != nullptr;
} }
@ -1830,6 +1849,10 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<Material> material = get_material("camera_material", p_gizmo); Ref<Material> material = get_material("camera_material", p_gizmo);
const Size2i viewport_size = _get_viewport_size(camera);
const real_t viewport_aspect = viewport_size.x > 0 && viewport_size.y > 0 ? viewport_size.aspect() : 1.0;
const Size2 size_factor = viewport_aspect > 1.0 ? Size2(1.0, 1.0 / viewport_aspect) : Size2(viewport_aspect, 1.0);
#define ADD_TRIANGLE(m_a, m_b, m_c) \ #define ADD_TRIANGLE(m_a, m_b, m_c) \
{ \ { \
lines.push_back(m_a); \ lines.push_back(m_a); \
@ -1857,10 +1880,11 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
// The real FOV is halved for accurate representation // The real FOV is halved for accurate representation
float fov = camera->get_fov() / 2.0; float fov = camera->get_fov() / 2.0;
Vector3 side = Vector3(Math::sin(Math::deg_to_rad(fov)), 0, -Math::cos(Math::deg_to_rad(fov))); const float hsize = Math::sin(Math::deg_to_rad(fov));
Vector3 nside = side; const float depth = -Math::cos(Math::deg_to_rad(fov));
nside.x = -nside.x; Vector3 side = Vector3(hsize * size_factor.x, 0, depth);
Vector3 up = Vector3(0, side.x, 0); Vector3 nside = Vector3(-side.x, side.y, side.z);
Vector3 up = Vector3(0, hsize * size_factor.y, 0);
ADD_TRIANGLE(Vector3(), side + up, side - up); ADD_TRIANGLE(Vector3(), side + up, side - up);
ADD_TRIANGLE(Vector3(), nside + up, nside - up); ADD_TRIANGLE(Vector3(), nside + up, nside - up);
@ -1868,18 +1892,18 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
ADD_TRIANGLE(Vector3(), side - up, nside - up); ADD_TRIANGLE(Vector3(), side - up, nside - up);
handles.push_back(side); handles.push_back(side);
side.x *= 0.25; side.x = MIN(side.x, hsize * 0.25);
nside.x *= 0.25; nside.x = -side.x;
Vector3 tup(0, up.y * 3 / 2, side.z); Vector3 tup(0, up.y + hsize / 2, side.z);
ADD_TRIANGLE(tup, side + up, nside + up); ADD_TRIANGLE(tup, side + up, nside + up);
} break; } break;
case Camera3D::PROJECTION_ORTHOGONAL: { case Camera3D::PROJECTION_ORTHOGONAL: {
float size = camera->get_size(); float size = camera->get_size();
float hsize = size * 0.5; float hsize = size * 0.5;
Vector3 right(hsize, 0, 0); Vector3 right(hsize * size_factor.x, 0, 0);
Vector3 up(0, hsize, 0); Vector3 up(0, hsize * size_factor.y, 0);
Vector3 back(0, 0, -1.0); Vector3 back(0, 0, -1.0);
Vector3 front(0, 0, 0); Vector3 front(0, 0, 0);
@ -1890,18 +1914,19 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
handles.push_back(right + back); handles.push_back(right + back);
right.x *= 0.25; right.x = MIN(right.x, hsize * 0.25);
Vector3 tup(0, up.y * 3 / 2, back.z); Vector3 tup(0, up.y + hsize / 2, back.z);
ADD_TRIANGLE(tup, right + up + back, -right + up + back); ADD_TRIANGLE(tup, right + up + back, -right + up + back);
} break; } break;
case Camera3D::PROJECTION_FRUSTUM: { case Camera3D::PROJECTION_FRUSTUM: {
float hsize = camera->get_size() / 2.0; float hsize = camera->get_size() / 2.0;
Vector3 side = Vector3(hsize, 0, -camera->get_near()).normalized(); Vector3 side = Vector3(hsize, 0, -camera->get_near()).normalized();
Vector3 nside = side; side.x *= size_factor.x;
nside.x = -nside.x; Vector3 nside = Vector3(-side.x, side.y, side.z);
Vector3 up = Vector3(0, side.x, 0); Vector3 up = Vector3(0, hsize * size_factor.y, 0);
Vector3 offset = Vector3(camera->get_frustum_offset().x, camera->get_frustum_offset().y, 0.0); Vector3 offset = Vector3(camera->get_frustum_offset().x, camera->get_frustum_offset().y, 0.0);
ADD_TRIANGLE(Vector3(), side + up + offset, side - up + offset); ADD_TRIANGLE(Vector3(), side + up + offset, side - up + offset);
@ -1909,11 +1934,11 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
ADD_TRIANGLE(Vector3(), side + up + offset, nside + up + offset); ADD_TRIANGLE(Vector3(), side + up + offset, nside + up + offset);
ADD_TRIANGLE(Vector3(), side - up + offset, nside - up + offset); ADD_TRIANGLE(Vector3(), side - up + offset, nside - up + offset);
side.x *= 0.25; side.x = MIN(side.x, hsize * 0.25);
nside.x *= 0.25; nside.x = -side.x;
Vector3 tup(0, up.y * 3 / 2, side.z); Vector3 tup(0, up.y + hsize / 2, side.z);
ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset); ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset);
} } break;
} }
#undef ADD_TRIANGLE #undef ADD_TRIANGLE
@ -1921,7 +1946,10 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(lines, material); p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines); p_gizmo->add_collision_segments(lines);
p_gizmo->add_handles(handles, get_material("handles"));
if (!handles.is_empty()) {
p_gizmo->add_handles(handles, get_material("handles"));
}
} }
////// //////

View File

@ -264,6 +264,9 @@ public:
class Camera3DGizmoPlugin : public EditorNode3DGizmoPlugin { class Camera3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Camera3DGizmoPlugin, EditorNode3DGizmoPlugin); GDCLASS(Camera3DGizmoPlugin, EditorNode3DGizmoPlugin);
private:
static Size2i _get_viewport_size(Camera3D *p_camera);
public: public:
bool has_gizmo(Node3D *p_spatial) override; bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override; String get_gizmo_name() const override;

View File

@ -7248,6 +7248,8 @@ void Node3DEditor::_notification(int p_what) {
sun_state->set_custom_minimum_size(sun_vb->get_combined_minimum_size()); sun_state->set_custom_minimum_size(sun_vb->get_combined_minimum_size());
environ_state->set_custom_minimum_size(environ_vb->get_combined_minimum_size()); environ_state->set_custom_minimum_size(environ_vb->get_combined_minimum_size());
EditorNode::get_singleton()->connect("project_settings_changed", callable_mp(this, &Node3DEditor::update_all_gizmos).bind(Variant()));
} break; } break;
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_ENTER_TREE: {

View File

@ -112,6 +112,12 @@ void Camera3D::_notification(int p_what) {
if (current || first_camera) { if (current || first_camera) {
viewport->_camera_3d_set(this); viewport->_camera_3d_set(this);
} }
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
viewport->connect(SNAME("size_changed"), callable_mp((Node3D *)this, &Camera3D::update_gizmos));
}
#endif
} break; } break;
case NOTIFICATION_TRANSFORM_CHANGED: { case NOTIFICATION_TRANSFORM_CHANGED: {
@ -133,6 +139,11 @@ void Camera3D::_notification(int p_what) {
} }
if (viewport) { if (viewport) {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
viewport->disconnect(SNAME("size_changed"), callable_mp((Node3D *)this, &Camera3D::update_gizmos));
}
#endif
viewport->_camera_3d_remove(this); viewport->_camera_3d_remove(this);
viewport = nullptr; viewport = nullptr;
} }