How to align an instance of an object to a collision normal?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By wowzzers

When shooting a raycast from the center of the screen and creating and object in the hit position, how to correctly align your object or particle with the hit normal? Here’s my code:

var from = camera.global_transform.origin
var to = from + -camera.global_transform.basis.z * ray_length
var space_state = get_world().direct_space_state
var result = space_state.intersect_ray(from, to, [self])
if not result.empty():
	var impact_fx = scn_impact_fx.instance()
	get_tree().root.add_child(impact_fx)
	impact_fx.translation = result.position
	impact_fx.rotation = result.normal # HERE
	impact_fx.emitting = true

I’am just trying to rotate it based on a normal, I know I’m doing it wrong. Please help!

I’ve also tried this:

imapct_fx.global_transform.basis = Basis(result.normal)

Here’s a screenshot:
enter image description here

I am using Godot 3.1. Thank you!

try:
impact_fx.global_transform=impact_fx.global_transform.looking_at(camera.global_transform.basis.z+result.normal, camera.global_transform.basis.z)

Explanation:
looking_at returns a copy of the transform where -z is pointing at the target coordinate. Which i calculated as its own position + the normal.
You also need an up vector. I chose to select the opposite ray direction. (

wombatstampede | 2019-03-18 21:00

Doesn’t work, sorry
enter image description here

wowzzers | 2019-03-19 06:54

Ok, about your initial post:
You set the rotation (radian angles) of the Scene with the normal vector (coordinates). Obviously that didn’t work.

try:
impact_fx.look_at(impact_fx.global_transform.origin+normal,camera.global_transform.basis.z)
I did a “typo”. (While the explanation described it hopefully correctly)

wombatstampede | 2019-03-19 10:09

impact_fx.look_at(impact_fx.global_transform.origin + result.normal, camera.global_transform.basis.z)

Tried this, same result :frowning:

wowzzers | 2019-03-19 12:45

I tried it out:

global_transform.origin=result.position
look_at(result.position+result.normal,$"../Camera".global_transform.basis.z)

As test, I assigned this to a spatial which has its “forward” in direction -z.
The “upside” of the spatial shows afterwards to the camera and -z toward the normal of the hit collision face.
You can also pass Vector(0,1,0) instead of camera.global_transform.basis.z if you want the “upside” of the scene to look upward (+y).

If this doesn’t work then I’d say, you check if your impact_fx doesn’t emit into -z direction.

wombatstampede | 2019-03-19 15:08

Unfortunately it doesn’t align. Here are the results: Video

I’m using this code:

result.collider.add_child(wound_fx)
wound_fx.global_transform.origin = result.position
wound_fx.look_at(result.position + result.normal, camera.global_transform.basis.z)

Impact effect (wound_fx) scene in it’s original object is facing upwards.

wowzzers | 2019-03-19 16:25

:bust_in_silhouette: Reply From: wombatstampede

I guess that you want to align your y-axis with the result normal of the raycast. look_at only aligns the -z-axis but i looked at the code and (hopefully) adapted the function to align the y-axis instead:

global_transform.origin=result.position
global_transform=look_at_with_y(global_transform,result.normal,$\"../Camera\".global_transform.basis.y)

func look_at_with_y(trans,new_y,v_up):
	#Y vector
	trans.basis.y=new_y.normalized()
	trans.basis.z=v_up*-1
	trans.basis.x = trans.basis.z.cross(trans.basis.y).normalized();
	#Recompute z = y cross X
	trans.basis.z = trans.basis.y.cross(trans.basis.x).normalized();
	trans.basis = trans.basis.orthonormalized() # make sure it is valid 
	return trans

(Sorry for the late answer, I thought that I posted it yesterday but somehow it seems that I never clicked the send button.)

Thank you for the answer! It seems to work but it has a weird glitch effect, inverted normals? Here’s the video.

wowzzers | 2019-03-21 12:29

func look_at_with_y(trans,new_y,v_up):
    #Y vector
    trans.basis.y=new_y.normalized()
    trans.basis.z=v_up*-1
    trans.basis.x = trans.basis.z.cross(trans.basis.y).normalized();
    #Recompute z = y cross X
    trans.basis.z = trans.basis.y.cross(trans.basis.x).normalized();
    trans.basis.x = trans.basis.x * -1   # <======= ADDED THIS LINE
    trans.basis = trans.basis.orthonormalized() # make sure it is valid 
    return trans

The basis.x was pointing in the wrong direction. Interesting what a messed up Basis can do.

Honestly, I don’t know why this is so (didn’t spend the time to look further into it), but it seems to work fine that way.
There surely is a nicer solution but perhaps you can live with a “working” solution. :wink:

wombatstampede | 2019-03-21 16:12

It did work! Thank you, wombatstampede!!!

wowzzers | 2019-03-21 20:19