160 lines
4.8 KiB
GDScript
160 lines
4.8 KiB
GDScript
# my_custom_gizmo_plugin.gd
|
|
extends EditorNode3DGizmoPlugin
|
|
|
|
const handles_axis: PackedVector3Array = [
|
|
Vector3(1, 0, 0),
|
|
Vector3(0, 1, 0),
|
|
Vector3(0, 0, 1),
|
|
Vector3(-1, 0, 0),
|
|
Vector3(0, -1, 0),
|
|
Vector3(0, 0, -1)
|
|
]
|
|
|
|
const box_lines: PackedVector3Array = [
|
|
# plane -x
|
|
Vector3(-1, -1, -1), Vector3(-1, -1, 1),
|
|
Vector3(-1, -1, 1), Vector3(-1, 1, 1),
|
|
Vector3(-1, 1, 1), Vector3(-1, 1, -1),
|
|
Vector3(-1, 1, -1), Vector3(-1, -1, -1),
|
|
# plane +x
|
|
Vector3(1, -1, -1), Vector3(1, -1, 1),
|
|
Vector3(1, -1, 1), Vector3(1, 1, 1),
|
|
Vector3(1, 1, 1), Vector3(1, 1, -1),
|
|
Vector3(1, 1, -1), Vector3(1, -1, -1),
|
|
# connecting plane x with -x
|
|
Vector3(1, -1, -1), Vector3(-1, -1, -1),
|
|
Vector3(1, -1, 1), Vector3(-1, -1, 1),
|
|
Vector3(1, 1, -1), Vector3(-1, 1, -1),
|
|
Vector3(1, 1, 1), Vector3(-1, 1, 1),
|
|
]
|
|
|
|
var icon: Texture2D = preload("lightmap_probe_grid_icon.svg")
|
|
|
|
var timer: Timer = Timer.new()
|
|
var is_awayting: bool = false
|
|
|
|
|
|
func _get_gizmo_name() -> String:
|
|
return "LightmapProbeGrid"
|
|
|
|
|
|
func _init() -> void:
|
|
create_material("main_material", Color(0,0,0))
|
|
create_material("tool_material", Color(1, 0.9, 0))
|
|
create_handle_material("handles_material")
|
|
create_icon_material("icon_material", icon)
|
|
|
|
|
|
func _has_gizmo(node: Node3D) -> bool:
|
|
if node is LightmapProbeGrid:
|
|
if not node.size_changed.is_connected(node.update_gizmos):
|
|
node.size_changed.connect(node.update_gizmos)
|
|
if not node.probes_changed.is_connected(node.update_gizmos):
|
|
node.probes_changed.connect(node.update_gizmos)
|
|
return true
|
|
else:
|
|
return false
|
|
|
|
|
|
func _redraw(gizmo: EditorNode3DGizmo) -> void:
|
|
gizmo.clear()
|
|
var box: LightmapProbeGrid = gizmo.get_node_3d() as LightmapProbeGrid
|
|
var size: Vector3 = box.size
|
|
|
|
var icon_gizmo: Material = get_material("icon_material")
|
|
gizmo.add_unscaled_billboard(icon_gizmo, 0.05)
|
|
|
|
# Setting box lines
|
|
var lines: PackedVector3Array = []
|
|
for pos: Vector3 in box_lines:
|
|
var scaled: Vector3 = 0.5 * pos * size
|
|
lines.append(scaled)
|
|
gizmo.add_lines(lines, get_material("main_material", gizmo))
|
|
|
|
# Setting handles
|
|
var handles: PackedVector3Array = []
|
|
for pos: Vector3 in handles_axis:
|
|
var scaled: Vector3 = 0.5 * pos * size
|
|
handles.append(scaled)
|
|
gizmo.add_handles(handles, get_material("handles_material", gizmo), [])
|
|
|
|
# Setting extra tool lines from main script
|
|
var tool_lines: PackedVector3Array = box.gizmo_lines
|
|
if not tool_lines.is_empty():
|
|
gizmo.add_lines(tool_lines, get_material("tool_material", gizmo))
|
|
clear_tool_await(box)
|
|
|
|
|
|
# Wait 3 seconds before clear the main script gizmos. If called twice the timer is reset
|
|
func clear_tool_await(box: LightmapProbeGrid):
|
|
if not is_instance_valid(timer):
|
|
timer = Timer.new()
|
|
# Add timer to the scene
|
|
if not is_instance_valid(timer.get_parent()):
|
|
var root_node = EditorInterface.get_edited_scene_root()
|
|
root_node.add_child(timer)
|
|
timer.name = "lightmap_probe_grid_timer"
|
|
|
|
timer.wait_time = 3.0
|
|
timer.start()
|
|
|
|
if is_awayting:
|
|
return
|
|
|
|
is_awayting = true
|
|
await timer.timeout
|
|
is_awayting = false
|
|
|
|
timer.stop
|
|
box.gizmo_lines.clear()
|
|
box.update_gizmos()
|
|
|
|
|
|
# Based on github.com/godotengine/godot/blob/master/editor/plugins/gizmos/gizmo_3d_helper.cpp
|
|
# please, make it available to GDScript plugin developers...
|
|
func _set_handle(gizmo: EditorNode3DGizmo, index: int, _sec: bool, camera: Camera3D, point: Vector2) -> void:
|
|
var box: LightmapProbeGrid = gizmo.get_node_3d() as LightmapProbeGrid
|
|
var axis: Vector3 = handles_axis[index]
|
|
var axis_index: int = axis.abs().max_axis_index()
|
|
|
|
var inverse: Transform3D = box.global_transform.affine_inverse()
|
|
var ray_from: Vector3 = camera.project_ray_origin(point)
|
|
var ray_to: Vector3 = camera.project_ray_normal(point)
|
|
var camera_position: Vector3 = inverse * ray_from
|
|
var camera_to_mouse: Vector3 = inverse * (ray_from + ray_to * 5000)
|
|
|
|
var segment1: Vector3 = axis * 5000
|
|
var segment2: Vector3 = axis * -5000
|
|
|
|
var intersection: PackedVector3Array = Geometry3D.get_closest_points_between_segments(segment2,
|
|
segment1, camera_position, camera_to_mouse)
|
|
|
|
# Distance between the center and the handle (without scale)
|
|
var distance: float = intersection[0][axis_index]
|
|
# multiply axis signal to cancel distance signal
|
|
distance *= axis[axis_index]
|
|
|
|
var old_distance: float = 0.5 * box.size[axis_index]
|
|
|
|
# Defining new size and positions
|
|
var new_size: float = distance + old_distance
|
|
|
|
# Translate halfway through the size difference
|
|
var translate: Vector3 = 0.5 * (distance - old_distance) * axis
|
|
|
|
# Updating size and position
|
|
box.size[axis_index] = new_size
|
|
box.translate(translate)
|
|
|
|
# Update Gizmo
|
|
box.update_gizmos()
|
|
|
|
|
|
func _get_handle_name(_gizmo: EditorNode3DGizmo, _handle_id: int, _sec: bool) -> String:
|
|
return "Probe Grid Size"
|
|
|
|
|
|
func _get_handle_value(gizmo: EditorNode3DGizmo, _id: int, _sec: bool) -> Vector3:
|
|
var box: LightmapProbeGrid = gizmo.get_node_3d() as LightmapProbeGrid
|
|
return box.size
|