diff --git a/core/math/projection.cpp b/core/math/projection.cpp index c135e1946aec..534953c4004c 100644 --- a/core/math/projection.cpp +++ b/core/math/projection.cpp @@ -33,6 +33,7 @@ #include "core/math/aabb.h" #include "core/math/math_funcs.h" #include "core/math/plane.h" +#include "core/math/quaternion.h" #include "core/math/rect2.h" #include "core/math/transform_3d.h" #include "core/string/ustring.h" @@ -313,6 +314,62 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t *this = *this * cm; } +void Projection::set_oblique(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, Quaternion p_oblique_plane, bool p_flip_fov) { + if (p_flip_fov) { + p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect); + } + + // real_t *columns = (real_t *)columns; + + real_t sine, cotangent, deltaZ; + real_t radians = p_fovy_degrees / 2.0 * Math_PI / 180.0; + + deltaZ = p_z_far - p_z_near; + sine = Math::sin(radians); + + if ((deltaZ == 0) || (sine == 0) || (p_aspect == 0)) { + return; + } + cotangent = Math::cos(radians) / sine; + + set_identity(); + + columns[0][0] = cotangent / p_aspect; + columns[1][1] = cotangent; + columns[2][2] = -(p_z_far + p_z_near) / deltaZ; + columns[2][3] = -1; + columns[3][2] = -2 * p_z_near * p_z_far / deltaZ; + columns[3][3] = 0; + + // Here goes oblique magic! + // Eric Lengyel Solution: http://terathon.com/code/oblique.html + // i < 0 ? -1 : (i > 0 ? +1 : 0) = sign() + Quaternion q; + + /* clang-format off */ + q.x = (( + p_oblique_plane.x < 0 ? -1 : + p_oblique_plane.x > 0 ? +1 : 0 + ) + columns[2][0] + ) / columns[0][0]; + + q.y = (( + p_oblique_plane.y < 0 ? -1 : + p_oblique_plane.y > 0 ? +1 : 0 + ) + columns[2][1] + ) / columns[1][1]; + /* clang-format on */ + + q.z = -1.0F; + q.w = (1.0F + columns[2][2]) / columns[3][2]; + + Quaternion c = p_oblique_plane * (2.0F / p_oblique_plane.dot(q)); + columns[0][2] = c.x; + columns[1][2] = c.y; + columns[2][2] = c.z + 1.0F; + columns[3][2] = c.w; +} + void Projection::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) { // we first calculate our base frustum on our values without taking our lens magnification into account. real_t f1 = (p_intraocular_dist * 0.5) / p_display_to_lens; diff --git a/core/math/projection.h b/core/math/projection.h index 38fb9781aea8..da9c70da8ea5 100644 --- a/core/math/projection.h +++ b/core/math/projection.h @@ -31,6 +31,8 @@ #ifndef PROJECTION_H #define PROJECTION_H +#include "core/math/math_defs.h" +#include "core/math/quaternion.h" #include "core/math/vector3.h" #include "core/math/vector4.h" @@ -74,6 +76,7 @@ struct _NO_DISCARD_ Projection { void set_light_atlas_rect(const Rect2 &p_rect); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); + void set_oblique(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, Quaternion p_oblique_plane, bool p_flip_fov = false); void set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far); void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar); void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false); diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index 322c4f0bf486..5fc72ed73cce 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -116,6 +116,28 @@ Sets the camera projection to frustum mode (see [constant PROJECTION_FRUSTUM]), by specifying a [param size], an [param offset], and the [param z_near] and [param z_far] clip planes in world space units. See also [member frustum_offset]. + + + + + + + + Sets the camera projection to perspective with oblique near clipping (see [constant PROJECTION_OBLIQUE]), by specifying a [code]fov[/code] (field of view) angle in degrees, the [code]oblique_data[/code] used to transform the projection frustum, and the [code]z_near[/code] and [code]z_far[/code] clip planes in world space before transformation. + [b]Note:[/b] [code]oblique_data[/code] is a dictionary containing the following fields: + [code]camera_gt[/code]: The camera global transform. + [code]normal[/code]: The desired normal vector of the plane. + [code]position[/code]: The world-space position of the plane relative to the camera + [code]offset[/code]: An adjustable offset for the oblique plane distance value + + + + + + + Sets the Oblique_normal and oblique_position values of an oblique projection camera using a the origin and upward vector of the transform argument. For ease of using plane meshes as portals and mirrors. + + @@ -190,6 +212,15 @@ The distance to the near culling boundary for this camera relative to its local Z axis. + + The desired normal vector of the world space plane used by an oblique camera as an oblique near clipping plane. + + + The an offset value for the oblique plane along it's forward vector. + + + The world space position of the plane used by an oblique camera as an oblique near clipping plane. + The camera's projection mode. In [constant PROJECTION_PERSPECTIVE] mode, objects' Z distance from the camera's local space scales their perceived size. @@ -210,6 +241,9 @@ Frustum projection. This mode allows adjusting [member frustum_offset] to create "tilted frustum" effects. + + Oblique Near Plane projection. This mode allows adjusting the near clipping plane to align with a given world plane. + Preserves the horizontal aspect ratio; also known as Vert- scaling. This is usually the best option for projects running in portrait mode, as taller aspect ratios will benefit from a wider vertical FOV. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 87e569ba20d6..efa96dffb058 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -131,6 +131,20 @@ Sets camera to use frustum projection. This mode allows adjusting the [param offset] argument to create "tilted frustum" effects. + + + + + + + + + + + + Sets camera to use oblique projection. This mode allows adjusting the [code]normal[/code], [code]position[/code], and [code]offset[/code] arguments to create an oblique near clipping plane. + + diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 91c7fbc06ab5..927fca84cc05 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -1941,6 +1941,26 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Vector3 tup(0, up.y + hsize / 2, side.z); ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset); } break; + case Camera3D::PROJECTION_OBLIQUE: { + // The real FOV is halved for accurate representation + 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))); + Vector3 nside = side; + nside.x = -nside.x; + Vector3 up = Vector3(0, side.x, 0); + + ADD_TRIANGLE(Vector3(), side + up, side - up); + ADD_TRIANGLE(Vector3(), nside + up, nside - up); + ADD_TRIANGLE(Vector3(), side + up, nside + up); + ADD_TRIANGLE(Vector3(), side - up, nside - up); + + handles.push_back(side); + side.x *= 0.25; + nside.x *= 0.25; + Vector3 tup(0, up.y * 3 / 2, side.z); + ADD_TRIANGLE(tup, side + up, nside + up); + } break; } #undef ADD_TRIANGLE diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 2a50575749dd..92508468eeb1 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -47,7 +47,14 @@ void Camera3D::_update_camera_mode() { switch (mode) { case PROJECTION_PERSPECTIVE: { set_perspective(fov, near, far); - + } break; + case PROJECTION_OBLIQUE: { + Dictionary ob_data = Dictionary(); + ob_data["camera_gt"] = get_global_transform(); + ob_data["normal"] = oblique_normal; + ob_data["position"] = oblique_position; + ob_data["offset"] = oblique_offset; + set_oblique(fov, ob_data, near, far); } break; case PROJECTION_ORTHOGONAL: { set_orthogonal(size, near, far); @@ -60,7 +67,7 @@ void Camera3D::_update_camera_mode() { void Camera3D::_validate_property(PropertyInfo &p_property) const { if (p_property.name == "fov") { - if (mode != PROJECTION_PERSPECTIVE) { + if (mode != PROJECTION_PERSPECTIVE && mode != PROJECTION_OBLIQUE) { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } else if (p_property.name == "size") { @@ -71,6 +78,10 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const { if (mode != PROJECTION_FRUSTUM) { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } + } else if (p_property.name == "oblique_normal" || p_property.name == "oblique_position" || p_property.name == "oblique_offset") { + if (mode != PROJECTION_OBLIQUE) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } } if (attributes.is_valid()) { @@ -185,6 +196,28 @@ void Camera3D::set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_ force_change = false; } +void Camera3D::set_oblique(real_t p_fovy_degrees, const Dictionary &p_oblique_data, real_t p_z_near, real_t p_z_far) { + if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_OBLIQUE) { + return; + } + + if (!force_change && (Vector3)p_oblique_data["normal"] == oblique_normal && (Vector3)p_oblique_data["position"] == oblique_position && (real_t)p_oblique_data["offset"] == oblique_offset) { + return; + } + + fov = p_fovy_degrees; + oblique_normal = p_oblique_data["normal"]; + oblique_position = p_oblique_data["position"]; + oblique_offset = p_oblique_data["offset"]; + near = p_z_near; + far = p_z_far; + mode = PROJECTION_OBLIQUE; + + RenderingServer::get_singleton()->camera_set_oblique(camera, fov, p_oblique_data["camera_gt"], p_oblique_data["normal"], p_oblique_data["position"], p_oblique_data["offset"], near, far); + update_gizmos(); + force_change = false; +} + void Camera3D::set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) { if (!force_change && size == p_size && p_z_near == near && p_z_far == far && mode == PROJECTION_ORTHOGONAL) { return; @@ -218,8 +251,8 @@ void Camera3D::set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, rea update_gizmos(); } -void Camera3D::set_projection(ProjectionType p_mode) { - if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) { +void Camera3D::set_projection(Camera3D::ProjectionType p_mode) { + if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_OBLIQUE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) { mode = p_mode; _update_camera_mode(); notify_property_list_changed(); @@ -501,6 +534,7 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_position_behind", "world_point"), &Camera3D::is_position_behind); ClassDB::bind_method(D_METHOD("project_position", "screen_point", "z_depth"), &Camera3D::project_position); ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera3D::set_perspective); + ClassDB::bind_method(D_METHOD("set_oblique", "fov", "oblique_data", "z_near", "z_far"), &Camera3D::set_oblique); ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera3D::set_orthogonal); ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera3D::set_frustum); ClassDB::bind_method(D_METHOD("make_current"), &Camera3D::make_current); @@ -509,11 +543,18 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_current"), &Camera3D::is_current); ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera3D::get_camera_transform); ClassDB::bind_method(D_METHOD("get_fov"), &Camera3D::get_fov); + ClassDB::bind_method(D_METHOD("get_oblique_normal"), &Camera3D::get_oblique_normal); + ClassDB::bind_method(D_METHOD("get_oblique_position"), &Camera3D::get_oblique_position); + ClassDB::bind_method(D_METHOD("get_oblique_offset"), &Camera3D::get_oblique_offset); ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera3D::get_frustum_offset); ClassDB::bind_method(D_METHOD("get_size"), &Camera3D::get_size); ClassDB::bind_method(D_METHOD("get_far"), &Camera3D::get_far); ClassDB::bind_method(D_METHOD("get_near"), &Camera3D::get_near); ClassDB::bind_method(D_METHOD("set_fov", "fov"), &Camera3D::set_fov); + ClassDB::bind_method(D_METHOD("set_oblique_normal", "oblique_normal"), &Camera3D::set_oblique_normal); + ClassDB::bind_method(D_METHOD("set_oblique_position", "oblique_position"), &Camera3D::set_oblique_position); + ClassDB::bind_method(D_METHOD("set_oblique_plane_from_transform", "oblique_transform"), &Camera3D::set_oblique_plane_from_transform); + ClassDB::bind_method(D_METHOD("set_oblique_offset", "oblique_offset"), &Camera3D::set_oblique_offset); ClassDB::bind_method(D_METHOD("set_frustum_offset", "offset"), &Camera3D::set_frustum_offset); ClassDB::bind_method(D_METHOD("set_size", "size"), &Camera3D::set_size); ClassDB::bind_method(D_METHOD("set_far", "far"), &Camera3D::set_far); @@ -551,17 +592,21 @@ void Camera3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum,Oblique"), "set_projection", "get_projection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1,degrees"), "set_fov", "get_fov"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.001,suffix:m"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_frustum_offset", "get_frustum_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "oblique_normal"), "set_oblique_normal", "get_oblique_normal"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "oblique_position"), "set_oblique_position", "get_oblique_position"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oblique_offset"), "set_oblique_offset", "get_oblique_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.001"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp"), "set_near", "get_near"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp"), "set_far", "get_far"); BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL); BIND_ENUM_CONSTANT(PROJECTION_FRUSTUM); + BIND_ENUM_CONSTANT(PROJECTION_OBLIQUE); BIND_ENUM_CONSTANT(KEEP_WIDTH); BIND_ENUM_CONSTANT(KEEP_HEIGHT); @@ -575,6 +620,18 @@ real_t Camera3D::get_fov() const { return fov; } +Vector3 Camera3D::get_oblique_normal() const { + return oblique_normal; +} + +Vector3 Camera3D::get_oblique_position() const { + return oblique_position; +} + +real_t Camera3D::get_oblique_offset() const { + return oblique_offset; +} + real_t Camera3D::get_size() const { return size; } @@ -601,6 +658,27 @@ void Camera3D::set_fov(real_t p_fov) { _update_camera_mode(); } +void Camera3D::set_oblique_normal(Vector3 p_oblique_normal) { + oblique_normal = p_oblique_normal; + _update_camera_mode(); +} + +void Camera3D::set_oblique_position(Vector3 p_oblique_position) { + oblique_position = p_oblique_position; + _update_camera_mode(); +} + +void Camera3D::set_oblique_offset(real_t p_oblique_offset) { + oblique_offset = p_oblique_offset; + _update_camera_mode(); +} + +void Camera3D::set_oblique_plane_from_transform(Transform3D p_oblique_transform) { + set_oblique_normal(p_oblique_transform.basis.get_column(1)); + set_oblique_position(p_oblique_transform.origin); + _update_camera_mode(); +} + void Camera3D::set_size(real_t p_size) { ERR_FAIL_COND(p_size < 0.001 || p_size > 16384); size = p_size; @@ -736,6 +814,9 @@ RID Camera3D::get_pyramid_shape_rid() { Camera3D::Camera3D() { camera = RenderingServer::get_singleton()->camera_create(); set_perspective(75.0, 0.05, 4000.0); + oblique_normal = Vector3(0, 1, 0); + oblique_position = Vector3(); + oblique_offset = 0; RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers); //active=false; velocity_tracker.instantiate(); diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index f150a23e2711..a7704f98f80f 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -43,7 +43,8 @@ class Camera3D : public Node3D { enum ProjectionType { PROJECTION_PERSPECTIVE, PROJECTION_ORTHOGONAL, - PROJECTION_FRUSTUM + PROJECTION_FRUSTUM, + PROJECTION_OBLIQUE }; enum KeepAspect { @@ -64,7 +65,10 @@ class Camera3D : public Node3D { ProjectionType mode = PROJECTION_PERSPECTIVE; - real_t fov = 75.0; + real_t fov = 0.0; + Vector3 oblique_normal; + Vector3 oblique_position; + real_t oblique_offset; real_t size = 1.0; Vector2 frustum_offset; real_t near = 0.05; @@ -112,6 +116,7 @@ class Camera3D : public Node3D { }; void set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far); + void set_oblique(real_t p_fovy_degrees, const Dictionary &p_oblique_data, real_t p_z_near, real_t p_z_far); void set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far); void set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, real_t p_z_far); void set_projection(Camera3D::ProjectionType p_mode); @@ -124,6 +129,9 @@ class Camera3D : public Node3D { RID get_camera() const; real_t get_fov() const; + Vector3 get_oblique_normal() const; + Vector3 get_oblique_position() const; + real_t get_oblique_offset() const; real_t get_size() const; real_t get_far() const; real_t get_near() const; @@ -132,6 +140,10 @@ class Camera3D : public Node3D { ProjectionType get_projection() const; void set_fov(real_t p_fov); + void set_oblique_normal(Vector3 p_oblique_normal); + void set_oblique_position(Vector3 p_oblique_position); + void set_oblique_offset(real_t p_oblique_offset); + void set_oblique_plane_from_transform(Transform3D p_oblique_plane_transform); void set_size(real_t p_size); void set_far(real_t p_far); void set_near(real_t p_near); diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 675e81c62a25..4c1267063233 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -31,7 +31,9 @@ #include "renderer_scene_cull.h" #include "core/config/project_settings.h" +#include "core/math/quaternion.h" #include "core/os/os.h" +// #include "scene/3d/camera_3d.h" #include "rendering_server_default.h" #include "rendering_server_globals.h" @@ -55,6 +57,21 @@ void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degree camera->zfar = p_z_far; } +void RendererSceneCull::camera_set_oblique(RID p_camera, float p_fovy_degrees, const Transform3D &p_camera_gt, const Vector3 &p_ob_normal, const Vector3 &p_ob_position, float p_ob_offset, float p_z_near, float p_z_far) { + int dot = int(p_ob_normal.dot(p_ob_position - p_camera_gt.origin) >= 0.0f ? 1.0f : -1.0f); + Vector3 cam_space_pos = p_camera_gt.inverse().xform(p_ob_position); + Vector3 cam_space_normal = p_camera_gt.basis.inverse().xform(p_ob_normal) * dot; + real_t cam_space_dst = -cam_space_pos.dot(cam_space_normal) + p_ob_offset; + + Camera *camera = camera_owner.get_or_null(p_camera); + ERR_FAIL_COND(!camera); + camera->type = Camera::OBLIQUE; + camera->fov = p_fovy_degrees; + camera->oblique_plane = Plane(cam_space_normal, cam_space_dst); + camera->znear = p_z_near; + camera->zfar = p_z_far; +} + void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); @@ -2514,7 +2531,17 @@ void RendererSceneCull::render_camera(const Ref &p_render_bu camera->znear, camera->zfar, camera->vaspect); - + } break; + case Camera::OBLIQUE: { + Quaternion oblique_plane = Quaternion(camera->oblique_plane.normal.x, camera->oblique_plane.normal.y, camera->oblique_plane.normal.z, camera->oblique_plane.d); + projection.set_oblique( + camera->fov, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + oblique_plane, + camera->vaspect); + // ortho = false; ### TO REMOVE?? } break; case Camera::FRUSTUM: { projection.set_frustum( diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 106871edfd31..ddb5bb0632be 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -66,10 +66,12 @@ class RendererSceneCull : public RenderingMethod { enum Type { PERSPECTIVE, ORTHOGONAL, - FRUSTUM + FRUSTUM, + OBLIQUE }; Type type; float fov; + Plane oblique_plane; float znear, zfar; float size; Vector2 offset; @@ -98,6 +100,7 @@ class RendererSceneCull : public RenderingMethod { virtual void camera_initialize(RID p_rid); virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far); + virtual void camera_set_oblique(RID p_camera, float p_fovy_degrees, const Transform3D &p_camera_gt, const Vector3 &p_ob_normal, const Vector3 &p_ob_position, float p_ob_offset, float p_z_near, float p_z_far); virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far); virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform); diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h index e3f29b51d519..54514617e30b 100644 --- a/servers/rendering/rendering_method.h +++ b/servers/rendering/rendering_method.h @@ -41,6 +41,7 @@ class RenderingMethod { virtual void camera_initialize(RID p_rid) = 0; virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0; + virtual void camera_set_oblique(RID p_camera, float p_fovy_degrees, const Transform3D &p_camera_gt, const Vector3 &p_ob_normal, const Vector3 &p_ob_position, float p_ob_offset, float p_z_near, float p_z_far) = 0; virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0; virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0; virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 3f5b135d2a80..e7d83ca993df 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -565,6 +565,7 @@ class RenderingServerDefault : public RenderingServer { FUNCRIDSPLIT(camera) FUNC4(camera_set_perspective, RID, float, float, float) + FUNC8(camera_set_oblique, RID, float, const Transform3D &, const Vector3 &, const Vector3 &, float, float, float) FUNC4(camera_set_orthogonal, RID, float, float, float) FUNC5(camera_set_frustum, RID, float, Vector2, float, float) FUNC2(camera_set_transform, RID, const Transform3D &) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index de3bd8d3e04d..24c1c7e66d2c 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2170,6 +2170,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("camera_create"), &RenderingServer::camera_create); ClassDB::bind_method(D_METHOD("camera_set_perspective", "camera", "fovy_degrees", "z_near", "z_far"), &RenderingServer::camera_set_perspective); + ClassDB::bind_method(D_METHOD("camera_set_oblique", "camera", "fovy_degrees", "camera_gt", "oblique_normal", "oblique_position", "oblique_offset", "z_near", "z_far"), &RenderingServer::camera_set_oblique); ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &RenderingServer::camera_set_orthogonal); ClassDB::bind_method(D_METHOD("camera_set_frustum", "camera", "size", "offset", "z_near", "z_far"), &RenderingServer::camera_set_frustum); ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &RenderingServer::camera_set_transform); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index f3d95e07cbf8..82b358b69204 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -768,6 +768,7 @@ class RenderingServer : public Object { virtual RID camera_create() = 0; virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0; + virtual void camera_set_oblique(RID p_camera, float p_fovy_degrees, const Transform3D &p_camera_gt, const Vector3 &p_ob_normal, const Vector3 &p_ob_position, float p_ob_offset, float p_z_near, float p_z_far) = 0; virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0; virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0; virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0;