![]() |
Attention | Topic was automatically imported from the old Question2Answer platform. |
![]() |
Asked By | VanKurt |
I have a basic 3D VR scene. To the player’s hand I have attached a mesh (just as a visual aid) and a raycast. The mesh follows the movement of my (real life) hand very nicely. So everything seems to be set up correctly.
But sadly the ray cast never returns any hit:
func _physics_process(delta):
if($RayCast.is_colliding()):
print("hit")
Of course I have some rigid bodies with collision shapes in my scene. Also the RayCast is set to Enabled in the inspector.
PS: When I put the RayCast + Script directly into my scene (NOT as a child of my VR hand node, but directly under the scene’s root node), it actually works!
Do I have to do some extra steps to use a RayCast as a child of another node?
Did you check the layer / mask? Also check collide with parent.
DaddyMonster | 2021-02-24 15:22
In the collision mask I turned everything on. Collide with parent is disabled.
VanKurt | 2021-02-24 15:55
In order to debug this, I am now trying to add a visualization for my RayCast. So far I added a marker mesh to the ray’s origin like this:
$Marker.global_transform.origin = $RayCast.global_transform.origin
This looks good, the marker is exactly where my hand is and where the RayCast should start.
Now I would like to add a second marker to show which direction the ray is going. Can anyone give me a hint on how to get a point somewhere along the ray of my RayCast (in absolute world coordinates)?
$Marker2.global_transform.origin = ?
VanKurt | 2021-02-25 07:26
Nice logical approach. Getting a direction from an obj to a target obj is just a case of subtracting the target origin from the start point origin. So:
var tar_vec = ($RayCast.global_transform.origin - $Marker.global_transform.origin).normalized()
You can get the distance between them with:
var dist = $RayCast.global_transform.origin.distance_to($Marker.global_transform.origin)
If you want to get any point along the line:
var point_between = tar_vec * tar_dist * 0.5
0.5 gives you the point exactly halfway between the hand and the target.
You can’t make a VR game without knowing this so I’ll take a moment to explain why:
Imagine you had a starting position in 2d of say Vector2(1, 2)
(hand) and a target of Vector2(1, 4)
(ray cast interception point) then getting to the target vector from the hand means adding Vector2(0, 2)
- normalize this to a unit vector and you get Vector2(0, 1)
- it’s above / on the positive y.
That’s to say, Vector2(1, 4) - Vector2(1, 2) = Vector2(0, 2).normalized() = Vector2(0, 1)
. Then you can multiply this unit vector to scale it.
Hope that helps.
EDIT: This all assumes the ray cast is working and you have the target vector. If not you can get the direction vector of the ray and scale that unit vector. This can be got/set with $RayCast.cast_to
- in global space this is $RayCast.global_transform.origin + $RayCast.cast_to * scalar
Lazy option: You can save yourself the code and just go to “debug/visible collision shapes” at the top dropdown menu and Godot will show the ray when you run the game.
DaddyMonster | 2021-02-25 10:58
Hey, thanks’s for the detailed reply. What you say totally makes sense.
Maybe I understood the cast_to property of the RayCast wrong. I thought it was relative to the RayCast’s parent node (thus in local coordinates). So i set it to (0,0-1) (aka “forward”), so that the ray will always point in the direction my hand is pointing (which the RayCast is a child of).
Thus showing my second marker like this
$Marker2.global_transform.origin = $RayCast.global_transform.origin + $RayCast.cast_to * 1.0
would not make much sense, since it would not actually show the direction of my ray. Instead the cast_to vector would be interpreted in world coordinates. and thus always show in the same fixed direction.
So is the cast_to vector meant to be in global coordinates, or is it in local coordinates and rotates with its parent node?
VanKurt | 2021-02-25 13:37
Local space buddy. If you want to transform from local to global space, that’s a little bit more advanced, you need Transform.xform(Vector3) / xform_inv. I’m not following why that would be necessary here. You want it as a child of your hand, you don’t want to manually transform everything from global to local space and back, let Godot handle that for you.
My guess would be that in local space it’s just pointing the wrong way. It defaults to Vector3(0, -1, 0) (I never got why they chose DOWN and not FORWARD as default… Probably there’s a good reason / convention I don’t know about).
Anyway, try clicking “visible collision shapes” in Debug, running the game and see where the raycast red line is pointing in game. You might need to change it: $RayCast.set_cast_to(Vector3.FORWARD)
or whatever in the_ready
method or just do it manually by changing the “cast to” vector in the editor. If it’s working in global space and not local then that’s by far the most likely explanation.
DaddyMonster | 2021-02-25 14:04
Sadly the debug shapes are not visible when running my game on the Oculus Quest
But after LOTS of trying around I finally found a clue: the ray seems to have a very limited range! When i walk close up to an object, the ray actually starts hitting hit. When I then move my hand/the raycast slowly backwards, it stops hitting the target at a certain distance (feels like 1 meter in VR).
This is repeatable:
ray origin closer than 1m to the target → hit
ray origin more than 1m away from target → no hit
Is there some sort of hidden max range setting on the raycast? Or must the cast_to vector be “longer”, e.g. (0,0-1000) instead of (0,0,-1)?
VanKurt | 2021-02-25 14:30
all you really need, to visualize it is enable show collisions in the debug menu on the top.
zen3001 | 2021-02-26 13:02