Rotating a 3D bullet hole decal based on raycast collision using gdscript

Godot Version 4.2

Question

I’m very new to Godot and have a basic weapon management system set up with hit scan weapons. The hit scan weapons create a ray using code and instantiate a bullet hole decal if there’s a collision. The problem is that I need to rotate the decal depending on the surface it collides with so that it shows properly.

Most people I’ve seen use a raycast node as a child of the camera and get the collision that way, but I’m not sure that’s possible in my case. I’ve seen some suggest using look_at( ) and get_collision_normal( ) but that seems to cause an error “Invalid call. Nonexistent function ‘get_collision_normal’ in base ‘Dictionary’”.

Here’s the relevant code. The first function Get_Camera_Collision returns the collision point, the second function creates the decal.

# Get the location currently being aimed at
# Return a Vector3 value
func Get_Camera_Collision()->Vector3:
	var camera = get_viewport().get_camera_3d() # Get the camera
	var viewport = get_viewport().get_size() # Get the viewport size
	
	# Center of screen
	var Ray_Origin = camera.project_ray_origin(viewport/2)
	# Distance of ray cast
	var Ray_End = Ray_Origin + camera.project_ray_normal(viewport/2) * Current_Weapon.Weapon_Range
	
	# Create ray parameters
	var New_Intersection = PhysicsRayQueryParameters3D.create(Ray_Origin,Ray_End)
	# Get intersection location
	var Intersection = get_world_3d().direct_space_state.intersect_ray(New_Intersection)
	
	# Check for a ray intersection
	if not Intersection.is_empty():
		# Get Colision Point
		var Col_Point = Intersection.position
		return Col_Point
	# Return end point even if there isn't an intersection (for projectile weapons)
	else:
		return Ray_End
var Debug_Bullet = preload("res://resources/scene resources/bullet_debug.tscn")

# Check for Hit Scan Collision
func Hit_Scan_Collision(Collision_Point):
	
	# Create Intersection, exclude player weapon projectiles from being targeted
	var New_Intersection = PhysicsRayQueryParameters3D.create(Bullet_Point.get_global_transform().origin,Collision_Point+Bullet_Direction*2)
	New_Intersection.set_exclude(Collision_Exclusion)
	# Check for Collision on Intersection
	var Bullet_Collision = get_world_3d().direct_space_state.intersect_ray(New_Intersection)
	
	if Bullet_Collision:
		# Add the hit indicator at the location of the bullet collision
		var Hit_Indicator = Debug_Bullet.instantiate()
		var world = get_tree().get_root().get_child(0)
		world.add_child(Hit_Indicator)
		Hit_Indicator.global_translate(Bullet_Collision.position)
		Hit_Indicator.look_at(Bullet_Collision.position + Bullet_Collision.get_collision_normal(), Vector3.UP) # Causes error

That error means that whatever your using
The get collision normal function on is a dictionary. You can check return types in the editor by ctrl clicking where you are getting the dictionary from. Ctrl clicking on an variable would lead to where the variable is declared if it isn’t built in. Sorry I can’t tell you the exact part of your code that the error is happening since I don’t know 3d or raycast function that well, but the advice I gave should work based on the error you are getting.