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;