Raycast from VR camera (Quaternion to Vector 3)

0

The HMD tracking state returns a pose state with a quaternion orientation. Raycast takes a vector 3 for its direction. How do I get a vector3 from a quaternion, or otherwise how do I raycast from the VR camera?

In fact I haven't been able to figure out how to raycast from any camera. I never seem to get any hits. I think the orientation is wrong but it could be something else. I can't eliminate anything though because I have no idea how it works.

In flowgraph there's at least the debug draw line function which I could use to see where the raycast was going, but that doesn't seem to be exposed to Lua.

asked 7 years ago212 views
9 Answers
0
Accepted Answer

Hi @REDACTEDUSER

I'm going through your questions one by one, but I wanted to show you a quick way to work with Quaternions in Lua to get the direction vector you desire. As always, you may already be familiar with most or all of this, but I'm including this for completeness.

You may grab the rotation quaternion another way but here is a quick example of using the bus system in Lua:


local quat = TransformBus.Event.GetWorldRotationQuaternion(self.entityId)
local rayDir = quat * Vector3(1,0,0)

If you are wondering how the quat * Vector3(1,0,0) works, there are a couple of things going on in the above code.

First, there is already a function overload (using the multiplication * symbol) that automatically rotates a vector by that quaternion rotation - you only need to call it in lua by multiplying the two. Second, a 0 degree rotation is traditionally represented by the vector 1,0,0 - a unit vector (vector of total length 1) along the x-axis with no rotation. This means that we can get the actual rotation in vector form by taking this 1,0,0 vector and multiplying it by our quat, giving us the exact direction to raycast in!

Let me know if this helps you out!

answered 7 years ago
0

Actually I can't seem to get raycasting to work at all. The only time I can get hits from a raycast in Lua is if I set:

raycastconfig.direction = (0.0, 0.0, 0.0)

Then I get (maxhits + 1) hits on entityId [4294967295]. If I change any of those values even to something like 0.00000001, I get zero hits.

I haven't found any other combination of values to set that results in a hit.

What value am I supposed to use to cast a ray in the direction a camera is facing? Raycastconfig direction takes a vector3, but that could be literally any set of 3 values, and there don't seem to be any vector3 values/types in Lumberyard that store orientation. Quaternions, matrices, euler angles all don't work here.

I tried using:

local cameraTransform = TransformBus.Event.GetWorldTM(self.entityId)
rayCastConfig.direction = cameraTransform:GetColumn(1)

As I've seen in some examples, but it also doesn't return any hits.

I have a test level with a camera that pans with mouse control, and a cube. No matter how I turn the camera or play with the variables I can't hit the cube with a raycast. Here's the code I've tried:

    RCTestRaycast = {
Properties = {
}
}
function RCTestRaycast:OnActivate()
self.tickBusConnection = TickBus.Connect(self)
end
function RCTestRaycast:OnTick()
local rayCastConfig = RayCastConfiguration()
local cameraTransform = TransformBus.Event.GetWorldTM(self.entityId)
rayCastConfig.origin = cameraTransform:GetTranslation()
local eulerRotation = TransformBus.Broadcast.GetEulerRotation(self.entityId)
rayCastConfig.maxDistance = 20
rayCastConfig.physicalEntityTypes = 15
rayCastConfig.maxHits = 10
--It seems likeliest that the direction is configured incorrectly. Here are
--some directions and how many hits they return:
--returns 0 hits
--rayCastConfig.direction = cameraTransform:GetColumn(1)
--returns (maxHits + 1) hits on entityId:[4294967295].
--Changing even one vector value to "0.000001" results in zero hits.
--What is going on here?
--rayCastConfig.direction = Vector3(0, 0, 0)
--returns 0 hits
--rayCastConfig.direction = TransformBus.Event.GetEulerRotation(self.entityId)
rayCastResult = PhysicsSystemRequestBus.Broadcast.RayCast(rayCastConfig)
hitCount = rayCastResult:GetHitCount()
hasBlockingHit = rayCastResult:HasBlockingHit()
local hit1 = rayCastResult:GetHit(1)
local blockingHit = rayCastResult:GetBlockingHit()
--local hitEntityId = hit1.entityId
Debug.Log("camera transform = "..tostring(cameraTransform))
Debug.Log("rayCastConfig.origin = "..tostring(rayCastConfig.origin))
Debug.Log("rayCastConfig.direction = "..tostring(rayCastConfig.direction))
Debug.Log("************************")
Debug.Log("hitCount = "..tostring(hitCount))
Debug.Log("hasBlockingHit = "..tostring(hasBlockingHit))
--Debug.Log("hit1.position = "..tostring(hit1.position))
--Debug.Log("hit1.entityId = "..tostring(hit1.entityId))
--Debug.Log("blockingHit.entityId = "..tostring(blockingHit.entityId))
end
function RCTestRaycast:OnDeactivate()
self.tickBusConnection:Disconnect()
end
return RCTestRaycast
answered 7 years ago
0

