Skip to content

[compat] GlowLayer (selective glow for emissive meshes) #751

Description

@sdoleg2011

Missing API

GlowLayer from @babylonjs/core — constructor options (blurKernelSize), intensity, isEnabled, customEmissiveColorSelector, customEmissiveTextureSelector, addIncludedOnlyMesh / addExcludedMesh, dispose.

Current behavior

It exists but throws LiteCompatError ("Effect layers are not implemented in Babylon Lite").

Use case

A kitchen configurator (Babylon.js 9, ~1700 meshes in a large project) that I am moving to Babylon Lite through lite-compat. LED strips under wall cabinets and inside carcasses are thin unlit emissive boxes; a GlowLayer with a colour selector gives them their halo, and everything that is not a strip acts as an occluder, so a strip behind a door does not glow through it. Without the layer the lighting feature looks broken, and a full-frame bloom is not a substitute: it is not selective and the scene has plenty of bright non-LED surfaces.

Minimal example

const glow = new GlowLayer("ledGlow", scene, { blurKernelSize: 32 });
glow.intensity = 0.6;
glow.customEmissiveTextureSelector = () => null;
glow.customEmissiveColorSelector = (mesh, _subMesh, material, result) => {
    if (mesh.metadata?.isLed) {
        const c = material.emissiveColor;
        result.set(c.r, c.g, c.b, 1);
    } else {
        result.set(0, 0, 0, 1); // occluder
    }
};

Additional context

I have this working in my app-side shim on 1.30.0, built only from native frame-graph tasks and without touching the scene's default render task, so I think it is feasible for the compat layer. The composition, in graph order after the scene task:

  1. createGeometryRendererTask (one VIEW_DEPTH attachment) — used only for its geometryDepthTexture.
  2. createRenderTask({ rt: <rgba16float, no depth>, depth: geo.geometryDepthTexture, autoMirror: false, clr: true, clrColor: transparent }) with the emitting meshes added through addMesh. Because the geometry depth is _eager, it is loaded rather than cleared, which gives exact occlusion for free.
  3. A half-size copy, then createBlurPostProcessTask H+V at half size and H+V again at quarter size with kernel = blurKernelSize / 2 — the same two radii Babylon.js uses.
  4. An additive merge of the two blurred targets onto engine.scRT (alphaMode: 1, clear: false), scaled by intensity.

Tasks are appended with addTask + buildFrameGraphTask once the first emitter shows up, and toggled with executionEnabled, so a scene without emitters pays nothing. Side by side with Babylon.js the halo size and brightness match closely.

Three things were awkward and may be worth a look regardless of whether GlowLayer itself lands:

  • No public custom full-screen pass over a RenderTarget. createPostProcessTask is internal and the createEffectWrapper API binds Texture2D, not the canvas-sized RenderTargets that frame-graph tasks produce and rebuild on resize. For the half-size copy I used a blur task with direction: { x: 0, y: 0 }; for the merge (two sources and an intensity uniform) I had to reach into the blur task's _shader.
  • No way to remove a task from a scene's frame graph (there is addTask* but no counterpart), and disposeRenderTarget is not exported, so explicit targetTextures have to be destroyed by hand.
  • GeometryRendererTask had two problems for this kind of scene; I opened fix(geometry): emit valid normal outputs for unlit Standard materials #747 (unlit Standard material with a normal attachment produced invalid WGSL) and fix(geometry): load a material family bridge that first appears after preload #748 (a material family that first appears after _preload throws on every frame).

I would be glad to turn the shim code into a PR against babylon-lite-compat if that is a direction you want.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions