Hello everyone, I’m doing a project in virtual reality, working with the Meta Quest 2, and I’m facing a problem I cannot seem to be able to solve and I need to solve as soon as possible. Sadly I wasn’t able to record a video directly from the VR headset, so I’ve attached a screen recording.
https://www.youtube.com/watch?v=_FiMg0aSf2A
I have an object which is the endpoint of the ray you can see in this screenshot.
This object can move within a “cage” of colliders and should not be able to escape. My goal is to be able to move it smoothly without getting stuck in the colliders, which is something that happens sometimes.
The endpoint object has a sphere collider (isTrigger=true) and a rigidbody component (no gravity, isKinematic=true, continuous dynamic collision detection). The cage of colliders is related to the 3d model object of a cube from which the volume of a weird cone with a concavity has been hollowed out.
So I have basically two colliders: a box collider to cover the opening at the base of the cone and a concave mesh collider that follows the mesh of the 3D model with precision. I know that it’s hard to work with mesh colliders, especially when not convex, but as of now I am successful in keeping the sphere collider of the endpoint object inside, as you can see in the video.
Now let’s talk about the movement of the object, giving as premise that doing a raycast is not an option in my case and that I’m using the XR Interaction suite, more specifically the XR Direct Interactor component. What I do instead is take the position of my hand (the small white sphere, you can IGNORE the red ray coming from it) at each FixedUpdate, find the difference with the previous position, calculate the distance, and multiply this distance by a certain factor to scale it for the endpoint object which is far away. I then make sure that I don’t move too far away and check collisions. The actual movement is performed on the RigidBody component with the MovePosition function. I’m not sure that every single one of the aforementioned checks are 100% needed. Here’s the code.
private void HandleRayEndpointMovement(out float finalNewDistance)
{
int index = 0;
Vector3 pointerMovement = Vector3.zero;
float distance = 0;
// Loop through each pointer and calculate the movement for the one that is moving the most
foreach (Pointer pointer in pointers)
{
// Get the current pointer position and the previous frame pointer position
Vector3 currentPointerPosition = pointer.transform.position;
Vector3 previousPointerPosition = pointer.GetPreviousPosition();
float newPointerDistance = Vector3.Distance(currentPointerPosition, previousPointerPosition);
if(newPointerDistance > distance)
{
distance = newPointerDistance;
// Calculate the pointer's movement vector
pointerMovement = currentPointerPosition - previousPointerPosition;
index = pointers.IndexOf(pointer);
}
}
// Apply a multiplier to make the movement more significant
Vector3 scaledMovement = pointerMovement * sauronMovementMultiplier;
// Smooth the movement vector
smoothedMovement = Vector3.Lerp(smoothedMovement, scaledMovement, smoothTime);
// Calculate new potential position of the ray's endpoint
Vector3 newEndPointPosition = rayEndPoint.position + smoothedMovement;
// Calculate the maximum distance the endpoint can move to stay inside the cage of colliders
float maxDistance = 0f;
Vector3 direction = newEndPointPosition - previousPosition;
RaycastHit hit;
if (Physics.Raycast(previousPosition, direction, out hit))
{
maxDistance = hit.distance;
}
if(direction.magnitude > maxDistance)
{
direction = direction.normalized * maxDistance;
}
newEndPointPosition = previousPosition + direction;
// Update alpha and beta angles of the cone, so that the values based on them to be sent to the
// physical Sauron can be computed
UpdateConeAngles(newEndPointPosition);
// Check for collision
if (!IsColliding(newEndPointPosition))
{
previousPosition = rayEndPoint.position;
rayEndPointRb.MovePosition(newEndPointPosition);
Debug.Log($"DIO: Sphere moved to: {newEndPointPosition}");
}
else
{
// Send haptic feedback to the hand controller
ProvideHapticFeedback(index, colliderHapticFeedbackAmplitude, colliderHapticFeedbackDuration);
}
finalNewDistance = Vector3.Distance(coreCenter.position, rayEndPoint.position);
}
bool IsColliding(Vector3 targetPos)
{
Collider[] colliders = Physics.OverlapSphere(targetPos, sphereCollider.radius);
foreach (var coll in colliders)
{
if (coll == portalBoxCollider || System.Array.Exists(portalSupportColliders, c => c == coll))
{
return true;
}
}
return false;
}
In the video you can see that I’m in control of the object when the line renderer is yellow. That’s when it’s possible to move the endpoint object and that happens more in detail when my hand controllers are inside another collider near me. You can see how the endpoint sometimes gets stuck in the surface of the colliders and doesn’t always smoothly move. You can do some precise movements to actually direction it quite smoothly, but his project will be used for some tests with people who do not know anything about it.
One last thing: I tried also to add physic materials to the cage of colliders and the endpoint object sphere collider, but they helped me only to a certain extent.
Does anyone have an idea on how to improve this whole thing and make the control of that object smoother? Thank you in advance.