Let me see if I can get you some answers on this :)

answered 7 years ago
0

I have not yet resolved the issue of trying to issue a raycast from the VR camera / along the VR camera's orientation.

I have resolved the secondary issue of getting the raycast to work at all. The issue was that raycasts can only hit objects which have certain components attached, in this case a mesh collider component to ensure that the raycast could "collide" with the entity at all points defined by its mesh, and a rigid body physics component.

A raycast from camera can be oriented using direction = cameraTransform.basisY or cameraTransform:GetColumn(1), although I don't understand why either of these works.

answered 7 years ago
0

I've made some progress by realizing that the trackingState.pose.position is a relative position, not a global translation.

I'm not clear on what is actually centering the position of the VR camera right now. I don't have it tied to any entity as far as I can tell, but it seems to respond to the map's camera entity. The VR camera appears a meter or two above the camera entity. Not sure why.

It also seems like raycasting from the headset is an unreliable way to figure out what the user is looking at. I'm still not sure if this is due to camera shift causing the center of focus to be misunderstood, or if there's some other issue with positioning that I'm not aware of.

Is there a better way to do this, or should I be raycasting?

answered 7 years ago
0

Hi @REDACTEDUSER

I'm going through your questions one by one, but I wanted to show you a quick way to work with Quaternions in Lua to get the direction vector you desire. As always, you may already be familiar with most or all of this, but I'm including this for completeness.

You may grab the rotation quaternion another way but here is a quick example of using the bus system in Lua:

local quat = TransformBus.Event.GetWorldRotationQuaternion(self.entityId)

local rayDir = quat * Vector3(1,0,0)

If you are wondering how the quat * Vector3(1,0,0) works, there are a couple of things going on in the above code.

First, there is already a function overload (using the multiplication

  • symbol) that automatically rotates a vector by that quaternion rotation - you only need to call it in lua by multiplying the two. Second, a 0 degree rotation is traditionally represented by the vector 1,0,0 - a unit vector (vector of total length 1) along the x-axis with no rotation. This means that we can get the actual rotation in vector form by taking this 1,0,0 vector and multiplying it by our quat, giving us the exact direction to raycast in!

Let me know if this helps you out!

answered 7 years ago
0

Thanks, that does answer that question and make it more clear what needs to be done. It's also good to know about the (1, 0, 0) vector.

I wound up doing this:


--Script attached to camera entity
local cameraTransform = TransformBus.Broadcast.GetWorldTM(self.entityId)
local cameraTranslation = cameraTransform:GetTranslation()
local trackingState = HMDDeviceRequestBus.Broadcast.GetTrackingState()
local hmdOrientation = trackingState.pose.orientation
local hmdTransform = Transform.CreateFromQuaternionAndTranslation(hmdOrientation, cameraTranslation)
...
rayCastConfig.direction = hmdTransform:GetColumn(1)<br>

Which seems to work. It can be very hard to tell if the raycast is hitting the exact center of view with an HMD.

I've been running into other issues. I'm not sure why the HMD offset doesn't seem to come into play. Also sometimes, moving the camera entity in the editor seems to break the raycast somehow. I'm still not confident I'm getting the overall angle exactly right.

Finally, I can't figure out what combination of components is needed to create an entity that will be hit by a raycast. The only things that seem to work reliably are the water (terrain hit) and a character physics component. A static mesh + mesh collider (+physics component?) should work, but it doesn't. Is there something in the cfg that could affect this, or some other file? I still can't tell if it's because of the entity configuration or if my orientation/translation are wrong.

answered 7 years ago
0

Hi @REDACTEDUSER

Glad that answered your question! The components you should need are the physics components (collider component with a shape component if it is a primitive collider). Raycasts are always tricky - a good way to test to put your test object right in front of your raycaster, or even surrounding it, so you know it has to be hit. That should tell you if you have the right components, or if you are somehow missing it with the raycast direction!

Thanks for all of these great questions. Please keep asking them, and don't be afraid to create new posts for each one - we like to create as many visible posts as possible. Your new post and question now is an answer for another dev down the line!

Let me know if this helps!

answered 7 years ago
0

Hi @Catma,

You are correct! Raycasting relies on the physics system, and thus requires a collider component (not necessarily a mesh collider, primitive colliders work too!) to function correctly. Raycasting is traditionally tied to the physics system (sometimes graphics), but uses these systems not only to achieve results, but generate them efficiently.

The reason that the cameraTransform.basisY works is because the camera's forward direction is tied to the y-axis. When you create a camera, you may notice that the camera faces in the way direction. As the camera moves, it's own internal direction is determined by column 1, also known as its y basis.

answered 7 years ago

This post is closed: Adding new answers, comments, and votes is disabled.