How to project UI elements in 3D space relative to the camera?

Godot Version

4.4.1

Question

So, I’m currently working on the shooting systems for my project, Monkanics.

It’s third-person, meaning in certain scenarios, the place where the projectile actually goes doesn’t match the crosshairs position. Such as when the player is too close to a wall.

This is natural. What isn’t however, is the lack of communication for the player.

What I want to implement is a dynamic crosshair (I’m calling it an “Alt Crosshair”) that becomes visible when the muzzle’s raycasts doesn’t align with the camera’s raycast. (Similar to what’s implemented in other third-person shooter games)

Alt Crosshair texture I made.

alt_crosshair

I’ve got the alignment detection working properly, but I haven’t gotten the crosshair UI projection working properly yet. That’s what I need help implementing.

I want to project a TextureRect control node to the muzzle raycast’s hit location.


Code and Crosshair System

So, the relevant code is the following (This is incomplete):

# Triggers every physics tick in _physics_process

func check_raycast_alignment() -> void:
	
	# Update the camera raycast
	Camera_Raycast.force_raycast_update()
	
	# Create collision variables
	var Camera_Raycast_Collision_Point : Vector3 = Camera_Raycast.get_collision_point()
	var New_Muzzle_Raycast_Target_Location : Vector3 = Muzzle_Raycast.to_local(Camera_Raycast_Collision_Point)
	
	# Update muzzle raycast to go toward camera raycast hit location
	Muzzle_Raycast.target_position = New_Muzzle_Raycast_Target_Location
	Muzzle_Raycast.force_raycast_update()
	
	# Create hit distance variable
	var Muzzle_Raycast_Hit_Distance : Variant
	
	# Get the distance between the start/end of the muzzle raycast
	Muzzle_Raycast_Hit_Distance = Muzzle_Raycast.global_position.distance_to(Camera_Raycast.get_collision_point())
	
	# Check if the player is too close to a wall via the muzzle raycast
	if Muzzle_Raycast_Hit_Distance <= MIN_PROJECTILE_SHOOT_DISTANCE:
		
		Alt_Crosshair.show()
		
		#TODO Doesn't project to the correct position
		Alt_Crosshair.position = get_viewport().get_camera_3d().\
		unproject_position(New_Muzzle_Raycast_Target_Location)
		
	else:
		
		pass # Hiding functionality not implemented yet

Everything works except for these lines:

#TODO Doesn't project to the correct position
Alt_Crosshair.position = get_viewport().get_camera_3d().\
unproject_position(New_Muzzle_Raycast_Target_Location)

The crosshair projection works, but it doesn’t project to the right location.

(Also, the alt crosshair display is off-center. Instead of projecting from the center, it’s projecting from the top left corner, but that’s a separate issue)

The player scene is laid out like this (Has a CharacterBody3D root):

Camera raycast for reference:

Any help or understanding is very appreciated.

unproject_position takes global coordinates, maybe the to_local is hurting more than helping.

Your Muzzle_Raycast is updated but I don’t see you take the collision point? Only on the Camera raycast

1 Like

So, I tried getting the collision point of the muzzle raycast, and it works better.

I also got the hide() functionality working.

However, the alt crosshair doesn’t project the way I want it due to me miscalibrating the movement location of the projectile themselves.

When the camera and muzzle raycasts aren’t aligned, the projectiles follow the camera’s rotation instead of the muzzle raycast’s. That’s what I have to adjust.

Another thing, the texture is still offset at the top left (The top left of the texture is treated as the middle). I actually figured out how to fix this, I just change the pivot offset in the inspector to half of the image size (Silly me!):

Since the issue is no longer with the UI, I’ll mark this is the solution. Thanks for the help, Gert. :+1:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.