VR Rig Flickering Issue When Parenting to Car Controller

Hi, I have a small problem with the car controller. I’m working on a project and adapting the car controller code to my needs, but I ran into a little issue. Unlike your example, I’m using a teleport to get inside the car. The problem is that I’m making the rig a child of the object that has the car controller so the rig can follow the car, and it works fine, but sometimes there’s a really annoying flickering. I was checking your example, and when you enter VR, for a moment that error appears but then it goes away. Any ideas or workarounds would be really helpful, thanks!

Hi boss15493,

This issue is likely related to how reparenting the XR rig during an active VR session can temporarily disturb the camera’s transformation updates. In our standard samples, the rig is usually not directly reparented when entering a car—instead, it’s updated (or “followed”) using local offsets so that abrupt changes and matrix recalculations in VR don’t cause flickering.

You might try one of the following workarounds:

• Instead of directly parenting the entire rig to the car controller, consider keeping the rig at the scene’s root and only update its position/rotation each frame to match the car’s movement. This avoids disrupting the VR camera’s update flow.

• If reparenting is necessary, delay the operation slightly—use a short wait (like 0.1 seconds) after the teleport before setting the rig’s parent. This gives the XR system time to stabilize its matrices before the parenting takes effect. For example:

import { Behaviour, serializable, WaitForSeconds } from "@needle-tools/engine";
import { Object3D } from "three";

export class VRRigReparenting extends Behaviour {
    @serializable(Object3D)
    vrRig?: Object3D;

    @serializable(Object3D)
    carController?: Object3D;

    async enterCar() {
        // Allow the XR system to stabilize after the teleport
        await WaitForSeconds(0.1);
        if(this.vrRig && this.carController) {
             this.vrRig.parent = this.carController;
        }
    }
}

• Also check that the car controller’s transform (especially its scale) is set to (1,1,1) when reparenting, since non-uniform scales can also lead to rendering artifacts in VR.

These strategies are similar to patterns used in our samples and documented practices in Needle Engine to avoid transient issues during VR mode at needle-engine-samples.json.md.

If the flickering persists or becomes problematic, a minimal reproduction (for instance, via Needle-engine - Vite Template (duplicated) - StackBlitz) can greatly help in further narrowing down the exact cause. Let me know if you need any more details or additional assistance!

4 replies left
thread_NnEXRKqaVoa5HtxE2q4uUgBp
Reply to this post directly if you need further help (bottom right button)

Updating the rig position each frame onBeforeRender is working really well, the problem is with the rotation — if a big rotation happens, the flickering continues. I tried smoothing the rotation with a slerp but the issue is still there, and I also tried delaying the rotation a bit with a setTimeout, but the same error keeps happening. Do you have any idea that might work?

Hi boss15493, it sounds like the abrupt or large rotations are interfering with the XR rig’s internal tracking, causing persistent flickering. In XR setups, the rig’s own rotation is usually dictated by head tracking, so trying to reapply an external rotation on the rig itself (even with slerp or delays) can lead to conflicts.

A common approach to solving this is to decouple the car’s rotation from the XR rig by using an intermediate container (or “seat anchor”). Instead of directly updating the rig’s rotation, you place the rig as a child of an anchor object. Then, update the anchor’s transform to follow the car’s position and rotation. This way, the XR rig maintains its internal tracking while the anchor smoothly inherits the car’s rotation without causing flickering.

Here’s a sample component illustrating this approach:

import { Behaviour, serializable } from "@needle-tools/engine";
import { Object3D } from "three";

export class CarSeatRotationFollower extends Behaviour {
  // The anchor object that will smoothly follow the car
  @serializable(Object3D)
  seatAnchor!: Object3D;
  
  // The car controller object whose rotation we need to follow
  @serializable(Object3D)
  carController!: Object3D;

  update() {
    if (!this.seatAnchor || !this.carController) return;
    
    // Smoothly update the anchor's rotation using slerp
    this.seatAnchor.quaternion.slerp(
      this.carController.quaternion,
      this.context.time.deltaTime * 5.0
    );
    
    // Update position instantly or apply smoothing as needed
    this.seatAnchor.position.copy(this.carController.position);
  }
}

In your scene, you’d then ensure that the XR rig is a child of this seatAnchor, not directly reparented to the car controller. This technique prevents the XR system’s update routine from conflicting with the externally applied rotations.

This pattern—using an intermediate container to handle external transforms—is consistent with best practices in Needle Engine (see, for example, the rig-following logic in XR controller components at XRControllerFollow.d.ts.md). It helps to isolate sudden rotation changes of the vehicle from the XR head tracking, thereby reducing or eliminating flickering even when big rotations occur.

Give this a try, and let me know if it resolves the flickering or if you need further tweaks or additional help!

4 replies left
thread_NnEXRKqaVoa5HtxE2q4uUgBp
Reply to this post directly if you need further help (bottom right button)

I thought the main idea was that the rig shouldn’t have any parent

Hi boss15493, you’re absolutely correct—the best practice in XR (and with Needle Engine) is to keep the rig unparented so its transform remains entirely driven by the XR hardware tracking. Directly parenting the rig (or even doing so via an intermediate container that alters its rotation) can cause conflicts with the internal updates and lead to flickering, especially when large rotations occur.

Instead of reparenting the rig to the car, you can update its world position (and if necessary, apply a calculated offset) while preserving its unparented structure. For example, you might compute the car seat’s world transform and then update the rig’s position accordingly during each frame update, without modifying its rotation. Any rotation-based visuals relevant to the vehicle—like an avatar or seat indicator—can be attached to a separate container that follows the car’s transform.

This approach is consistent with our XR components (as seen in our XRRig implementation at WebXRRig.d.ts.md) where the rig remains the root for accurate head tracking. That way, you prevent interference between the XR tracking system and your car’s transformations, avoiding the flickering you observed.

If you need further guidance on computing and applying such offsets without reparenting the rig, let me know!

3 replies left
thread_NnEXRKqaVoa5HtxE2q4uUgBp
Reply to this post directly if you need further help (bottom right button)

Hi @boss15493 the XRRig can be parented to moving objects, the bot is not right here. I’ve done this before when working on the car example.

Which Needle Engine version are you currently using?

Can you provide a bugreport?

Hi Marcel, I’m currently on version 4.4.3. Ok, I’ll go ahead and file a bug report, but I wanted to mention that in the example you have on the website the same error also shows up, but only for about 2 seconds when starting inside the car. I tested it using the Meta Quest 3 and in the Meta Browser. In my case, I followed the bot’s advice and created a CarSeatHandler class so the rig follows the car and a little delay with a courtine for the rotation, and it works except when we’re making a turn — though little by little the error goes away. I also thought maybe it was related to frame rate, and in that case it only happens once. I’d love to share the videos with you, but since this is a client project I can’t post them here. However, if you let me I could send them to you in a Dm if that helps.

Hi @boss15493 thanks for the additional info. Please send a DM sure. I’ll see if I can reproduce the issue. You’re refering to this example? Car Physics | Needle Engine

Hi Marcel, yes that’s the example I was referring to.

The issue should be fixed in 4.9.0-alpha

Thanks for the help :clap:.