Merge pull request #26064 from JFonS/add_frustum_camera_mode

Add FRUSTUM camera mode, allowing tilted frustums
This commit is contained in:
Hein-Pieter van Braam 2019-04-23 06:20:13 +03:00 committed by GitHub
commit 5d33f241f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 133 additions and 27 deletions

View file

@ -210,6 +210,14 @@ void CameraMatrix::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, r
te[15] = 0;
}
void CameraMatrix::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) {
if (!p_flip_fov) {
p_size *= p_aspect;
}
set_frustum(-p_size / 2 + p_offset.x, +p_size / 2 + p_offset.x, -p_size / p_aspect / 2 + p_offset.y, +p_size / p_aspect / 2 + p_offset.y, p_near, p_far);
}
real_t CameraMatrix::get_z_far() const {
const real_t *matrix = (const real_t *)this->matrix;

View file

@ -61,6 +61,7 @@ struct CameraMatrix {
void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar);
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);
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {

View file

@ -1309,6 +1309,28 @@ void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
Ref<Material> material = get_material("camera_material", p_gizmo);
Ref<Material> icon = get_material("camera_icon", p_gizmo);
#define ADD_TRIANGLE(m_a, m_b, m_c) \
{ \
lines.push_back(m_a); \
lines.push_back(m_b); \
lines.push_back(m_b); \
lines.push_back(m_c); \
lines.push_back(m_c); \
lines.push_back(m_a); \
}
#define ADD_QUAD(m_a, m_b, m_c, m_d) \
{ \
lines.push_back(m_a); \
lines.push_back(m_b); \
lines.push_back(m_b); \
lines.push_back(m_c); \
lines.push_back(m_c); \
lines.push_back(m_d); \
lines.push_back(m_d); \
lines.push_back(m_a); \
}
switch (camera->get_projection()) {
case Camera::PROJECTION_PERSPECTIVE: {
@ -1321,16 +1343,6 @@ void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
nside.x = -nside.x;
Vector3 up = Vector3(0, side.x, 0);
#define ADD_TRIANGLE(m_a, m_b, m_c) \
{ \
lines.push_back(m_a); \
lines.push_back(m_b); \
lines.push_back(m_b); \
lines.push_back(m_c); \
lines.push_back(m_c); \
lines.push_back(m_a); \
}
ADD_TRIANGLE(Vector3(), side + up, side - up);
ADD_TRIANGLE(Vector3(), nside + up, nside - up);
ADD_TRIANGLE(Vector3(), side + up, nside + up);
@ -1345,17 +1357,6 @@ void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
} break;
case Camera::PROJECTION_ORTHOGONAL: {
#define ADD_QUAD(m_a, m_b, m_c, m_d) \
{ \
lines.push_back(m_a); \
lines.push_back(m_b); \
lines.push_back(m_b); \
lines.push_back(m_c); \
lines.push_back(m_c); \
lines.push_back(m_d); \
lines.push_back(m_d); \
lines.push_back(m_a); \
}
float size = camera->get_size();
float hsize = size * 0.5;
@ -1368,6 +1369,7 @@ void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
ADD_QUAD(-up - right + back, -up + right + back, up + right + back, up - right + back);
ADD_QUAD(up + right, up + right + back, up - right + back, up - right);
ADD_QUAD(-up + right, -up + right + back, -up - right + back, -up - right);
handles.push_back(right + back);
right.x *= 0.25;
@ -1375,8 +1377,30 @@ void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
ADD_TRIANGLE(tup, right + up + back, -right + up + back);
} break;
case Camera::PROJECTION_FRUSTUM: {
float hsize = camera->get_size() / 2.0;
Vector3 side = Vector3(hsize, 0, -camera->get_znear()).normalized();
Vector3 nside = side;
nside.x = -nside.x;
Vector3 up = Vector3(0, side.x, 0);
Vector3 offset = Vector3(camera->get_frustum_offset().x, camera->get_frustum_offset().y, 0.0);
ADD_TRIANGLE(Vector3(), side + up + offset, side - up + offset);
ADD_TRIANGLE(Vector3(), nside + up + offset, nside - up + offset);
ADD_TRIANGLE(Vector3(), side + up + offset, nside + up + offset);
ADD_TRIANGLE(Vector3(), side - up + offset, nside - up + offset);
side.x *= 0.25;
nside.x *= 0.25;
Vector3 tup(0, up.y * 3 / 2, side.z);
ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset);
}
}
#undef ADD_TRIANGLE
#undef ADD_QUAD
p_gizmo->add_lines(lines, material);
p_gizmo->add_unscaled_billboard(icon, 0.05);
p_gizmo->add_handles(handles, get_material("handles"));

