Convert normal to vector

Godot Version

4.3 stable

Question

Searching the internet for hours now, and it seems this is a very hard problem…

I have a raycast in 3d. The raycast hits some collision and i … foolishly… expected this to work:

	if ray.is_colliding():
		pivotGuide.global_position = ray.get_collision_point()
		pivotGuide.global_rotation = ray.get_collision_normal()

(pivotGuide is just a red,green,blue object to show what is going on)

looks like this:

should look like this of course:
should

reading up on these things reveals that this is not at all possible since a normal and a vector3 is not actually the same.

So far i’ve come across questionable intricate calculations to solve and in most cases not really solve this.

Can it really be true? Is it really that complicated for us to get this to work?

I would have hoped for some functionality that looked like this:

pivotGuide.global_rotation = ray.get_collision_normal_as_vector()

normals are vectors, just not a representation of rotation. You might use look_at_from_position to achieve the effect you want.

if ray.is_colliding():
	var pos: Vector3 = ray.get_collision_point()
	var normal: Vector3 = ray.get_collision_normal()

	pivotGuide.look_at_from_position(pos, pos + normal)
3 Likes

Expanding on this answer:

The normal vector does not provide complete information for 3D orientation.
There is an “up” argument in look_at_from_position which defaults to +Y.

For many use cases, that may be just fine.
For others, you may have to specify your “up” such that the remaining two vectors of your object point in meaningful directions.

There is also the special (but potentially common) case of your normal pointing directly along +Y, in which case the default +Y “up” vector in look_at[_from_position] will not produce expected behavior.
There would be a singularity AKA gimbal lock.

2 Likes

ok thanks guys. i’ll try this out.

thanks i’ll try this out! :smiling_face_with_three_hearts:

freaking works!!! This is 500% more efficient than all the 20 line attempts ive found on here and reddit! Thank you sensei

well… unless the normal is just straight up. Then it gives up. Hmm wondering why that is.

Alright final solution here!

	if ray.is_colliding():
		var pos: Vector3 = ray.get_collision_point()
		var normal: Vector3 = ray.get_collision_normal()
		pivotGuide.global_position = pos
		if normal == Vector3(0,1,0):
			pivotGuide.global_rotation = Vector3(PI/2,0,0)
		else:
			pivotGuide.look_at_from_position(pos, pos + normal)