+1 vote

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.

in Engine by (5,206 points)

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.

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.

1 Answer

+2 votes

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)
by (5,206 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.