-
-
Notifications
You must be signed in to change notification settings - Fork 25.4k
Add Custom Projection to Camera3D #84454
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -104,14 +104,16 @@ void Camera3D::_update_camera_mode() { | |||||||||||||||||||||||||||||||||||||||||
| switch (mode) { | ||||||||||||||||||||||||||||||||||||||||||
| case PROJECTION_PERSPECTIVE: { | ||||||||||||||||||||||||||||||||||||||||||
| set_perspective(fov, _near, _far); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| } break; | ||||||||||||||||||||||||||||||||||||||||||
| case PROJECTION_ORTHOGONAL: { | ||||||||||||||||||||||||||||||||||||||||||
| set_orthogonal(size, _near, _far); | ||||||||||||||||||||||||||||||||||||||||||
| } break; | ||||||||||||||||||||||||||||||||||||||||||
| case PROJECTION_FRUSTUM: { | ||||||||||||||||||||||||||||||||||||||||||
| set_frustum(size, frustum_offset, _near, _far); | ||||||||||||||||||||||||||||||||||||||||||
| } break; | ||||||||||||||||||||||||||||||||||||||||||
| case PROJECTION_CUSTOM: { | ||||||||||||||||||||||||||||||||||||||||||
| set_custom(c_proj); | ||||||||||||||||||||||||||||||||||||||||||
| } break; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| fti_notify_node_changed(false); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -131,6 +133,18 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const { | |||||||||||||||||||||||||||||||||||||||||
| p_property.usage = PROPERTY_USAGE_NO_EDITOR; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } else if (p_property.name == "custom_projection") { | ||||||||||||||||||||||||||||||||||||||||||
| if (mode != PROJECTION_CUSTOM) { | ||||||||||||||||||||||||||||||||||||||||||
| p_property.usage = PROPERTY_USAGE_NO_EDITOR; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } else if (p_property.name == "near") { | ||||||||||||||||||||||||||||||||||||||||||
| if (mode == PROJECTION_CUSTOM) { | ||||||||||||||||||||||||||||||||||||||||||
| p_property.usage = PROPERTY_USAGE_NO_EDITOR; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } else if (p_property.name == "far") { | ||||||||||||||||||||||||||||||||||||||||||
| if (mode == PROJECTION_CUSTOM) { | ||||||||||||||||||||||||||||||||||||||||||
| p_property.usage = PROPERTY_USAGE_NO_EDITOR; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (attributes.is_valid()) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -279,6 +293,9 @@ Projection Camera3D::_get_camera_projection(real_t p_near) const { | |||||||||||||||||||||||||||||||||||||||||
| case PROJECTION_FRUSTUM: { | ||||||||||||||||||||||||||||||||||||||||||
| cm.set_frustum(size, viewport_size.aspect(), frustum_offset, p_near, _far); | ||||||||||||||||||||||||||||||||||||||||||
| } break; | ||||||||||||||||||||||||||||||||||||||||||
| case PROJECTION_CUSTOM: { | ||||||||||||||||||||||||||||||||||||||||||
| cm = c_proj; | ||||||||||||||||||||||||||||||||||||||||||
| } break; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return cm; | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -337,8 +354,44 @@ void Camera3D::set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, rea | |||||||||||||||||||||||||||||||||||||||||
| update_gizmos(); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| void Camera3D::set_custom(Projection p_proj) { | ||||||||||||||||||||||||||||||||||||||||||
| if (!force_change && c_proj == p_proj) { | ||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| c_proj = p_proj; | ||||||||||||||||||||||||||||||||||||||||||
| mode = PROJECTION_CUSTOM; | ||||||||||||||||||||||||||||||||||||||||||
| force_change = false; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Vector<Plane> planes = c_proj.get_projection_planes(Transform3D()); | ||||||||||||||||||||||||||||||||||||||||||
| const Projection::Planes intersections[8][3] = { | ||||||||||||||||||||||||||||||||||||||||||
| { Projection::PLANE_FAR, Projection::PLANE_LEFT, Projection::PLANE_TOP }, | ||||||||||||||||||||||||||||||||||||||||||
| { Projection::PLANE_FAR, Projection::PLANE_LEFT, Projection::PLANE_BOTTOM }, | ||||||||||||||||||||||||||||||||||||||||||
| { Projection::PLANE_FAR, Projection::PLANE_RIGHT, Projection::PLANE_TOP }, | ||||||||||||||||||||||||||||||||||||||||||
| { Projection::PLANE_FAR, Projection::PLANE_RIGHT, Projection::PLANE_BOTTOM }, | ||||||||||||||||||||||||||||||||||||||||||
| { Projection::PLANE_NEAR, Projection::PLANE_LEFT, Projection::PLANE_TOP }, | ||||||||||||||||||||||||||||||||||||||||||
| { Projection::PLANE_NEAR, Projection::PLANE_LEFT, Projection::PLANE_BOTTOM }, | ||||||||||||||||||||||||||||||||||||||||||
| { Projection::PLANE_NEAR, Projection::PLANE_RIGHT, Projection::PLANE_TOP }, | ||||||||||||||||||||||||||||||||||||||||||
| { Projection::PLANE_NEAR, Projection::PLANE_RIGHT, Projection::PLANE_BOTTOM }, | ||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| for (int i = 0; i < 8; i++) { | ||||||||||||||||||||||||||||||||||||||||||
| Plane a = planes[intersections[i][0]]; | ||||||||||||||||||||||||||||||||||||||||||
| Plane b = planes[intersections[i][1]]; | ||||||||||||||||||||||||||||||||||||||||||
| Plane c = planes[intersections[i][2]]; | ||||||||||||||||||||||||||||||||||||||||||
| ERR_FAIL_COND_MSG(!a.intersect_3(b, c), "Camera3D custom projection has non-intersecting planes; skipping update."); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+366
to
+383
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My bad! I think this check should be in Edit: Okay actually I'm not too sure if changing this makes sense, since moving it before
Suggested change
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Separately, it seems that for testing only the planes for FWIW you can replicate the error without a custom projection by setting a funky transform (e.g. scale = 0), which isn't guarded against, so I also have to wonder if it makes sense to guard against weird projections in the first place. |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| RenderingServer::get_singleton()->camera_set_custom(camera, c_proj); | ||||||||||||||||||||||||||||||||||||||||||
| update_gizmos(); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| void Camera3D::set_projection(ProjectionType p_mode) { | ||||||||||||||||||||||||||||||||||||||||||
| if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) { | ||||||||||||||||||||||||||||||||||||||||||
| if (p_mode == PROJECTION_CUSTOM && mode != PROJECTION_CUSTOM && is_inside_tree()) { | ||||||||||||||||||||||||||||||||||||||||||
| c_proj = get_camera_projection(); | ||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't always work as expected in the editor1. However, it works fine at runtime. I do wonder if it is better not to set the custom projection this way though, and instead let it keep its existing value, since it is trivial to retain the existing projection anyway, and most of the time when setting a custom projection it's something not possible with the other projection modes. Footnotes
|
||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM || p_mode == PROJECTION_CUSTOM) { | ||||||||||||||||||||||||||||||||||||||||||
| mode = p_mode; | ||||||||||||||||||||||||||||||||||||||||||
| _update_camera_mode(); | ||||||||||||||||||||||||||||||||||||||||||
| notify_property_list_changed(); | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -404,6 +457,9 @@ Vector3 Camera3D::project_local_ray_normal(const Point2 &p_pos) const { | |||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (mode == PROJECTION_ORTHOGONAL) { | ||||||||||||||||||||||||||||||||||||||||||
| ray = Vector3(0, 0, -1); | ||||||||||||||||||||||||||||||||||||||||||
| } else if (mode == PROJECTION_CUSTOM) { | ||||||||||||||||||||||||||||||||||||||||||
| Vector3 from; | ||||||||||||||||||||||||||||||||||||||||||
| _get_camera_projection(_near).project_origin_and_ray(p_pos, viewport_size, from, ray); | ||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||
| Projection cm = _get_camera_projection(_near); | ||||||||||||||||||||||||||||||||||||||||||
| Vector2 screen_he = cm.get_viewport_half_extents(); | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -420,6 +476,8 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const { | |||||||||||||||||||||||||||||||||||||||||
| Vector2 cpos = get_viewport()->get_camera_coords(p_pos); | ||||||||||||||||||||||||||||||||||||||||||
| ERR_FAIL_COND_V(viewport_size.y == 0, Vector3()); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Vector3 origin; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (mode == PROJECTION_ORTHOGONAL) { | ||||||||||||||||||||||||||||||||||||||||||
| Vector2 pos = cpos / viewport_size; | ||||||||||||||||||||||||||||||||||||||||||
| real_t vsize, hsize; | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -436,10 +494,18 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const { | |||||||||||||||||||||||||||||||||||||||||
| ray.y = (1.0 - pos.y) * (vsize)-vsize / 2; | ||||||||||||||||||||||||||||||||||||||||||
| ray.z = -_near; | ||||||||||||||||||||||||||||||||||||||||||
| ray = get_camera_transform().xform(ray); | ||||||||||||||||||||||||||||||||||||||||||
| return ray; | ||||||||||||||||||||||||||||||||||||||||||
| origin = ray; | ||||||||||||||||||||||||||||||||||||||||||
| } else if (mode == PROJECTION_CUSTOM) { | ||||||||||||||||||||||||||||||||||||||||||
| Vector3 from; | ||||||||||||||||||||||||||||||||||||||||||
| Vector3 ray; | ||||||||||||||||||||||||||||||||||||||||||
| _get_camera_projection(_near).project_origin_and_ray(p_pos, viewport_size, from, ray); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| origin = get_camera_transform().xform(from); | ||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||
| return get_camera_transform().origin; | ||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||
| origin = get_camera_transform().origin; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return origin; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| bool Camera3D::is_position_behind(const Vector3 &p_pos) const { | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -623,6 +689,7 @@ void Camera3D::_bind_methods() { | |||||||||||||||||||||||||||||||||||||||||
| ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera3D::set_perspective); | ||||||||||||||||||||||||||||||||||||||||||
| 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("set_custom_projection", "p_proj"), &Camera3D::set_custom_projection); | ||||||||||||||||||||||||||||||||||||||||||
| ClassDB::bind_method(D_METHOD("make_current"), &Camera3D::make_current); | ||||||||||||||||||||||||||||||||||||||||||
| ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera3D::clear_current, DEFVAL(true)); | ||||||||||||||||||||||||||||||||||||||||||
| ClassDB::bind_method(D_METHOD("set_current", "enabled"), &Camera3D::set_current); | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -633,6 +700,7 @@ void Camera3D::_bind_methods() { | |||||||||||||||||||||||||||||||||||||||||
| 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_custom_projection"), &Camera3D::get_custom_projection); | ||||||||||||||||||||||||||||||||||||||||||
| 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_frustum_offset", "offset"), &Camera3D::set_frustum_offset); | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -677,17 +745,19 @@ 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,Custom"), "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,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"); | ||||||||||||||||||||||||||||||||||||||||||
| 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::PROJECTION, "custom_projection"), "set_custom_projection", "get_custom_projection"); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); | ||||||||||||||||||||||||||||||||||||||||||
| BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL); | ||||||||||||||||||||||||||||||||||||||||||
| BIND_ENUM_CONSTANT(PROJECTION_FRUSTUM); | ||||||||||||||||||||||||||||||||||||||||||
| BIND_ENUM_CONSTANT(PROJECTION_CUSTOM); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| BIND_ENUM_CONSTANT(KEEP_WIDTH); | ||||||||||||||||||||||||||||||||||||||||||
| BIND_ENUM_CONSTANT(KEEP_HEIGHT); | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -717,6 +787,10 @@ real_t Camera3D::get_far() const { | |||||||||||||||||||||||||||||||||||||||||
| return _far; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Projection Camera3D::get_custom_projection() const { | ||||||||||||||||||||||||||||||||||||||||||
| return c_proj; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Camera3D::ProjectionType Camera3D::get_projection() const { | ||||||||||||||||||||||||||||||||||||||||||
| return mode; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -748,6 +822,11 @@ void Camera3D::set_far(real_t p_far) { | |||||||||||||||||||||||||||||||||||||||||
| _update_camera_mode(); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| void Camera3D::set_custom_projection(Projection p_proj) { | ||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refer to the other comment.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
| c_proj = p_proj; | ||||||||||||||||||||||||||||||||||||||||||
| _update_camera_mode(); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| void Camera3D::set_cull_mask(uint32_t p_layers) { | ||||||||||||||||||||||||||||||||||||||||||
| layers = p_layers; | ||||||||||||||||||||||||||||||||||||||||||
| RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Referring to lines 79-153)
I think these need to be updated somehow, but am not really sure how.