Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix motion & drag event in 'GUI in 3D' #1108

Open
hippogyz opened this issue Aug 26, 2024 · 0 comments
Open

Fix motion & drag event in 'GUI in 3D' #1108

hippogyz opened this issue Aug 26, 2024 · 0 comments
Labels

Comments

@hippogyz
Copy link

Which demo project is affected:
GUI in 3D

Issue description:
The variables last_event_pos2D and last_event_time will be assigned repeatedly in same frame, if there are multiple events triggered in one frame.
It leads to wrong event data for InputEventMouseMotion and InputEventScreenDrag which need last frame's info.
These variables should be assigned at most once per frame.

Step to reproduce:

  1. Set project settings input_devices/pointing/emulate_touch_from_mouse to true
  2. Add a ScrollContainer and some scrollable Nodes to the main scene.
  3. The ScrollContainer does not response to mouse dragging in 3D scene.

Modification should fix it:

...

+ var record_frame = 0
+ var record_pos2D : Vector2
+ var record_event_time : float

func _mouse_input_event(_camera: Camera3D, event: InputEvent, event_position: Vector3, _normal: Vector3, _shape_idx: int) -> void:
	# Get mesh size to detect edges and make conversions. This code only supports PlaneMesh and QuadMesh.
	var quad_mesh_size: Vector2 = node_quad.mesh.size

	# Event position in Area3D in world coordinate space.
	var event_pos3D := event_position

	# Current time in seconds since engine start.
	var now := Time.get_ticks_msec() / 1000.0

	# Convert position to a coordinate space relative to the Area3D node.
	# NOTE: `affine_inverse()` accounts for the Area3D node's scale, rotation, and position in the scene!
	event_pos3D = node_quad.global_transform.affine_inverse() * event_pos3D

	# TODO: Adapt to bilboard mode or avoid completely.

	var event_pos2D := Vector2()

	if is_mouse_inside:
		# Convert the relative event position from 3D to 2D.
		event_pos2D = Vector2(event_pos3D.x, -event_pos3D.y)

		# Right now the event position's range is the following: (-quad_size/2) -> (quad_size/2)
		# We need to convert it into the following range: -0.5 -> 0.5
		event_pos2D.x = event_pos2D.x / quad_mesh_size.x
		event_pos2D.y = event_pos2D.y / quad_mesh_size.y
		# Then we need to convert it into the following range: 0 -> 1
		event_pos2D.x += 0.5
		event_pos2D.y += 0.5

		# Finally, we convert the position to the following range: 0 -> viewport.size
		event_pos2D.x *= node_viewport.size.x
		event_pos2D.y *= node_viewport.size.y
		# We need to do these conversions so the event's position is in the viewport's coordinate system.

	elif last_event_pos2D != null:
		# Fall back to the last known event position.
		event_pos2D = last_event_pos2D

+	# Update last frame state (only update once per frame)
+	if record_frame != Engine.get_process_frames():
+		record_frame = Engine.get_process_frames()
+		last_event_pos2D = record_pos2D
+		last_event_time = record_event_time
+		
+		record_pos2D = event_pos2D
+		record_event_time = now
	
	# Set the event's position and global position.
	event.position = event_pos2D
	if event is InputEventMouse:
		event.global_position = event_pos2D

	# Calculate the relative event distance.
	if event is InputEventMouseMotion or event is InputEventScreenDrag:
		# If there is not a stored previous position, then we'll assume there is no relative motion.
		if last_event_pos2D == null:
			event.relative = Vector2(0, 0)
		# If there is a stored previous position, then we'll calculate the relative position by subtracting
		# the previous position from the new position. This will give us the distance the event traveled from prev_pos.
		else:
			event.relative = event_pos2D - last_event_pos2D
			event.velocity = event.relative / (now - last_event_time)

-	## Update last_event_pos2D with the position we just calculated.
-	#last_event_pos2D = event_pos2D
-
-	## Update last_event_time to current time.
-	#last_event_time = now

	# Finally, send the processed input event to the viewport.
	node_viewport.push_input(event)

...
@hippogyz hippogyz added the bug label Aug 26, 2024
@godotengine godotengine deleted a comment Aug 26, 2024
@godotengine godotengine deleted a comment Aug 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant