Hi I am using postprocessing effects in my current implementation but I am experiencing issues currently in Oculus Browser on my Quest 3 and Needle 4.7.4. In browser there seems to be appearing a white overlay over my scene any time I register an OutlineEffect. This overlay appears and disappears every now and then on a somewhat frequent basis. As far as I understand postprocessing doesnt work in VR but I am unsure if it should be working in VR browsers.
import {
DeviceUtilities,
EffectProviderResult,
PostProcessingEffect,
PostProcessingEffectOrder,
registerCustomEffectType,
serializable,
} from "@needle-tools/engine";
import { BlendFunction, OutlineEffect } from "postprocessing";
import { Color, Object3D } from "three";
import { dragLayerIndex, PassOptions } from "../hierarchical/NeedleTypes";
export class NeedleDragEffects extends PostProcessingEffect {
@serializable(Color)
public _dragVisibleEdgeColor: Color = new Color(180, 180, 180);
@serializable(Color)
public _dragHiddenEdgeColor: Color = new Color(180, 180, 180);
@serializable()
public _dragEdgeStrength: number = 1;
@serializable()
public _dragPulseSpeed: number = 1;
@serializable()
public _dragBlur: boolean = false;
@serializable()
public _dragXray: boolean = true;
public order: number | undefined = PostProcessingEffectOrder.Bloom + 2;
get typeName(): string {
return "DragOutline";
}
private _outlineEffect: void | undefined | OutlineEffect;
public addToSelection(objects: Object3D[]) {
if (!this._outlineEffect) {
return;
}
for (const obj of objects) {
this._outlineEffect.selection.add(obj);
}
}
public removeFromSelection(objects: Object3D[]) {
if (!this._outlineEffect) {
return;
}
for (const obj of objects) {
this._outlineEffect.selection.delete(obj);
}
}
public clearSelection() {
if (!this._outlineEffect) {
return;
}
this._outlineEffect.selection.clear();
}
public onCreateEffect(): EffectProviderResult | undefined {
const dragOptions: PassOptions = {
blendFunction: BlendFunction.ADD,
// Mutlisampling will be reduced if FPS is below 50
multisampling: Math.min(2, this.context.renderer.capabilities.maxSamples),
edgeStrength: this._dragEdgeStrength,
pulseSpeed: this._dragPulseSpeed,
visibleEdgeColor: this._dragVisibleEdgeColor.getHex(),
hiddenEdgeColor: this._dragHiddenEdgeColor.getHex(),
blur: this._dragBlur,
xRay: this._dragXray,
resolutionScale: DeviceUtilities.isMobileDevice() ? 0.3 : 0.5,
};
const outlineEffect = new OutlineEffect(this.context.scene, this.context.mainCamera!, dragOptions);
this._outlineEffect = outlineEffect;
this._outlineEffect.selection.layer = dragLayerIndex;
this._outlineEffect.selection.exclusive = false;
return this._outlineEffect;
}
public changeHighlightEffectColor(color?: Color) {
if (!this._outlineEffect) {
return;
}
this._outlineEffect.visibleEdgeColor = color ?? this._dragVisibleEdgeColor;
this._outlineEffect.hiddenEdgeColor = color ?? this._dragHiddenEdgeColor;
}
}
Hi Martin, thanks for sharing the details. The issue with the white overlay when using OutlineEffect in VR (as seen in Oculus Browser on Quest 3 with Needle 4.7.4) is likely due to the way VR rendering pipelines work. In WebXR mode, browsers handle render targets and layering differently from the standard desktop case. Postprocessing effects like OutlineEffect are designed for the typical render pipeline and can cause artifacts (like a flashing white overlay) when applied on top of the XR image.
While it’s theoretically possible to use postprocessing effects in VR, many XR browsers haven’t fully optimized for multiple render passes, leading to such unexpected behavior. A common workaround is to detect when XR is active and disable non-essential postprocessing effects, such as the OutlineEffect. For example, you can check if XR or VR mode is active with Needle Engine’s DeviceUtilities (or via the XR properties available in the context) and skip registering the OutlineEffect when in VR. Here’s a short example:
import { Behaviour, DeviceUtilities } from "@needle-tools/engine";
export class MyComponent extends Behaviour {
start() {
// Check if XR is active
if (DeviceUtilities.xr.active) {
console.warn("VR mode active – postprocessing effects disabled");
return;
}
// Continue with registering your OutlineEffect
}
}
This approach helps avoid artifacts by not running the postprocessing chain when the render pipeline is managed by the XR session. If you require similar visual feedback in VR, you might need to create a custom solution adapted to XR’s constraints—possibly by applying effects directly in your scene material or adjusting the render target settings to suit the XR camera usage.
It’s also worth testing if any updated Needle Engine versions or adjustments in the postprocessing library (such as tweaking blend functions or multisampling options) can improve the behavior in VR. You can check the latest release notes or the related documentation for further guidance on postprocessing in XR contexts (see, for example, at CHANGELOG.md about performance and stability improvements in postprocessing).
Hey Martin, thanks for clarifying. Since the issue occurs in default browser mode on Oculus Browser (i.e. not during an active XR session), it’s likely a conflict between how the OutlineEffect postprocessing effect is set up and the particular rendering behavior or hardware quirks on Oculus Browser in this mode.
Some possibilities to consider:
• The OutlineEffect (from the postprocessing library) may use render targets and blending settings that aren’t fully compatible with the default framebuffer on Oculus Browser. Sometimes, the effect might be clearing or blending with a white background inadvertently.
• Check whether the postprocessing chain is expecting a specific clear color or alpha configuration. If the clear color is set to white or if there’s no proper transparent clear pass configured, intermittent white overlays can occur.
• The multisampling or gamma correction settings may interact unexpectedly on this platform. The Needle Engine changelog has noted several fixes in postprocessing stability (for example, improvements in multisampling settings seen in version 4.6.2/4.7.0 at CHANGELOG.md). Adjusting the multisampling property on your PostprocessingManager (for example, forcing a lower number) might help avoid artifacts.
A few actionable steps:
Verify your render target clear settings. Ensure that the underlying renderer and the postprocessing composer are configured with the correct clear color and alpha. For example, if you’re working with transparent backgrounds, make sure to set the clear color accordingly.
Experiment with the PostprocessingManager’s multisampling configuration. You can try setting it explicitly (e.g., multisampling: 0 or 2) to see if the white overlay disappears.
If possible, try disabling the OutlineEffect temporarily to confirm that it’s the culprit. If removing it removes the white overlay altogether, then you’re certain that this effect’s configuration needs tweaking for the Oculus browser environment.
Finally, consider adding a device-specific check (using DeviceUtilities or user agent detection) to adjust or even disable the OutlineEffect on Oculus Browser in default mode until a more robust solution is available.
If the issue persists after these adjustments, a minimal reproducible example via Needle-engine - Vite Template (duplicated) - StackBlitz could help diagnose further, and you might consider filing a bug report. This behavior appears to stem from a subtle interaction between postprocessing setup and the browser’s handling of WebGL render targets on Quest devices.
Hope this helps you narrow down the problem, Martin!
4 replies left thread_pqYISuWQ0c2doD7f4CjgtcFM Reply to this post directly if you need further help (bottom right button)
I have formatted the code here is the video recording of what is happening. This white screen does happen usually several times but only managed to reproduce it once this time at startup.
Hi there is there any update to this or any suggestions on what should I try to do/test/adjust please? I have forgotten to add the suffix to activate the NeedleJS UI I am very sorry. I would like to also add that I downgraded back to 4.4.3 and the postprocessing seems to work but I would to upgrade to later versions down the line.
Here is the link with the NeedleJS UI and the latest version of the app.
So I have downgraded back to 4.4.3 and realised that the legacy commit actually did postprocessing like this directly. Which seems to work but at the same time there are several notes of the composer being overwritten. I apologize for the previous notes but this is something of a new codebase alongside a new framework.
this.outlineSelectionEffect = new OutlineEffect(this.context.scene, this.context.mainCamera, selectionOptions);
this.outlineSelectionEffect.selectionLayer = 12;
this.outlineDragEffect = new OutlineEffect(this.context.scene, this.context.mainCamera, dragOptions);
this.outlineDragEffect.selectionLayer = 11;
this.outlineSelectionPass = new EffectPass(this.context.mainCamera, this.outlineSelectionEffect);
this.outlineDragPass = new EffectPass(this.context.mainCamera, this.outlineDragEffect);
if (!this.context.composer) {
this.context.composer = new EffectComposer(this.context.renderer);
}
this.context.composer.addPass(new RenderPass(this.context.scene, this.context.isInVR ? this.context.xrCamera : this.context.mainCamera!));
this.context.composer.addPass(this.outlineSelectionPass);
this.context.composer.addPass(this.outlineDragPass);