Skip to content
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

Add custom projection to camera3d #134

Closed
Closed
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
7 changes: 7 additions & 0 deletions doc/classes/Camera3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,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. See [enum DopplerTracking] for possible values.
</member>
Expand Down Expand Up @@ -222,6 +226,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/plugins/gizmos/camera_3d_gizmo_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,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
72 changes: 69 additions & 3 deletions scene/3d/camera_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,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;
}
}

Expand All @@ -71,6 +73,18 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const {
if (mode != PROJECTION_FRUSTUM) {
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 @@ -309,6 +323,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 @@ -367,8 +384,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.");
}

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();
}

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 @@ -650,6 +703,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 @@ -660,6 +714,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 @@ -702,17 +757,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 @@ -742,6 +799,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 @@ -773,6 +834,11 @@ void Camera3D::set_far(real_t p_far) {
_update_camera_mode();
}

void Camera3D::set_custom_projection(Projection p_proj) {
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 @@ -151,7 +153,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 @@ -163,6 +167,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 @@ -110,6 +110,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 @@ -2755,6 +2762,10 @@ void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_bu
camera->zfar,
camera->vaspect);
} break;
case Camera::CUSTOM: {
projection = camera->c_proj;
is_orthogonal = projection.is_orthogonal();
} break;
}

camera_data.set_camera(transform, projection, is_orthogonal, 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 @@ -78,7 +78,8 @@ class RendererSceneCull : public RenderingMethod {
enum Type {
PERSPECTIVE,
ORTHOGONAL,
FRUSTUM
FRUSTUM,
CUSTOM,
};
Type type;
float fov;
Expand All @@ -91,6 +92,7 @@ class RendererSceneCull : public RenderingMethod {
RID attributes;
RID compositor;

Projection c_proj;
Transform3D transform;

Camera() {
Expand All @@ -113,6 +115,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
1 change: 1 addition & 0 deletions servers/rendering/rendering_method.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_custom(RID p_camera, Projection p_proj) = 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;
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/rendering_server_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,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_custom, RID, Projection)
FUNC2(camera_set_transform, RID, const Transform3D &)
FUNC2(camera_set_cull_mask, RID, uint32_t)
FUNC2(camera_set_environment, RID, RID)
Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2771,6 +2771,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_custom", "camera", "p_proj"), &RenderingServer::camera_set_custom);
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);
Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,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_custom(RID p_camera, Projection p_proj) = 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;
Expand Down
Loading