View file

@ -55,16 +55,23 @@ void Camera::_update_camera_mode() {
case PROJECTION_ORTHOGONAL: {
set_orthogonal(size, near, far);
} break;
case PROJECTION_FRUSTUM: {
set_frustum(size, frustum_offset, near, far);
} break;
}
}
void Camera::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "fov") {
if (mode == PROJECTION_ORTHOGONAL) {
if (mode != PROJECTION_PERSPECTIVE) {
p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
} else if (p_property.name == "size") {
if (mode == PROJECTION_PERSPECTIVE) {
if (mode != PROJECTION_ORTHOGONAL && mode != PROJECTION_FRUSTUM) {
p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
} else if (p_property.name == "frustum_offset") {
if (mode != PROJECTION_FRUSTUM) {
p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
}
@ -177,8 +184,24 @@ void Camera::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
update_gizmo();
}
void Camera::set_frustum(float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
if (!force_change && size == p_size && frustum_offset == p_offset && p_z_near == near && p_z_far == far && mode == PROJECTION_FRUSTUM)
return;
size = p_size;
frustum_offset = p_offset;
near = p_z_near;
far = p_z_far;
mode = PROJECTION_FRUSTUM;
force_change = false;
VisualServer::get_singleton()->camera_set_frustum(camera, size, frustum_offset, near, far);
update_gizmo();
}
void Camera::set_projection(Camera::Projection p_mode) {
if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL) {
if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) {
mode = p_mode;
_update_camera_mode();
_change_notify();
@ -470,16 +493,19 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("project_position", "screen_point"), &Camera::project_position);
ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective);
ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal);
ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera::set_frustum);
ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current);
ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera::clear_current, DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current);
ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform);
ClassDB::bind_method(D_METHOD("get_fov"), &Camera::get_fov);
ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera::get_frustum_offset);
ClassDB::bind_method(D_METHOD("get_size"), &Camera::get_size);
ClassDB::bind_method(D_METHOD("get_zfar"), &Camera::get_zfar);
ClassDB::bind_method(D_METHOD("get_znear"), &Camera::get_znear);
ClassDB::bind_method(D_METHOD("set_fov"), &Camera::set_fov);
ClassDB::bind_method(D_METHOD("set_frustum_offset"), &Camera::set_frustum_offset);
ClassDB::bind_method(D_METHOD("set_size"), &Camera::set_size);
ClassDB::bind_method(D_METHOD("set_zfar"), &Camera::set_zfar);
ClassDB::bind_method(D_METHOD("set_znear"), &Camera::set_znear);
@ -510,15 +536,17 @@ void Camera::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "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"), "set_projection", "get_projection");
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::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
BIND_ENUM_CONSTANT(PROJECTION_FRUSTUM);
BIND_ENUM_CONSTANT(KEEP_WIDTH);
BIND_ENUM_CONSTANT(KEEP_HEIGHT);
@ -543,6 +571,10 @@ float Camera::get_znear() const {
return near;
}
Vector2 Camera::get_frustum_offset() const {
return frustum_offset;
}
float Camera::get_zfar() const {
return far;
@ -570,6 +602,11 @@ void Camera::set_znear(float p_znear) {
_update_camera_mode();
}
void Camera::set_frustum_offset(Vector2 p_offset) {
frustum_offset = p_offset;
_update_camera_mode();
}
void Camera::set_zfar(float p_zfar) {
far = p_zfar;
_update_camera_mode();
@ -648,6 +685,7 @@ Camera::Camera() {
camera = VisualServer::get_singleton()->camera_create();
size = 1;
fov = 0;
frustum_offset = Vector2();
near = 0;
far = 0;
current = false;

View file

@ -46,7 +46,8 @@ public:
enum Projection {
PROJECTION_PERSPECTIVE,
PROJECTION_ORTHOGONAL
PROJECTION_ORTHOGONAL,
PROJECTION_FRUSTUM
};
enum KeepAspect {
@ -68,6 +69,7 @@ private:
float fov;
float size;
Vector2 frustum_offset;
float near, far;
float v_offset;
float h_offset;
@ -110,6 +112,7 @@ public:
void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
void set_orthogonal(float p_size, float p_z_near, float p_z_far);
void set_frustum(float p_size, Vector2 p_offset, float p_near, float p_far);
void set_projection(Camera::Projection p_mode);
void make_current();
@ -123,12 +126,15 @@ public:
float get_size() const;
float get_zfar() const;
float get_znear() const;
Vector2 get_frustum_offset() const;
Projection get_projection() const;
void set_fov(float p_fov);
void set_size(float p_size);
void set_zfar(float p_zfar);
void set_znear(float p_znear);
void set_frustum_offset(Vector2 p_offset);
virtual Transform get_camera_transform() const;

View file

@ -430,6 +430,7 @@ public:
BIND0R(RID, camera_create)
BIND4(camera_set_perspective, RID, float, float, float)
BIND4(camera_set_orthogonal, RID, float, float, float)
BIND5(camera_set_frustum, RID, float, Vector2, float, float)
BIND2(camera_set_transform, RID, const Transform &)
BIND2(camera_set_cull_mask, RID, uint32_t)
BIND2(camera_set_environment, RID, RID)

View file

@ -61,6 +61,16 @@ void VisualServerScene::camera_set_orthogonal(RID p_camera, float p_size, float
camera->zfar = p_z_far;
}
void VisualServerScene::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
Camera *camera = camera_owner.get(p_camera);
ERR_FAIL_COND(!camera);
camera->type = Camera::FRUSTUM;
camera->size = p_size;
camera->offset = p_offset;
camera->znear = p_z_near;
camera->zfar = p_z_far;
}
void VisualServerScene::camera_set_transform(RID p_camera, const Transform &p_transform) {
Camera *camera = camera_owner.get(p_camera);
@ -1730,6 +1740,17 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view
ortho = false;
} break;
case Camera::FRUSTUM: {
camera_matrix.set_frustum(
camera->size,
p_viewport_size.width / (float)p_viewport_size.height,
camera->offset,
camera->znear,
camera->zfar,
camera->vaspect);
ortho = false;
} break;
}
_prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID());

View file

@ -77,12 +77,14 @@ public:
enum Type {
PERSPECTIVE,
ORTHOGONAL
ORTHOGONAL,
FRUSTUM
};
Type type;
float fov;
float znear, zfar;
float size;
Vector2 offset;
uint32_t visible_layers;
bool vaspect;
RID env;
@ -97,6 +99,7 @@ public:
znear = 0.05;
zfar = 100;
size = 1.0;
offset = Vector2();
vaspect = false;
}
};
@ -106,6 +109,7 @@ public:
virtual RID camera_create();
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_transform(RID p_camera, const Transform &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);

View file

@ -360,6 +360,7 @@ public:
FUNCRID(camera)
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_transform, RID, const Transform &)
FUNC2(camera_set_cull_mask, RID, uint32_t)
FUNC2(camera_set_environment, RID, RID)

View file

@ -1863,6 +1863,7 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("camera_create"), &VisualServer::camera_create);
ClassDB::bind_method(D_METHOD("camera_set_perspective", "camera", "fovy_degrees", "z_near", "z_far"), &VisualServer::camera_set_perspective);
ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &VisualServer::camera_set_orthogonal);
ClassDB::bind_method(D_METHOD("camera_set_frustum", "camera", "size", "offset", "z_near", "z_far"), &VisualServer::camera_set_frustum);
ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &VisualServer::camera_set_transform);
ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &VisualServer::camera_set_cull_mask);
ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &VisualServer::camera_set_environment);

View file

@ -584,6 +584,7 @@ public:
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_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 Transform &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;