Merge pull request #8616 from Zylann/fps_look

Added 3D freelook navigation mode
This commit is contained in:
Rémi Verschelde 2017-05-05 22:51:25 +02:00 committed by GitHub
commit 63d02067de
3 changed files with 123 additions and 124 deletions

View file

@ -591,6 +591,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
set("editors/3d/emulate_3_button_mouse", false);
set("editors/3d/warped_mouse_panning", true);
set("editors/3d/freelook_base_speed", 5);
set("editors/3d/freelook_acceleration", 10);
set("editors/3d/freelook_max_speed", 100);
set("editors/3d/freelook_modifier_speed_factor", 1.0 / 5.0);
set("editors/2d/bone_width", 5);
set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9));
set("editors/2d/bone_color2", Color(0.75, 0.75, 0.75, 0.9));

View file

@ -58,15 +58,7 @@ void SpatialEditorViewport::_update_camera() {
} else
camera->set_perspective(get_fov(), get_znear(), get_zfar());
Transform camera_transform;
camera_transform.translate(cursor.pos);
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
if (orthogonal)
camera_transform.translate(0, 0, 4096);
else
camera_transform.translate(0, 0, cursor.distance);
Transform camera_transform = to_camera_transform(cursor);
if (camera->get_global_transform() != camera_transform) {
camera->set_global_transform(camera_transform);
@ -74,6 +66,20 @@ void SpatialEditorViewport::_update_camera() {
}
}
Transform SpatialEditorViewport::to_camera_transform(const Cursor &p_cursor) const {
Transform camera_transform;
camera_transform.translate(p_cursor.pos);
camera_transform.basis.rotate(Vector3(1, 0, 0), -p_cursor.x_rot);
camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot);
if (orthogonal)
camera_transform.translate(0, 0, 4096);
else
camera_transform.translate(0, 0, p_cursor.distance);
return camera_transform;
}
String SpatialEditorGizmo::get_handle_name(int p_idx) const {
if (get_script_instance() && get_script_instance()->has_method("get_handle_name"))
@ -669,8 +675,7 @@ void SpatialEditorViewport::_list_select(InputEventMouseButton b) {
selection_menu->add_item(spat->get_name());
selection_menu->set_item_icon(i, icon);
selection_menu->set_item_metadata(i, node_path);
selection_menu->set_item_tooltip(i, String(spat->get_name()) +
"\nType: " + spat->get_class() + "\nPath: " + node_path);
selection_menu->set_item_tooltip(i, String(spat->get_name()) + "\nType: " + spat->get_class() + "\nPath: " + node_path);
}
selection_menu->set_global_position(Vector2(b.global_x, b.global_y));
@ -729,76 +734,6 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (_edit.mode == TRANSFORM_NONE && b.pressed) {
Plane cursor_plane(cursor.cursor_pos, _get_camera_normal());
Vector3 ray_origin = _get_ray_pos(Vector2(b.x, b.y));
Vector3 ray_dir = _get_ray(Vector2(b.x, b.y));
//gizmo modify
if (b.mod.control) {
Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(ray_origin, ray_dir, get_tree()->get_root()->get_world()->get_scenario());
Plane p(ray_origin, _get_camera_normal());
float min_d = 1e10;
bool found = false;
for (int i = 0; i < instances.size(); i++) {
Object *obj = ObjectDB::get_instance(instances[i]);
if (!obj)
continue;
VisualInstance *vi = obj->cast_to<VisualInstance>();
if (!vi)
continue;
//optimize by checking AABB (although should pre sort by distance)
Rect3 aabb = vi->get_global_transform().xform(vi->get_aabb());
if (p.distance_to(aabb.get_support(-ray_dir)) > min_d)
continue;
PoolVector<Face3> faces = vi->get_faces(VisualInstance::FACES_SOLID);
int c = faces.size();
if (c > 0) {
PoolVector<Face3>::Read r = faces.read();
for (int j = 0; j < c; j++) {
Vector3 inters;
if (r[j].intersects_ray(ray_origin, ray_dir, &inters)) {
float d = p.distance_to(inters);
if (d < 0)
continue;
if (d < min_d) {
min_d = d;
found = true;
}
}
}
}
}
if (found) {
//cursor.cursor_pos=ray_origin+ray_dir*min_d;
//VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos));
}
} else {
Vector3 new_pos;
if (cursor_plane.intersects_ray(ray_origin, ray_dir, &new_pos)) {
//cursor.cursor_pos=new_pos;
//VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos));
}
}
if (b.mod.alt) {
if (nav_scheme == NAVIGATION_MAYA)
@ -1344,6 +1279,8 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (nav_scheme == NAVIGATION_MAYA && m.mod.alt) {
nav_mode = NAVIGATION_ZOOM;
} else {
nav_mode = NAVIGATION_LOOK;
}
} else if (m.button_mask & 4) {
@ -1453,6 +1390,29 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
_update_name();
} break;
case NAVIGATION_LOOK: {
// Freelook only works properly in perspective.
// It technically works too in ortho, but it's awful for a user due to fov being near zero
if (!orthogonal) {
cursor.x_rot += m.relative_y / 120.0;
cursor.y_rot += m.relative_x / 120.0;
if (cursor.x_rot > Math_PI / 2.0)
cursor.x_rot = Math_PI / 2.0;
if (cursor.x_rot < -Math_PI / 2.0)
cursor.x_rot = -Math_PI / 2.0;
// Look is like Orbit, except the cursor translates, not the camera
Transform camera_transform = to_camera_transform(cursor);
Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
Vector3 diff = camera->get_translation() - pos;
cursor.pos += diff;
name = "";
_update_name();
}
} break;
default: {}
}
} break;
@ -1543,6 +1503,75 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
}
}
void SpatialEditorViewport::_update_freelook(real_t delta) {
const Input &input = *Input::get_singleton();
if (!input.is_mouse_button_pressed(BUTTON_RIGHT))
return;
Vector3 forward = camera->get_transform().basis.xform(Vector3(0, 0, -1));
Vector3 right = camera->get_transform().basis.xform(Vector3(1, 0, 0));
Vector3 up = Vector3(0, 1, 0);
int key_left = ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A)->get_shortcut().key.scancode;
int key_right = ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D)->get_shortcut().key.scancode;
int key_forward = ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W)->get_shortcut().key.scancode;
int key_backwards = ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), KEY_S)->get_shortcut().key.scancode;
int key_up = ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), KEY_Q)->get_shortcut().key.scancode;
int key_down = ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_E)->get_shortcut().key.scancode;
int key_speed_modifier = ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT)->get_shortcut().key.scancode;
Vector3 velocity;
bool pressed = false;
bool speed_modifier = false;
if (input.is_key_pressed(key_left)) {
velocity -= right;
pressed = true;
}
if (input.is_key_pressed(key_right)) {
velocity += right;
pressed = true;
}
if (input.is_key_pressed(key_forward)) {
velocity += forward;
pressed = true;
}
if (input.is_key_pressed(key_backwards)) {
velocity -= forward;
pressed = true;
}
if (input.is_key_pressed(key_up)) {
velocity += up;
pressed = true;
}
if (input.is_key_pressed(key_down)) {
velocity -= up;
pressed = true;
}
if (input.is_key_pressed(key_speed_modifier)) {
speed_modifier = true;
}
const EditorSettings &s = *EditorSettings::get_singleton();
real_t base_speed = s.get("editors/3d/freelook_base_speed");
real_t acceleration = s.get("editors/3d/freelook_acceleration");
real_t max_speed = s.get("editors/3d/freelook_max_speed");
real_t modifier_speed_factor = s.get("editors/3d/freelook_modifier_speed_factor");
if (pressed) {
velocity.normalize();
freelook_speed += acceleration * delta;
if (freelook_speed > max_speed)
freelook_speed = max_speed;
cursor.pos += velocity * ((freelook_speed * (speed_modifier ? modifier_speed_factor : 1.0) * delta));
} else {
freelook_speed = base_speed;
}
}
void SpatialEditorViewport::set_message(String p_message, float p_time) {
message = p_message;
@ -1579,6 +1608,8 @@ void SpatialEditorViewport::_notification(int p_what) {
}
*/
_update_freelook(get_tree()->get_idle_process_time());
_update_camera();
Map<Node *, Object *> &selection = editor_selection->get_selection();
@ -2204,6 +2235,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
previewing = NULL;
preview = NULL;
gizmo_scale = 1.0;
freelook_speed = 0;
selection_menu = memnew(PopupMenu);
add_child(selection_menu);
@ -3149,36 +3181,6 @@ void SpatialEditor::_finish_indicators() {
VisualServer::get_singleton()->free(cursor_mesh);
}
void SpatialEditor::_instance_scene() {
#if 0
EditorNode *en = get_scene()->get_root_node()->cast_to<EditorNode>();
ERR_FAIL_COND(!en);
String path = en->get_filesystem_dock()->get_selected_path();
if (path=="") {
set_message(TTR("No scene selected to instance!"));
return;
}
undo_redo->create_action(TTR("Instance at Cursor"));
Node* scene = en->request_instance_scene(path);
if (!scene) {
set_message(TTR("Could not instance scene!"));
undo_redo->commit_action(); //bleh
return;
}
Spatial *s = scene->cast_to<Spatial>();
if (s) {
undo_redo->add_do_method(s,"set_global_transform",Transform(Matrix3(),cursor.cursor_pos));
}
undo_redo->commit_action();
#endif
}
void SpatialEditor::_unhandled_key_input(InputEvent p_event) {
if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())
@ -3242,8 +3244,6 @@ void SpatialEditor::_notification(int p_what) {
tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));
tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons"));
instance_button->set_icon(get_icon("SpatialAdd", "EditorIcons"));
instance_button->hide();
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons"));
@ -3383,7 +3383,6 @@ void SpatialEditor::_bind_methods() {
ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed);
ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed);
ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action);
ClassDB::bind_method("_instance_scene", &SpatialEditor::_instance_scene);
ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data);
ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo);
ClassDB::bind_method("_default_light_angle_input", &SpatialEditor::_default_light_angle_input);
@ -3520,12 +3519,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)"));
instance_button = memnew(Button);
hbc_menu->add_child(instance_button);
instance_button->set_flat(true);
instance_button->connect("pressed", this, "_instance_scene");
instance_button->hide();
VSeparator *vs = memnew(VSeparator);
hbc_menu->add_child(vs);

View file

@ -113,6 +113,7 @@ private:
bool transforming;
bool orthogonal;
float gizmo_scale;
real_t freelook_speed;
struct _RayResult {
@ -168,7 +169,8 @@ private:
NAVIGATION_NONE,
NAVIGATION_PAN,
NAVIGATION_ZOOM,
NAVIGATION_ORBIT
NAVIGATION_ORBIT,
NAVIGATION_LOOK
};
enum TransformMode {
TRANSFORM_NONE,
@ -203,8 +205,6 @@ private:
struct Cursor {
Vector3 cursor_pos;
Vector3 pos;
float x_rot, y_rot, distance;
bool region_select;
@ -227,10 +227,12 @@ private:
//
void _update_camera();
Transform to_camera_transform(const Cursor &p_cursor) const;
void _draw();
void _smouseenter();
void _sinput(const InputEvent &p_ie);
void _update_freelook(real_t delta);
SpatialEditor *spatial_editor;
Camera *previewing;
@ -385,7 +387,6 @@ private:
};
Button *tool_button[TOOL_MAX];
Button *instance_button;
MenuButton *transform_menu;
MenuButton *view_menu;