Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions core/math/projection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,28 @@ void Projection::add_jitter_offset(const Vector2 &p_offset) {
columns[3][1] += p_offset.y;
}

void Projection::project_origin_and_ray(const Vector2 &p_screen_pos, const Vector2 &p_screen_size, Vector3 &r_origin, Vector3 &r_ray) const {
// Use full matrix.
Projection inv_cm = inverse();

// Clip-Space point in near plane.
Vector4 clip_near(
(2.0 * p_screen_pos.x) / p_screen_size.width - 1.0,
1.0 - (2.0 * p_screen_pos.y) / p_screen_size.height,
-1.0, // Near plane in OpenGL clip space.
1.0);

Vector4 view_near = inv_cm.xform(clip_near);
r_origin = Vector3(view_near.x, view_near.y, view_near.z) / view_near.w;

Vector4 clip_adv = clip_near;
clip_adv.z = 1.0;

Vector4 view_adv = inv_cm.xform(clip_adv);
Vector3 point_adv = Vector3(view_adv.x, view_adv.y, view_adv.z) / view_adv.w;
r_ray = (point_adv - r_origin).normalized();
}

Projection::operator Transform3D() const {
Transform3D tr;
const real_t *m = &columns[0][0];
Expand Down
3 changes: 3 additions & 0 deletions core/math/projection.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ struct [[nodiscard]] Projection {
Vector2 get_viewport_half_extents() const;
Vector2 get_far_plane_half_extents() const;

// Used for generic ray picking in any matrix.
void project_origin_and_ray(const Vector2 &p_screen_pos, const Vector2 &p_screen_size, Vector3 &r_origin, Vector3 &r_ray) const;

void invert();
Projection inverse() const;

Expand Down
7 changes: 7 additions & 0 deletions doc/classes/Camera3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@
If [code]true[/code], the ancestor [Viewport] is currently using this camera.
If multiple cameras are in the scene, one will always be made current. For example, if two [Camera3D] nodes are present in the scene and only one is current, setting one camera's [member current] to [code]false[/code] will cause the other camera to be made current.
</member>
<member name="custom_projection" type="Projection" setter="set_custom_projection" getter="get_custom_projection" default="Projection(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)">
The camera's [Projection]. This can be changed from the default to apply custom projection matrix.
[b]Note:[/b] Only effective if [member projection] is [constant PROJECTION_CUSTOM].
</member>
<member name="doppler_tracking" type="int" setter="set_doppler_tracking" getter="get_doppler_tracking" enum="Camera3D.DopplerTracking" default="0">
If not [constant DOPPLER_TRACKING_DISABLED], this camera will simulate the [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] for objects changed in particular [code]_process[/code] methods.
[b]Note:[/b] The Doppler effect will only be heard on [AudioStreamPlayer3D]s if [member AudioStreamPlayer3D.doppler_tracking] is not set to [constant AudioStreamPlayer3D.DOPPLER_TRACKING_DISABLED].
Expand Down Expand Up @@ -224,6 +228,9 @@
<constant name="PROJECTION_FRUSTUM" value="2" enum="ProjectionType">
Frustum projection. This mode allows adjusting [member frustum_offset] to create "tilted frustum" effects.
</constant>
<constant name="PROJECTION_CUSTOM" value="3" enum="ProjectionType">
Custom projection. This mode allows using [member custom_projection].
</constant>
<constant name="KEEP_WIDTH" value="0" enum="KeepAspect">
Preserves the horizontal aspect ratio; also known as Vert- scaling. This is usually the best option for projects running in portrait mode, as taller aspect ratios will benefit from a wider vertical FOV.
</constant>
Expand Down
8 changes: 8 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@
Sets the cull mask associated with this camera. The cull mask describes which 3D layers are rendered by this camera. Equivalent to [member Camera3D.cull_mask].
</description>
</method>
<method name="camera_set_custom">
<return type="void" />
<param index="0" name="camera" type="RID" />
<param index="1" name="p_proj" type="Projection" />
<description>
Sets camera to use custom projection.
</description>
</method>
<method name="camera_set_environment">
<return type="void" />
<param index="0" name="camera" type="RID" />
Expand Down
30 changes: 30 additions & 0 deletions editor/scene/3d/gizmos/camera_3d_gizmo_plugin.cpp
Copy link
Copy Markdown
Contributor

@otonashixav otonashixav Mar 23, 2024

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.

Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,36 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector3 tup(0, up.y + hsize / 2, side.z);
ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset);
} break;

case Camera3D::PROJECTION_CUSTOM: {
Vector3 points[8] = {
Vector3(0.5f, 0.5f, 0.0f),
Vector3(0.5f, -0.5f, 0.0f),
Vector3(-0.5f, 0.5f, 0.0f),
Vector3(-0.5f, -0.5f, 0.0f),
Vector3(0.5f, 0.5f, -1.0f),
Vector3(0.5f, -0.5f, -1.0f),
Vector3(-0.5f, 0.5f, -1.0f),
Vector3(-0.5f, -0.5f, -1.0f)
};

Projection proj = camera->get_camera_projection();

for (int i = 0; i < 8; i++) {
points[i] = proj.xform(points[i]);
}

ADD_QUAD(points[0], points[1], points[5], points[4]);
ADD_QUAD(points[2], points[3], points[7], points[6]);
ADD_QUAD(points[0], points[2], points[6], points[4]);
ADD_QUAD(points[1], points[3], points[7], points[5]);

Vector3 top_left_to_top_right = points[0] - points[2];
Vector3 up = Vector3(0, 0, 0.2).cross(top_left_to_top_right);
ADD_TRIANGLE(points[2] + top_left_to_top_right * 0.4,
points[2] + top_left_to_top_right * 0.6,
points[2] + top_left_to_top_right * 0.5 + up);
} break;
}

#undef ADD_TRIANGLE
Expand Down
91 changes: 85 additions & 6 deletions scene/3d/camera_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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()) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Copy link
Copy Markdown
Contributor

@otonashixav otonashixav Mar 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad! I think this check should be in set_custom_projection instead, before c_proj is ever set. I'm also not sure if it makes sense to disallow these projections, since it seems like only lighting and the editor gizmo are dependent on having endpoints, if someone familiar could weigh in.

Edit: Okay actually I'm not too sure if changing this makes sense, since moving it before c_proj is set means you can't change the value through the invalid values in the editor.

Suggested change
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.");
}

Copy link
Copy Markdown
Contributor

@otonashixav otonashixav Mar 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separately, it seems that for testing only the planes for Transform3D() is not sufficient, since it seems that it is still possible to have no endpoints if the camera position/rotation is different, which means the reported vulkan crash can still happen, albeit rarely (I spent about 30 seconds dragging every projection value back and forth before getting a crash). I don't think testing every time the camera transform changes makes sense, so there should be a more robust way of checking if a projection has endpoints regardless of transform?

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();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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

  1. get_viewport seems to give the 2D viewport, which has its size out of sync with the 3D viewport sometimes (e.g. when the editor is first opened, or when the viewport area is resized, the viewport which isn't being rendered doesn't have its size updated)

}

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();
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -748,6 +822,11 @@ void Camera3D::set_far(real_t p_far) {
_update_camera_mode();
}

void Camera3D::set_custom_projection(Projection p_proj) {
Copy link
Copy Markdown
Contributor

@otonashixav otonashixav Mar 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refer to the other comment.

Suggested change
void Camera3D::set_custom_projection(Projection p_proj) {
void Camera3D::set_custom_projection(Projection p_proj) {
Vector<Plane> planes = p_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.");
}

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);
Expand Down
7 changes: 6 additions & 1 deletion scene/3d/camera_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class Camera3D : public Node3D {
enum ProjectionType {
PROJECTION_PERSPECTIVE,
PROJECTION_ORTHOGONAL,
PROJECTION_FRUSTUM
PROJECTION_FRUSTUM,
PROJECTION_CUSTOM
};

enum KeepAspect {
Expand Down Expand Up @@ -74,6 +75,7 @@ class Camera3D : public Node3D {
real_t v_offset = 0.0;
real_t h_offset = 0.0;
KeepAspect keep_aspect = KEEP_HEIGHT;
Projection c_proj;

RID camera;
RID scenario_id;
Expand Down Expand Up @@ -139,7 +141,9 @@ class Camera3D : public Node3D {
void set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far);
void set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far);
void set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, real_t p_z_far);
void set_custom(Projection p_proj);
void set_projection(Camera3D::ProjectionType p_mode);
void set_custom_projection(Projection p_proj);

void make_current();
void clear_current(bool p_enable_next = true);
Expand All @@ -151,6 +155,7 @@ class Camera3D : public Node3D {
real_t get_fov() const;
real_t get_size() const;
real_t get_far() const;
Projection get_custom_projection() const;
real_t get_near() const;
Vector2 get_frustum_offset() const;

Expand Down
11 changes: 11 additions & 0 deletions servers/rendering/renderer_scene_cull.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p
camera->zfar = p_z_far;
}

void RendererSceneCull::camera_set_custom(RID p_camera, Projection p_proj) {
Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_NULL(camera);
camera->type = Camera::CUSTOM;
camera->c_proj = p_proj;
}

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);
Expand Down Expand Up @@ -2653,6 +2660,10 @@ void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_bu
camera->vaspect);
is_frustum = true;
} break;
case Camera::CUSTOM: {
projection = camera->c_proj;
is_orthogonal = projection.is_orthogonal();
} break;
}

camera_data.set_camera(transform, projection, is_orthogonal, is_frustum, vaspect, jitter, taa_frame_count, camera->visible_layers);
Expand Down
5 changes: 4 additions & 1 deletion servers/rendering/renderer_scene_cull.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ class RendererSceneCull : public RenderingMethod {
enum Type {
PERSPECTIVE,
ORTHOGONAL,
FRUSTUM
FRUSTUM,
CUSTOM,
};
Type type;
float fov;
Expand All @@ -87,6 +88,7 @@ class RendererSceneCull : public RenderingMethod {
RID attributes;
RID compositor;

Projection c_proj;
Transform3D transform;

Camera() {
Expand All @@ -109,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_custom(RID p_camera, Projection p_proj);
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);
Expand Down
Loading