Merge pull request #26064 from JFonS/add_frustum_camera_mode
Add FRUSTUM camera mode, allowing tilted frustums
This commit is contained in:
commit
5d33f241f0
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue