diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index 9d5dc8b4d609..29b27eb5c0e5 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -93,6 +93,24 @@ Vector4 Projection::xform_inv(const Vector4 &p_vec4) const {
columns[3][0] * p_vec4.x + columns[3][1] * p_vec4.y + columns[3][2] * p_vec4.z + columns[3][3] * p_vec4.w);
}
+void Projection::apply_oblique_plane(Vector4 p_oblique_plane) {
+ // Here goes oblique magic!
+ // Eric Lengyel Solution: http://terathon.com/code/oblique.html
+ Vector4 q;
+
+ q.x = (SIGN(p_oblique_plane.x) + columns[2][0]) / columns[0][0];
+ q.y = (SIGN(p_oblique_plane.y) + columns[2][1]) / columns[1][1];
+
+ q.z = -1.0F;
+ q.w = (1.0F + columns[2][2]) / columns[3][2];
+
+ Vector4 c = p_oblique_plane * (2.0F / p_oblique_plane.dot(q));
+ columns[0][2] = c.x - columns[0][3];
+ columns[1][2] = c.y - columns[1][3];
+ columns[2][2] = c.z - columns[2][3];
+ columns[3][2] = c.w - columns[3][3];
+}
+
void Projection::adjust_perspective_znear(real_t p_new_znear) {
real_t zfar = get_z_far();
real_t znear = p_new_znear;
diff --git a/core/math/projection.h b/core/math/projection.h
index a7adc9017ed9..4f1956407d57 100644
--- a/core/math/projection.h
+++ b/core/math/projection.h
@@ -79,6 +79,7 @@ struct _NO_DISCARD_ Projection {
void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
+ void apply_oblique_plane(Vector4 p_oblique_plane);
void adjust_perspective_znear(real_t p_new_znear);
static Projection create_depth_correction(bool p_flip_y);
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index 01890b471c3b..72a5944182af 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -122,6 +122,13 @@
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 [member oblique_normal] and [member oblique_position] values of an oblique projection camera using a the origin and forward vector of the transform argument. For ease of using plane meshes as portals and mirrors.
+
+
@@ -202,12 +209,24 @@
The distance to the near culling boundary for this camera relative to its local Z axis. Lower values allow the camera to see objects more up close to its origin, at the cost of lower precision across the [i]entire[/i] range. Values lower than the default can lead to increased Z-fighting.
+
+ The desired normal vector of the world space plane used by an oblique camera as an oblique near clipping plane.
+
+
+ The offset value for the oblique plane along its 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.
The camera's size in meters measured as the diameter of the width or height, depending on [member keep_aspect]. Only applicable in orthogonal and frustum modes.
+
+ Toggle for applying oblique near plane frustum culling.
+
The vertical (Y) offset of the camera viewport.
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 152518e7da97..ab3bdedfaed0 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -93,7 +93,7 @@
The normalization factor can be calculated from exposure value (EV100) as follows:
[codeblock]
func get_exposure_normalization(float ev100):
- return 1.0 / (pow(2.0, ev100) * 1.2)
+ return 1.0 / (pow(2.0, ev100) * 1.2)
[/codeblock]
The exposure value can be calculated from aperture (in f-stops), shutter speed (in seconds), and sensitivity (in ISO) as follows:
[codeblock]
@@ -153,6 +153,17 @@
Sets camera to use frustum projection. This mode allows adjusting the [param offset] argument to create "tilted frustum" effects.
+
+
+
+
+
+
+
+
+ Sets the camera to use oblique near plane frustum culling.
+
+
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index e8bd498e1fc1..b869a1694d72 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -45,7 +45,6 @@ void Camera3D::_update_camera_mode() {
switch (mode) {
case PROJECTION_PERSPECTIVE: {
set_perspective(fov, _near, _far);
-
} break;
case PROJECTION_ORTHOGONAL: {
set_orthogonal(size, _near, _far);
@@ -69,6 +68,14 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const {
if (mode != PROJECTION_FRUSTUM) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
+ } else if (p_property.name == "use_oblique_frustum") {
+ if (mode != PROJECTION_PERSPECTIVE && mode != PROJECTION_ORTHOGONAL) {
+ 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 (use_oblique_frustum == false) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
if (attributes.is_valid()) {
@@ -175,6 +182,9 @@ Projection Camera3D::_get_camera_projection(real_t p_near) const {
switch (mode) {
case PROJECTION_PERSPECTIVE: {
cm.set_perspective(fov, viewport_size.aspect(), p_near, _far, keep_aspect == KEEP_WIDTH);
+ if (use_oblique_frustum) {
+ cm.apply_oblique_plane(_get_oblique_plane());
+ }
} break;
case PROJECTION_ORTHOGONAL: {
cm.set_orthogonal(size, viewport_size.aspect(), p_near, _far, keep_aspect == KEEP_WIDTH);
@@ -192,6 +202,16 @@ Projection Camera3D::get_camera_projection() const {
return _get_camera_projection(_near);
}
+Vector4 Camera3D::_get_oblique_plane() const {
+ Transform3D transform = get_global_transform();
+ int dot = int(oblique_normal.dot(oblique_position - transform.origin) >= 0.0f ? 1.0f : -1.0f);
+ Vector3 cam_space_pos = transform.xform_inv(oblique_position);
+ Vector3 cam_space_normal = transform.basis.xform_inv(oblique_normal) * dot;
+ real_t cam_space_dst = -cam_space_pos.dot(cam_space_normal) + oblique_offset;
+
+ return Vector4(cam_space_normal.x, cam_space_normal.y, cam_space_normal.z, cam_space_dst);
+}
+
void Camera3D::set_perspective(real_t p_fovy_degrees, 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_PERSPECTIVE) {
return;
@@ -203,6 +223,7 @@ void Camera3D::set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_
mode = PROJECTION_PERSPECTIVE;
RenderingServer::get_singleton()->camera_set_perspective(camera, fov, _near, _far);
+ RenderingServer::get_singleton()->camera_set_oblique_plane(camera, use_oblique_frustum, oblique_normal, oblique_position, oblique_offset);
update_gizmos();
force_change = false;
}
@@ -220,6 +241,7 @@ void Camera3D::set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) {
force_change = false;
RenderingServer::get_singleton()->camera_set_orthogonal(camera, size, _near, _far);
+ RenderingServer::get_singleton()->camera_set_oblique_plane(camera, use_oblique_frustum, oblique_normal, oblique_position, oblique_offset);
update_gizmos();
}
@@ -240,7 +262,7 @@ 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) {
+void Camera3D::set_projection(Camera3D::ProjectionType p_mode) {
if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) {
mode = p_mode;
_update_camera_mode();
@@ -525,11 +547,20 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera3D::get_camera_transform);
ClassDB::bind_method(D_METHOD("get_camera_projection"), &Camera3D::get_camera_projection);
ClassDB::bind_method(D_METHOD("get_fov"), &Camera3D::get_fov);
+ ClassDB::bind_method(D_METHOD("get_use_oblique_frustum"), &Camera3D::get_use_oblique_frustum);
+ 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_use_oblique_frustum", "use_oblique_normal"), &Camera3D::set_use_oblique_frustum);
+ 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);
@@ -573,6 +604,10 @@ void Camera3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "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::BOOL, "use_oblique_frustum"), "set_use_oblique_frustum", "get_use_oblique_frustum");
+ 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,100,0.001,or_greater,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");
@@ -594,6 +629,22 @@ real_t Camera3D::get_fov() const {
return fov;
}
+bool Camera3D::get_use_oblique_frustum() const {
+ return use_oblique_frustum;
+}
+
+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;
}
@@ -620,6 +671,33 @@ void Camera3D::set_fov(real_t p_fov) {
_update_camera_mode();
}
+void Camera3D::set_use_oblique_frustum(bool p_use_oblique_frustum) {
+ use_oblique_frustum = p_use_oblique_frustum;
+ _update_camera_mode();
+ notify_property_list_changed();
+}
+
+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) {
+ oblique_normal = -p_oblique_transform.basis.get_column(2);
+ oblique_position = p_oblique_transform.origin;
+ _update_camera_mode();
+}
+
void Camera3D::set_size(real_t p_size) {
ERR_FAIL_COND(p_size <= CMP_EPSILON);
size = p_size;
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index dbf2ffc1dd06..0dbdbe89574a 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -66,6 +66,10 @@ class Camera3D : public Node3D {
ProjectionType mode = PROJECTION_PERSPECTIVE;
real_t fov = 75.0;
+ bool use_oblique_frustum = false;
+ Vector3 oblique_normal = Vector3(0, 1, 0);
+ Vector3 oblique_position = Vector3();
+ real_t oblique_offset = 0;
real_t size = 1.0;
Vector2 frustum_offset;
// _ prefix to avoid conflict with Windows defines.
@@ -109,6 +113,7 @@ class Camera3D : public Node3D {
static void _bind_methods();
Projection _get_camera_projection(real_t p_near) const;
+ Vector4 _get_oblique_plane() const;
public:
enum {
@@ -129,6 +134,10 @@ class Camera3D : public Node3D {
RID get_camera() const;
real_t get_fov() const;
+ bool get_use_oblique_frustum() 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;
@@ -137,6 +146,11 @@ class Camera3D : public Node3D {
ProjectionType get_projection() const;
void set_fov(real_t p_fov);
+ void set_use_oblique_frustum(bool P_use_oblique_frustum);
+ 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 aa69cd8539eb..91fbb5bb23a4 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -71,6 +71,15 @@ void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degree
camera->zfar = p_z_far;
}
+void RendererSceneCull::camera_set_oblique_plane(RID p_camera, bool p_use_oblique_frustum, const Vector3 &p_ob_normal, const Vector3 &p_ob_position, float p_ob_offset) {
+ Camera *camera = camera_owner.get_or_null(p_camera);
+ ERR_FAIL_NULL(camera);
+ camera->use_oblique_frustum = p_use_oblique_frustum;
+ camera->oblique_normal = p_ob_normal;
+ camera->oblique_position = p_ob_position;
+ camera->oblique_offset = p_ob_offset;
+}
+
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_NULL(camera);
@@ -131,6 +140,18 @@ bool RendererSceneCull::is_camera(RID p_camera) const {
return camera_owner.owns(p_camera);
}
+Vector4 RendererSceneCull::get_camera_oblique_plane(RID p_camera) {
+ Camera *camera = camera_owner.get_or_null(p_camera);
+ ERR_FAIL_NULL_V(camera, Vector4());
+
+ int dot = int(camera->oblique_normal.dot(camera->oblique_position - camera->transform.origin) >= 0.0f ? 1.0f : -1.0f);
+ Vector3 cam_space_pos = camera->transform.xform_inv(camera->oblique_position);
+ Vector3 cam_space_normal = camera->transform.basis.xform_inv(camera->oblique_normal) * dot;
+ real_t cam_space_dst = -cam_space_pos.dot(cam_space_normal) + camera->oblique_offset;
+
+ return Vector4(cam_space_normal.x, cam_space_normal.y, cam_space_normal.z, cam_space_dst);
+}
+
/* OCCLUDER API */
RID RendererSceneCull::occluder_allocate() {
@@ -2148,7 +2169,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
if (p_cam_orthogonal) {
Vector2 vp_he = p_cam_projection.get_viewport_half_extents();
-
camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
} else {
real_t fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it
@@ -2570,13 +2590,14 @@ void RendererSceneCull::render_camera(const Ref &p_render_bu
if (p_xr_interface.is_null()) {
// Normal camera
Transform3D transform = camera->transform;
- Projection projection;
+ Projection main_projection;
+ Projection shadow_projection;
bool vaspect = camera->vaspect;
bool is_orthogonal = false;
switch (camera->type) {
case Camera::ORTHOGONAL: {
- projection.set_orthogonal(
+ main_projection.set_orthogonal(
camera->size,
p_viewport_size.width / (float)p_viewport_size.height,
camera->znear,
@@ -2585,16 +2606,15 @@ void RendererSceneCull::render_camera(const Ref &p_render_bu
is_orthogonal = true;
} break;
case Camera::PERSPECTIVE: {
- projection.set_perspective(
+ main_projection.set_perspective(
camera->fov,
p_viewport_size.width / (float)p_viewport_size.height,
camera->znear,
camera->zfar,
camera->vaspect);
-
} break;
case Camera::FRUSTUM: {
- projection.set_frustum(
+ main_projection.set_frustum(
camera->size,
p_viewport_size.width / (float)p_viewport_size.height,
camera->offset,
@@ -2604,7 +2624,11 @@ void RendererSceneCull::render_camera(const Ref &p_render_bu
} break;
}
- camera_data.set_camera(transform, projection, is_orthogonal, vaspect, jitter, camera->visible_layers);
+ shadow_projection = main_projection;
+ if (camera->use_oblique_frustum) {
+ main_projection.apply_oblique_plane(get_camera_oblique_plane(p_camera));
+ }
+ camera_data.set_camera(transform, main_projection, shadow_projection, is_orthogonal, vaspect, jitter, camera->visible_layers);
} else {
// Setup our camera for our XR interface.
// We can support multiple views here each with their own camera
@@ -2626,7 +2650,7 @@ void RendererSceneCull::render_camera(const Ref &p_render_bu
}
if (view_count == 1) {
- camera_data.set_camera(transforms[0], projections[0], false, camera->vaspect, jitter, camera->visible_layers);
+ camera_data.set_camera(transforms[0], projections[0], projections[0], false, camera->vaspect, jitter, camera->visible_layers);
} else if (view_count == 2) {
camera_data.set_multiview_camera(view_count, transforms, projections, false, camera->vaspect);
} else {
@@ -3025,7 +3049,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it
// Prepare the light - camera volume culling system.
- light_culler->prepare_camera(p_camera_data->main_transform, p_camera_data->main_projection);
+ light_culler->prepare_camera(p_camera_data->main_transform, p_camera_data->shadow_projection);
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
@@ -3110,7 +3134,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
RSG::light_storage->set_directional_shadow_count(lights_with_shadow.size());
for (int i = 0; i < lights_with_shadow.size(); i++) {
- _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect);
+ _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_camera_data->main_transform, p_camera_data->shadow_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect);
}
}
@@ -3155,7 +3179,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
cull_data.visible_layers = p_visible_layers;
cull_data.render_reflection_probe = render_reflection_probe;
cull_data.occlusion_buffer = RendererSceneOcclusionCull::get_singleton()->buffer_get_ptr(p_viewport);
- cull_data.camera_matrix = &p_camera_data->main_projection;
+ cull_data.camera_matrix = &p_camera_data->shadow_projection;
cull_data.visibility_viewport_mask = scenario->viewport_visibility_masks.has(p_viewport) ? scenario->viewport_visibility_masks[p_viewport] : 0;
//#define DEBUG_CULL_TIME
#ifdef DEBUG_CULL_TIME
@@ -3233,12 +3257,12 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
{ //compute coverage
- Transform3D cam_xf = p_camera_data->main_transform;
- float zn = p_camera_data->main_projection.get_z_near();
+ Transform3D cam_xf = p_camera_data->shadow_projection;
+ float zn = p_camera_data->shadow_projection.get_z_near();
Plane p(-cam_xf.basis.get_column(2), cam_xf.origin + cam_xf.basis.get_column(2) * -zn); //camera near plane
// near plane half width and height
- Vector2 vp_half_extents = p_camera_data->main_projection.get_viewport_half_extents();
+ Vector2 vp_half_extents = p_camera_data->shadow_projection.get_viewport_half_extents();
switch (RSG::light_storage->light_get_type(ins->base)) {
case RS::LIGHT_OMNI: {
@@ -3331,7 +3355,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) {
//must redraw!
RENDER_TIMESTAMP("> Render Light3D " + itos(i));
- if (_light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_mesh_lod_threshold, p_visible_layers)) {
+ if (_light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->shadow_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_mesh_lod_threshold, p_visible_layers)) {
light->make_shadow_dirty();
}
RENDER_TIMESTAMP("< Render Light3D " + itos(i));
@@ -3467,7 +3491,7 @@ void RendererSceneCull::render_empty_scene(const Ref &p_rend
RENDER_TIMESTAMP("Render Empty 3D Scene");
RendererSceneRender::CameraData camera_data;
- camera_data.set_camera(Transform3D(), Projection(), true, false);
+ camera_data.set_camera(Transform3D(), Projection(), Projection(), false, false);
scene_render->render_scene(p_render_buffers, &camera_data, &camera_data, PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), environment, RID(), compositor, p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
#endif
@@ -3545,7 +3569,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
RENDER_TIMESTAMP("Render ReflectionProbe, Step " + itos(p_step));
RendererSceneRender::CameraData camera_data;
- camera_data.set_camera(xform, cm, false, false);
+ camera_data.set_camera(xform, cm, cm, false, false);
Ref render_buffers = RSG::light_storage->reflection_probe_atlas_get_render_buffers(scenario->reflection_atlas);
_render_scene(&camera_data, render_buffers, environment, RID(), RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, mesh_lod_threshold, use_shadows);
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 86090aa416ee..41c10c740485 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -32,6 +32,7 @@
#define RENDERER_SCENE_CULL_H
#include "core/math/dynamic_bvh.h"
+#include "core/math/vector4.h"
#include "core/templates/bin_sorted_array.h"
#include "core/templates/local_vector.h"
#include "core/templates/paged_allocator.h"
@@ -73,6 +74,12 @@ class RendererSceneCull : public RenderingMethod {
};
Type type;
float fov;
+
+ bool use_oblique_frustum;
+ Vector3 oblique_normal;
+ Vector3 oblique_position;
+ float oblique_offset;
+
float znear, zfar;
float size;
Vector2 offset;
@@ -102,6 +109,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_plane(RID p_camera, bool p_use_oblique_frustum, const Vector3 &p_ob_normal, const Vector3 &p_ob_position, float p_ob_offset);
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);
@@ -111,6 +119,7 @@ class RendererSceneCull : public RenderingMethod {
virtual void camera_set_compositor(RID p_camera, RID p_compositor);
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable);
virtual bool is_camera(RID p_camera) const;
+ virtual Vector4 get_camera_oblique_plane(RID p_camera);
/* OCCLUDER API */
diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp
index 76c779900fba..a1cdda62a076 100644
--- a/servers/rendering/renderer_scene_render.cpp
+++ b/servers/rendering/renderer_scene_render.cpp
@@ -33,17 +33,18 @@
/////////////////////////////////////////////////////////////////////////////
// CameraData
-void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_vaspect, const Vector2 &p_taa_jitter, const uint32_t p_visible_layers) {
+void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const Projection p_main_projection, const Projection p_shadow_projection, bool p_is_orthogonal, bool p_vaspect, const Vector2 &p_taa_jitter, const uint32_t p_visible_layers) {
view_count = 1;
is_orthogonal = p_is_orthogonal;
vaspect = p_vaspect;
main_transform = p_transform;
- main_projection = p_projection;
+ main_projection = p_main_projection;
+ shadow_projection = p_shadow_projection;
visible_layers = p_visible_layers;
view_offset[0] = Transform3D();
- view_projection[0] = p_projection;
+ view_projection[0] = p_main_projection;
taa_jitter = p_taa_jitter;
}
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 719efa4df228..8b34f6a241e5 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -303,12 +303,13 @@ class RendererSceneRender {
// Main/center projection
Transform3D main_transform;
Projection main_projection;
+ Projection shadow_projection;
Transform3D view_offset[RendererSceneRender::MAX_RENDER_VIEWS];
Projection view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
Vector2 taa_jitter;
- void set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_vaspect, const Vector2 &p_taa_jitter = Vector2(), uint32_t p_visible_layers = 0xFFFFFFFF);
+ void set_camera(const Transform3D p_transform, const Projection p_main_projection, const Projection p_shadow_projection, bool p_is_orthogonal, bool p_vaspect, const Vector2 &p_taa_jitter = Vector2(), uint32_t p_visible_layers = 0xFFFFFFFF);
void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect);
};
diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h
index 456984675279..6604934c87fb 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_plane(RID p_camera, bool p_use_ob_frustum, const Vector3 &p_ob_normal, const Vector3 &p_ob_position, float p_ob_offset) = 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 99fd683e1d4d..181517166b08 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -585,6 +585,7 @@ class RenderingServerDefault : public RenderingServer {
FUNCRIDSPLIT(camera)
FUNC4(camera_set_perspective, RID, float, float, float)
+ FUNC5(camera_set_oblique_plane, RID, bool, const Vector3 &, const Vector3 &, 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 1ed04248392f..8db90e2ba926 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2758,6 +2758,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_plane", "camera", "use_oblique_frustum", "oblique_normal", "oblique_position", "oblique_offset"), &RenderingServer::camera_set_oblique_plane);
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 a67ae0a66ca2..ed141dd9d874 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -810,6 +810,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_plane(RID p_camera, bool p_use_ob_frustum, const Vector3 &p_ob_normal, const Vector3 &p_ob_position, float p_ob_offset) = 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;