Passthrough Underlay No Longer Working on Meta Quest 3 with Latest Firmware and Quest Link Update

We are using Passthrough in our Unreal Engine project with the Meta Quest 3. Since updating both the headset and Quest Link to the latest version, the camera passthrough image always appears in the foreground, covering all other scene content.

This issue does not occur when using a headset with firmware version v74 — in that case, the Passthrough Layer component works correctly and is rendered as an underlay as intended.

Current Project and Passthrough Settings:

  1. Project Settings > Rendering

    Enable alpha channel support in post processing: “Allow through tonemapper”

    Anti-Aliasing Method: “Multisample Anti-Aliasing (MSAA)”

  2. Plugins > MetaXR

    Enabled:

     Passthrough Enabled
    
     Anchor Support
    
     Anchor Sharing
    
     Scene Support
    

    Meta Quest device support: All required devices added

    Support Experimental Features: Enabled

  3. VR Pawn Class

    OculusXRPassthroughLayer component added to Camera

    Component settings:

     Supports Depth: Enabled
    
     No Alpha Channel: Enabled
    
     Stereo Layer Shape: "Reconstructed Passthrough Layer"
    
         Layer Placement: Set to "Underlay"
    

Problem:
Despite the correct underlay configuration, the passthrough is rendered on top of all 3D content on the Meta Quest 3 with the latest update.

We are having an issue very much like this, did you ever find a solution to this ?

Our issue seems to be triggered with the use of stereo layers.

Are you calling the MetaXR APIs – especially the initialization of the Persistent Passthrough – via Blueprint or via C++?

The C++ API for (???, v81, v83) is currently completely broken (if you trace through it) as it completely ignores the “Shape” and Overlay/Underlay settings passed in.

I’ve had to patch the C++ code myself, and it appears Meta has not noticed nor fixed it themselves. And with Meta now abandoning VR, I’m not confident the UE port team is still going to be around.

Meanwhile, the Blueprint path works well as demonstrated by their “Unreal-PassthroughSample”.

If anybody is interested, I can post my patch for their broken C++ code.

@NuShrike1 Yes please do so.

Hi NuShrike, I’m running into the exact same issue described here — “Unable to retrieve OculusXRHMD, cannot add event polling delegate” — using UE5.7.4 with the latest Meta XR Plugin (v201.0). Confirmed the same failure even in Meta’s official Unreal-PassthroughSample. Would really appreciate it if you could share your patch for the broken C++ passthrough code. Thank you!

Sorry, I haven’t logged-in in a while and I don’t have email notifications set up (or there’s none here).

I’ll post this patch asap.

Here’s my patch for the still broken C++ API for Passthrough Underlay. Should compile even in UE 5.8.0.

Author: NuShrike <73401213+NuShrike@users.noreply.github.com>  2025-11-29 16:05:34
[MetaXR] Fix critical bug in UOculusXRPersistentPassthroughInstance::UpdateParameters

Meta''s stock implementation corrupts the Passthrough Shape config on every call:

1) In editor it unconditionally nulled InParameters.Shape, discarding the caller''s settings.

2) It then built a new default UOculusXRStereoLayerShapeReconstructed to fix ownership.

Right after, the struct-copy Parameters = InParameters overwrote that new Shape with the (possibly nulled) incoming one — negating #2 and inheriting #1's data loss.

Net result: Passthrough ends up with no Shape configured.

Fix: keep the incoming Shape''s settings via ApplyShape(), struct-copy first, only null+recreate Parameters.Shape when it isn''t actually owned by this, then restore/reconfigure it via LoadShape(this) before UpdateLayer().

diff --git a/Private/OculusXRPersistentPassthroughInstance.cpp b/Private/OculusXRPersistentPassthroughInstance.cpp
--- a/Private/OculusXRPersistentPassthroughInstance.cpp
+++ b/Private/OculusXRPersistentPassthroughInstance.cpp
@@ -32,18 +32,21 @@ void UOculusXRPersistentPassthroughInstance::InitLayer(FOculusXRPersistentPassth
 
 void UOculusXRPersistentPassthroughInstance::UpdateParameters(FOculusXRPersistentPassthroughParameters InParameters)
 {
-#if WITH_EDITOR
-	// We need the instance to be the owner of the shape, but in editor the shape still exist and its owner is the BP calling the method.
-	// So we clear it to force a new one to be created with LoadShape(this)
-	InParameters.Shape = nullptr;
-#endif
+	// make sure incoming Shape settings are set
+	InParameters.ApplyShape();
+
+	// struct-copy InParameters to Parameters
+	Parameters = InParameters;
 
-	if (InParameters.LoadShape(this) == nullptr)
+	if (nullptr != Parameters.Shape && this != Parameters.Shape.GetOuter())
 	{
-		Parameters.Shape = NewObject<UOculusXRStereoLayerShapeReconstructed>(this, NAME_None, RF_Public);
+		// We need the instance to be the owner of the Shape, so clear it if it''s not the correct owner
+		// to force a new one to be created with LoadShape(this)
+		Parameters.Shape = nullptr;
 	}
 
-	Parameters = InParameters;
+	// FIX: restore/reconfigure Parameters.Shape after struct-copy from InParameters & REQUIRED for UpdateLayer()
+	Parameters.LoadShape(this);
 
 	UpdateLayer();
 }

Sorry, I don’t think your issue is related.

That error message basically says your headset isn’t plugged in, wrong XR system-runtime.

Seems easier to happen with the Epic OpenXR plugin because it checks for the plugged-in headset at editor start-up time, instead of “VR Preview” time like the original OVRPlugin.

Try replugging in the headset, or before you start the editor.