From 7e3c501c36cb93c393b3276b1d56102f418dae37 Mon Sep 17 00:00:00 2001 From: Lyuma Date: Wed, 14 Dec 2022 03:50:11 -0800 Subject: [PATCH] Permit overriding the projection matrix passed to shaders without affecting culling logic. --- doc/classes/Camera3D.xml | 6 ++++++ doc/classes/RenderingServer.xml | 11 +++++++++++ drivers/gles3/rasterizer_scene_gles3.cpp | 2 +- scene/3d/camera_3d.cpp | 13 +++++++++++++ scene/3d/camera_3d.h | 3 +++ .../renderer_rd/storage_rd/render_scene_data_rd.cpp | 4 ++-- servers/rendering/renderer_scene_cull.cpp | 12 ++++++++++++ servers/rendering/renderer_scene_cull.h | 5 +++++ servers/rendering/renderer_scene_render.cpp | 6 ++++++ servers/rendering/renderer_scene_render.h | 1 + servers/rendering/rendering_method.h | 1 + servers/rendering/rendering_server_default.h | 1 + servers/rendering_server.cpp | 1 + servers/rendering_server.h | 1 + 14 files changed, 64 insertions(+), 3 deletions(-) diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index 27194122d56..db8d3208626 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -202,6 +202,12 @@ 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. + + If set to a non-zero Projection, overrides the view-projection matrix passed to shaders with this custom matrix. This *only* overrides the projection passed to shaders on the GPU. The [constant PROJECTION_PERSPECTIVE], [constant PROJECTION_ORTHOGONAL] or [constant PROJECTION_FRUSTUM] values are still used for CPU-side operations such as culling, which can be used to provide a separate culling frustum. + To clear the overridden projection, set to [code]Projection(Vector4.ZERO, Vector4.ZERO, Vector4.ZERO, Vector4.ZERO)[/code]. + + [member override_projection] does not currently support stereo cameras. + The camera's projection mode. In [constant PROJECTION_PERSPECTIVE] mode, objects' Z distance from the camera's local space scales their perceived size. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 3c9f0fc7aff..f727cb41f7b 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -163,6 +163,17 @@ Sets camera to use orthogonal projection, also known as orthographic projection. Objects remain the same size on the screen no matter how far away they are. + + + + + + If set to a non-zero Projection, overrides the view-projection matrix passed to shaders with this custom matrix. This *only* overrides the projection passed to shaders on the GPU. The [method camera_set_frustum], [method camera_set_orthogonal] or [method camera_set_frustum] values are still used for CPU-side operations such as culling, which can be used to provide a separate culling frustum. + To clear the overridden projection, set to [code]Projection(Vector4.ZERO, Vector4.ZERO, Vector4.ZERO, Vector4.ZERO)[/code]. + + [method camera_set_override_projection] does not currently support stereo cameras. + + diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 6cbdf5e9350..96189a6d3a4 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1460,7 +1460,7 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows, float p_shadow_bias) { Projection correction; correction.set_depth_correction(p_flip_y, true, false); - Projection projection = correction * p_render_data->cam_projection; + Projection projection = correction * p_render_data->view_projection[0]; //store camera into ubo GLES3::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix); GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 8515aacba7c..03d877b8076 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -240,6 +240,15 @@ void Camera3D::set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, rea update_gizmos(); } +Projection Camera3D::get_override_projection() const { + return override_projection; +} + +void Camera3D::set_override_projection(const Projection &p_matrix) { + override_projection = p_matrix; + RenderingServer::get_singleton()->camera_set_override_projection(camera, override_projection); +} + void Camera3D::set_projection(ProjectionType p_mode) { if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) { mode = p_mode; @@ -536,6 +545,8 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_near", "near"), &Camera3D::set_near); ClassDB::bind_method(D_METHOD("get_projection"), &Camera3D::get_projection); ClassDB::bind_method(D_METHOD("set_projection", "mode"), &Camera3D::set_projection); + ClassDB::bind_method(D_METHOD("get_override_projection"), &Camera3D::get_override_projection); + ClassDB::bind_method(D_METHOD("set_override_projection", "projection_matrix"), &Camera3D::set_override_projection); ClassDB::bind_method(D_METHOD("set_h_offset", "offset"), &Camera3D::set_h_offset); ClassDB::bind_method(D_METHOD("get_h_offset"), &Camera3D::get_h_offset); ClassDB::bind_method(D_METHOD("set_v_offset", "offset"), &Camera3D::set_v_offset); @@ -571,6 +582,7 @@ void Camera3D::_bind_methods() { 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::PROJECTION, "override_projection"), "set_override_projection", "get_override_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,100,0.001,or_greater,suffix:m"), "set_size", "get_size"); @@ -748,6 +760,7 @@ RID Camera3D::get_pyramid_shape_rid() { Camera3D::Camera3D() { camera = RenderingServer::get_singleton()->camera_create(); + override_projection.set_zero(); set_perspective(75.0, 0.05, 4000.0); RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers); //active=false; diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index dbf2ffc1dd0..2d34a26e4a4 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -74,6 +74,7 @@ class Camera3D : public Node3D { real_t v_offset = 0.0; real_t h_offset = 0.0; KeepAspect keep_aspect = KEEP_HEIGHT; + Projection override_projection; RID camera; RID scenario_id; @@ -133,6 +134,7 @@ class Camera3D : public Node3D { real_t get_far() const; real_t get_near() const; Vector2 get_frustum_offset() const; + Projection get_override_projection() const; ProjectionType get_projection() const; @@ -141,6 +143,7 @@ class Camera3D : public Node3D { void set_far(real_t p_far); void set_near(real_t p_near); void set_frustum_offset(Vector2 p_offset); + void set_override_projection(const Projection &p_matrix); virtual Transform3D get_camera_transform() const; virtual Projection get_camera_projection() const; diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp index dc1e64ddcc2..f06895e6c12 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp @@ -78,7 +78,7 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p Projection correction; correction.set_depth_correction(p_flip_y); correction.add_jitter_offset(taa_jitter); - Projection projection = correction * cam_projection; + Projection projection = correction * view_projection[0]; //store camera into ubo RendererRD::MaterialStorage::store_camera(projection, ubo.projection_matrix); @@ -261,7 +261,7 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p Projection prev_correction; prev_correction.set_depth_correction(true); prev_correction.add_jitter_offset(prev_taa_jitter); - Projection prev_projection = prev_correction * prev_cam_projection; + Projection prev_projection = prev_correction * view_projection[0]; //store camera into ubo RendererRD::MaterialStorage::store_camera(prev_projection, prev_ubo.projection_matrix); diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index b02d3def88f..61230ab1144 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -90,6 +90,15 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p camera->zfar = p_z_far; } +void RendererSceneCull::camera_set_override_projection(RID p_camera, const Projection &p_matrix) { + Camera *camera = camera_owner.get_or_null(p_camera); + ERR_FAIL_COND(!camera); + Projection zero; + zero.set_zero(); + camera->has_override_projection = (p_matrix != zero); + camera->override_projection = p_matrix; +} + void RendererSceneCull::camera_set_transform(RID p_camera, const Transform3D &p_transform) { Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_NULL(camera); @@ -2607,6 +2616,9 @@ void RendererSceneCull::render_camera(const Ref &p_render_bu } camera_data.set_camera(transform, projection, is_orthogonal, vaspect, jitter, camera->visible_layers); + if (camera->has_override_projection) { + camera_data.set_override_projection(camera->override_projection); + } } else { // Setup our camera for our XR interface. // We can support multiple views here each with their own camera diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 0039d144751..4a1e80bd611 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -81,11 +81,13 @@ class RendererSceneCull : public RenderingMethod { Vector2 offset; uint32_t visible_layers; bool vaspect; + bool has_override_projection; RID env; RID attributes; RID compositor; Transform3D transform; + Projection override_projection; Camera() { visible_layers = 0xFFFFFFFF; @@ -96,6 +98,8 @@ class RendererSceneCull : public RenderingMethod { size = 1.0; offset = Vector2(); vaspect = false; + has_override_projection = false; + override_projection.set_zero(); } }; @@ -107,6 +111,7 @@ class RendererSceneCull : public RenderingMethod { virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, 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_override_projection(RID p_camera, const Projection &p_matrix); virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform); virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers); virtual void camera_set_environment(RID p_camera, RID p_env); diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp index 76c779900fb..d1290e2beb2 100644 --- a/servers/rendering/renderer_scene_render.cpp +++ b/servers/rendering/renderer_scene_render.cpp @@ -47,6 +47,12 @@ void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, taa_jitter = p_taa_jitter; } +void RendererSceneRender::CameraData::set_override_projection(const Projection &p_projection) { + if (view_count == 1) { + view_projection[0] = p_projection; + } +} + void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect) { ERR_FAIL_COND_MSG(p_view_count != 2, "Incorrect view count for stereoscopic view"); diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 719efa4df22..59b9fafcb5d 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -309,6 +309,7 @@ class RendererSceneRender { 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_override_projection(const Projection &p_projection); 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 aa5e7d83cc8..5f903b6c94f 100644 --- a/servers/rendering/rendering_method.h +++ b/servers/rendering/rendering_method.h @@ -50,6 +50,7 @@ class RenderingMethod { 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_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_override_projection(RID p_camera, const Projection &p_matrix) = 0; virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0; virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0; virtual void camera_set_environment(RID p_camera, RID p_env) = 0; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 164ec3cc09f..242728c81b2 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -582,6 +582,7 @@ class RenderingServerDefault : public RenderingServer { FUNC4(camera_set_perspective, RID, float, float, float) FUNC4(camera_set_orthogonal, RID, float, float, float) FUNC5(camera_set_frustum, RID, float, Vector2, float, float) + FUNC2(camera_set_override_projection, RID, const Projection &) FUNC2(camera_set_transform, RID, const Transform3D &) FUNC2(camera_set_cull_mask, RID, uint32_t) FUNC2(camera_set_environment, RID, RID) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 7637d4e7da2..9401075e7ae 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2756,6 +2756,7 @@ void RenderingServer::_bind_methods() { 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_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_override_projection", "camera", "matrix"), &RenderingServer::camera_set_override_projection); ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &RenderingServer::camera_set_transform); ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &RenderingServer::camera_set_cull_mask); ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &RenderingServer::camera_set_environment); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index e15dba43536..424b8c37c4d 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -842,6 +842,7 @@ class RenderingServer : public Object { 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_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_override_projection(RID p_camera, const Projection &p_matrix) = 0; virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0; virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0; virtual void camera_set_environment(RID p_camera, RID p_env) = 0;