Last active
April 20, 2022 05:29
-
-
Save HungryProton/b67fefe76082cb04cfc48842fb1aa270 to your computer and use it in GitHub Desktop.
Spatial gizmo example - A box you can resize
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tool | |
class_name ConceptBoxInput | |
extends Spatial | |
signal input_changed | |
signal property_changed | |
export var size := Vector3.ONE setget set_size | |
var auto_center := false setget set_auto_center # TODO: implement standard AABB behavior | |
export var center := Vector3.ZERO setget set_center | |
func _ready() -> void: | |
add_user_signal('input_changed') | |
set_notify_local_transform(true) | |
func _get_property_list() -> Array: | |
#if not auto_center: | |
# return [{"name": "Center", "type": TYPE_VECTOR3}] | |
return [] | |
func _notification(type: int): | |
if type == NOTIFICATION_TRANSFORM_CHANGED: | |
_on_box_changed() | |
func is_inside(pos: Vector3, ignore_y_axis: bool = false) -> bool: | |
var t = transform | |
if is_inside_tree(): | |
t = global_transform | |
var local = t.xform_inv(pos) | |
if ignore_y_axis: | |
local.y = size.y / 3.0 | |
var aabb = AABB(center - (size / 2.0), size) | |
return aabb.has_point(local) | |
func set_size(val: Vector3) -> void: | |
size = val | |
_on_box_changed() | |
func set_auto_center(val: bool) -> void: | |
auto_center = val | |
property_list_changed_notify() | |
func set_center(val: Vector3) -> void: | |
center = val | |
property_list_changed_notify() | |
_on_box_changed() | |
func _on_box_changed() -> void: | |
emit_signal("input_changed", self) # That tell the ConceptGraph to rerun the simulation | |
emit_signal("property_changed") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tool | |
extends EditorPlugin | |
var _editor_gizmo_plugins: Array | |
func _enter_tree() -> void: | |
_register_editor_gizmos() | |
func _exit_tree() -> void: | |
_deregister_editor_gizmos() | |
func _register_editor_gizmos() -> void: | |
if not _editor_gizmo_plugins: | |
_editor_gizmo_plugins = [] | |
if _editor_gizmo_plugins.size() > 0: | |
_deregister_editor_gizmos() | |
var box_gizmo = preload("src/editor/gizmos/box_gizmo_plugin.gd").new() | |
box_gizmo.editor_plugin = self | |
_editor_gizmo_plugins.append(box_gizmo) | |
add_spatial_gizmo_plugin(box_gizmo) | |
func _deregister_editor_gizmos() -> void: | |
if _editor_gizmo_plugins: | |
for gizmo in _editor_gizmo_plugins: | |
remove_spatial_gizmo_plugin(gizmo) | |
_editor_gizmo_plugins = [] | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends EditorSpatialGizmoPlugin | |
var editor_plugin: EditorPlugin | |
var _previous_size | |
func _init(): | |
create_material("lines", Color(1, 1, 1)) | |
create_material("box", Color(1.0, 1.0, 1.0, 0.1)) | |
create_handle_material("handles") | |
func get_name() -> String: | |
return "ConceptBoxInput" | |
func has_gizmo(node): | |
return node is ConceptBoxInput | |
func get_handle_name(gizmo: EditorSpatialGizmo, index: int) -> String: | |
return "Handle " + String(index) | |
func get_handle_value(gizmo: EditorSpatialGizmo, index: int): | |
var box = gizmo.get_spatial_node() | |
return box.size | |
""" | |
Automatically called when a handle is moved around. | |
""" | |
func set_handle(gizmo: EditorSpatialGizmo, index: int, camera: Camera, point: Vector2) -> void: | |
var box: ConceptBoxInput = gizmo.get_spatial_node() | |
if not _previous_size: | |
_previous_size = box.size | |
var global_transform: Transform = box.transform | |
if box.is_inside_tree(): | |
global_transform = box.get_global_transform() | |
var global_inverse: Transform = global_transform.affine_inverse() | |
var ray_from = camera.project_ray_origin(point) | |
var ray_dir = camera.project_ray_normal(point) | |
if index < 6: | |
# Face handle | |
var i := index % 3 | |
var axis: Vector3 | |
axis[i] = 1.0 | |
var p1 = axis * 4096 | |
var p2 = -p1 | |
var g1 = global_inverse.xform(ray_from) | |
var g2 = global_inverse.xform(ray_from + ray_dir * 4096) | |
var points = Geometry.get_closest_points_between_segments(p1, p2, g1, g2) | |
var d = points[0][i] | |
# TODO : Add snap support (when holding ctrl) | |
# TODO : Add symetric edition (when holding shift) | |
if index > 2: | |
d *= -1.0 | |
box.size[i] = d + (_previous_size[i] / 2.0) | |
box.center[i] = (box.size[i] * 0.5) - d | |
if index < 3: | |
box.center[i] *= -1.0 | |
redraw(gizmo) | |
else: | |
# Corner handle | |
print("Not implemented yet") | |
box.property_list_changed_notify() | |
""" | |
Handle Undo / Redo after a handle was moved. | |
""" | |
func commit_handle(gizmo: EditorSpatialGizmo, index: int, restore, cancel: bool = false) -> void: | |
var box = gizmo.get_spatial_node() | |
var ur = editor_plugin.get_undo_redo() | |
ur.create_action("Resize Box Input") | |
ur.add_do_method(box, "translate", box.center) | |
ur.add_do_property(box, "center", Vector3.ZERO) | |
ur.add_do_property(box, "size", box.size) | |
ur.add_undo_method(box, "translate", -box.center) | |
ur.add_undo_property(box, "size", restore) | |
ur.add_undo_method(box, "property_list_changed_notify") # TMP hack, find why the inspector does not refresh automatically on undo | |
ur.commit_action() | |
_previous_size = null | |
redraw(gizmo) | |
func redraw(gizmo: EditorSpatialGizmo): | |
gizmo.clear() | |
var box := gizmo.get_spatial_node() as ConceptBoxInput | |
# TMP: force the gizmo to redraw everytime we change a parameter. This should probably | |
# happen automatically but for some reason, it doesn't | |
if not box.is_connected("property_changed", self, "redraw"): | |
box.connect("property_changed", self, "redraw", [gizmo]) | |
var lines := _get_box_lines(box) | |
var handles := _get_box_handles(box) | |
gizmo.add_handles(handles, get_material("handles", gizmo)) | |
gizmo.add_lines(lines, get_material("lines", gizmo)) | |
gizmo.add_collision_segments(lines) | |
""" | |
Returns all the points that make up the box lines. | |
""" | |
func _get_box_lines(box: ConceptBoxInput) -> PoolVector3Array: | |
var lines = PoolVector3Array() | |
var c = _get_box_corners(box) | |
lines.push_back(c[0]) | |
lines.push_back(c[1]) | |
lines.push_back(c[1]) | |
lines.push_back(c[2]) | |
lines.push_back(c[2]) | |
lines.push_back(c[3]) | |
lines.push_back(c[3]) | |
lines.push_back(c[0]) | |
lines.push_back(c[0]) | |
lines.push_back(c[5]) | |
lines.push_back(c[1]) | |
lines.push_back(c[6]) | |
lines.push_back(c[2]) | |
lines.push_back(c[7]) | |
lines.push_back(c[3]) | |
lines.push_back(c[4]) | |
lines.push_back(c[4]) | |
lines.push_back(c[5]) | |
lines.push_back(c[5]) | |
lines.push_back(c[6]) | |
lines.push_back(c[6]) | |
lines.push_back(c[7]) | |
lines.push_back(c[7]) | |
lines.push_back(c[4]) | |
return lines | |
""" | |
Returns the position of each handles. One on each corner, one at the center of each faces. | |
""" | |
func _get_box_handles(box: ConceptBoxInput) -> PoolVector3Array: | |
var handles := PoolVector3Array() | |
var hs := box.size / 2.0 | |
# Ordered on purpose so their (index % 3) matches the associated Vector3 axis | |
handles.append(Vector3(hs.x, 0.0, 0.0) + box.center) | |
handles.append(Vector3(0.0, hs.y, 0.0) + box.center) | |
handles.append(Vector3(0.0, 0.0, hs.z) + box.center) | |
handles.append(Vector3(-hs.x, 0.0, 0.0) + box.center) | |
handles.append(Vector3(0.0, -hs.y, 0.0) + box.center) | |
handles.append(Vector3(0.0, 0.0, -hs.z) + box.center) | |
# Append _get_box_corners(box) there once we figure out the math to move corners | |
return handles | |
""" | |
Calculate the position of each corners of the box. | |
""" | |
func _get_box_corners(box: ConceptBoxInput) -> PoolVector3Array: | |
var corners = PoolVector3Array() | |
var hs := box.size / 2.0 | |
var left := -hs.x | |
var right := hs.x | |
var top := hs.y | |
var bottom := -hs.y | |
var front := hs.z | |
var back := - hs.z | |
corners.append(Vector3(left, top, front) + box.center) | |
corners.append(Vector3(right, top, front) + box.center) | |
corners.append(Vector3(right, bottom, front) + box.center) | |
corners.append(Vector3(left, bottom, front) + box.center) | |
corners.append(Vector3(left, bottom, back) + box.center) | |
corners.append(Vector3(left, top, back) + box.center) | |
corners.append(Vector3(right, top, back) + box.center) | |
corners.append(Vector3(right, bottom, back) + box.center) | |
return corners |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment