Passing click events into spatial viewports, from a viewportsprite.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By avencherus
:warning: Old Version Published before Godot 3 was released.

Anyone have any thoughts on the best way to pass mouse click coordinates accurately into a viewport of a 3D world, from clicking a viewportsprite that is rendering it?

I’m trying to click on 3D objects, but I’m heading down a path that is probably going to be way complicated than it probably needs to be.

The general easy way to get relative mouse coordinates is using a CollisionObject2D (like Area2D), maybe you can translate that value to the spatial viewport/camera and then I’m lost.

eons | 2016-10-28 12:57

What I ended up doing was just creating a function that forwarded the mouse position to the spatial node inside of the sub-viewport. From there I did a raycast of my own. The PhysicsServer version kept crashing, so I just used the node RayCast instead, and attached it to the camera.

As long as you don’t sub-scene it the spatial node, it will reference the viewport node’s dimensions.

Before I was doing some aspect ratio conversions, but after finding that it’s just become a couple lines of code. I’ll post the code as an answer.

avencherus | 2016-10-29 08:56

:bust_in_silhouette: Reply From: avencherus

Posting my solution here, in case anyone finds it helpful.

As long as it’s all structured in the same scene it’s not terribly difficult. I ended up forwarding the click position into the sub-viewport’s root Spatial node, and did a raycast using a RayCast node attached to the camera.

In the calling node:

extends ViewportSprite

onready var vp_scene = get_parent().get_node("viewport/root")

func _ready():
	set_process_input(true)

func _input(event):
	
	if(event.type==InputEvent.MOUSE_BUTTON):
		vp_scene.forward_click(event.pos - get_global_transform().get_origin())

In the receiving Spatial node:

onready var camera = get_node("camera")
onready var click_cast = get_node("camera/click_ray")

var ray_length = 3

func forward_click(click_pos):
	click_cast.set_cast_to(camera.project_ray_normal(click_pos) * ray_length)

func _fixed_process(delta):
	
	if(click_cast.is_colliding()):
		print(click_cast.get_collision_point())
		# DO STUFF

func _ready():
	set_fixed_process(true)
:bust_in_silhouette: Reply From: bath_idea

Just enable viewport’s property Physics->Object Picking no need any script for this simple issue.