Son aktivite 4 days ago

Revizyon 6aafe05b8ce231b56122ffc9fed46a82c9027fc9

gizmo.gd Ham
1@tool
2extends EditorNode3DGizmoPlugin
3
4const ONE_VEC = Vector3(1.0, 1.0, 1.0)
5
6var undo_redo: EditorUndoRedoManager
7
8var handles: PackedVector3Array = [
9 Vector3.UP,
10 -Vector3.FORWARD,
11 Vector3.RIGHT,
12
13 -Vector3.UP,
14 Vector3.FORWARD,
15 -Vector3.RIGHT
16]
17
18var directions: Array[String] = [
19 "+Y", "+Z", "+X", "-Y", "-Z", "-X"
20]
21
22var first_pos: Variant
23var first_scale: Vector3
24var first_position: Vector3
25var first_transform: Transform3D
26
27func _has_gizmo(node):
28 return node is Node3D
29
30func _get_gizmo_name() -> String:
31 return "Rodot gizmo"
32
33func _init(undo_redo: EditorUndoRedoManager):
34 self.undo_redo = undo_redo
35 create_handle_material("handles")
36
37func _redraw(gizmo):
38 gizmo.clear()
39 gizmo.add_handles(handles, get_material("handles", gizmo), [])
40
41func _get_handle_name(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool) -> String:
42 return "Resize " + directions[handle_id]
43
44func _get_handle_value(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool) -> Variant:
45 return handles[handle_id]
46
47func _begin_handle_action(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool) -> void:
48 var node = gizmo.get_node_3d()
49 first_pos = null
50 first_scale = node.scale
51 first_position = node.position
52 first_transform = Transform3D(node.transform)
53
54func _commit_handle(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool, restore: Variant, cancel: bool) -> void:
55 var node = gizmo.get_node_3d()
56 if cancel:
57 node.scale = first_scale
58 node.position = first_position
59 return
60
61 if node.scale.is_equal_approx(first_scale) and node.position.is_equal_approx(first_position):
62 return
63
64 undo_redo.create_action("Resize Node3D")
65 undo_redo.add_do_property(node, "position", node.position)
66 undo_redo.add_undo_property(node, "position", first_position)
67 undo_redo.add_do_property(node, "scale", node.scale)
68 undo_redo.add_undo_property(node, "scale", first_scale)
69 undo_redo.commit_action()
70
71func _update_node(node: Node3D, change: Vector3, axis: Vector3, minimum_deflection = 1.0) -> void:
72 if change.length() == 0:
73 # Reset to default, no size change
74 node.position = first_position
75 node.scale = first_scale
76 return
77
78 var axis_direction = sign(change.dot(axis))
79 var direction = axis_direction * sign(axis.dot(axis.abs()))
80 var amount_to_add = change.length() * direction
81 var current_scale = (first_scale * axis.abs()).length()
82
83 # If user attempts to go negative or zero, force them back to the minimum amount
84 var deflection = current_scale + amount_to_add
85 if deflection < minimum_deflection:
86 amount_to_add = amount_to_add - deflection + minimum_deflection
87
88 var abs_axis: Vector3 = axis.abs()
89 var scale_vec: Vector3 = ONE_VEC - abs_axis
90 var factor: float = (current_scale + amount_to_add) / current_scale
91 var axis_factor: Vector3 = abs_axis * factor
92 var apply_scale: Vector3 = scale_vec + axis_factor
93
94 var pos_factor = ((apply_scale - ONE_VEC) / 2) * axis
95
96 node.position = first_position
97 node.scale = first_scale
98 node.translate_object_local(pos_factor)
99 node.scale_object_local(apply_scale)
100
101func _set_handle(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool, camera: Camera3D, screen_pos: Vector2) -> void:
102 var node := gizmo.get_node_3d()
103 var pos = _get_projected_pos(gizmo, handle_id, camera, screen_pos)
104
105 if not pos is Vector3:
106 return
107
108 if not first_pos:
109 first_pos = pos
110 return
111
112 var o_pos := first_pos as Vector3
113 var m_pos := pos as Vector3
114 var axis := handles[handle_id]
115
116 var offset := (m_pos - o_pos) * axis
117
118 var scale_snap: float = EditorInterface.get_node_3d_translate_snap()
119
120 var handle_diff := offset.length()
121 var snap_diff = handle_diff
122
123 if EditorInterface.is_node_3d_snap_enabled():
124 snap_diff = roundf(handle_diff / scale_snap) * scale_snap
125
126 var handle_dot := offset.normalized().dot(axis)
127 var handle_dir = sign(handle_dot)
128
129 var handle_diff_vec = axis * snap_diff * handle_dir
130
131 _update_node(node, handle_diff_vec, axis, scale_snap)
132
133 node.update_gizmos()
134
135func _get_projected_pos(gizmo: EditorNode3DGizmo, handle_id: int, camera: Camera3D, screen_pos: Vector2) -> Variant:
136 var node := gizmo.get_node_3d()
137 var pos_vector = Vector3(0, node.global_position.y, 0)
138 var plane = Plane(node.global_basis.y, pos_vector)
139 if handle_id == 0 or handle_id == 3:
140 pos_vector = Vector3(node.global_position.x, 0, node.global_position.z)
141 plane = Plane(node.global_basis.z, pos_vector)
142
143 var from := camera.project_ray_origin(screen_pos)
144 var pos = plane.intersects_ray(from, camera.project_ray_normal(screen_pos) * 4096.0)
145
146 return pos
147
148