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;