OptiPixel library

We refactored the IndexManager and removed the use of an index subarray in favor of a more memory-efficient approach. As a result, memory usage was reduced while the free-index search performance degraded only slightly. This is an intentional trade-off: developers should be aware that reserving an index can be an expensive operation, so in this case we prioritized memory savings over peak allocation speed. If a different profile is required (for example, minimal allocation latency), the previous structure can be restored or a configurable mode added.

1 Like

Instancer: instance picking via pc.Picker

We have added pc.Picker support to the instancer. Individual instances can now be selected through PlayCanvas’s standard picking pipeline.

The previously established limits — 0xfffff instances and 0xfff — are now used for indexing. The identifier is packed as follows:

  • 0xfff stores the unique instance id or the unique instancer layer id;
  • 0xfffff stores the unique instance number.

This packing lets instance selection reuse the existing pc.Picker path without a separate identity channel.

A theoretical conflict between layer and instance still remains: in rare cases their identifiers can overlap in the 0xfff space. In practice this is uncommon. If a collision does occur, it can be resolved by picking the nearest among the matched instances.

1 Like

Software HiZ occlusion culling support

We’ve added occlusion culling via a software Hierarchical Z (HiZ / HZB) buffer. It fills a common gap: GPU occlusion works well on capable hardware, but you still need a fast CPU-side reject path — especially on weaker devices, in WebGL, and anywhere a GPU round-trip is too expensive to drive culling in time.

Why it exists

Classic GPU HiZ gives a solid depth test against the frame, but the test and the results often arrive too late: the CPU has already prepared batches, while the GPU is still busy with the previous frame. Software HiZ is aimed at that problem — fast culling on the CPU. Objects that are clearly hidden behind nearer geometry never enter frame preparation.

GPU HiZ and CPU HZB are interchangeable

GPU HiZ and CPU HZB are interchangeable backends of the same occlusion pipeline. You can pick the GPU path, the CPU path, or switch per device without rewriting the scene or changing how occluders are authored. The contract stays the same: a hierarchical depth buffer plus a visibility test. What changes is where the buffer lives and who queries it.

Buffer resolution per device

HiZ / HZB resolution is controllable per device class. On weaker hardware, keep the buffer smaller: less memory, cheaper build and tests, slightly coarser culling. On desktop or a strong mobile chip, raise the resolution for tighter rejection and fewer false visibles. It’s an explicit quality/cost knob, not a hidden internal.

Scene occluders

Basic primitives are supported:

  • spheres — trees, rocks, characters, and other round volumes;
  • boxes (AABB / OBB) — walls, buildings, large props;
  • planes — ground, big facades, “everything behind this wall”.

You can scatter them through the scene and tune them in the editor: transform, size, orientation, on/off. There’s no need to author complex occlusion meshes — place simple volumes where objects actually hide each other. The editor makes coverage obvious, so you can densify or thin occluders per location.

Threading, without going into the implementation

Tests run on a worker so the main thread stays free. Data moves between the worker and the main thread through a ring buffer: the CPU enqueues visibility queries, the worker returns occlusion status, and the frame doesn’t wait on a synchronous round-trip. That’s enough for a stable path even without SharedArrayBuffer.

If you enable SharedArrayBuffer, the same exchange gets cheaper: fewer copies and less overhead moving query batches and results. SAB is an optional speedup, not a hard requirement. Without it, the ring buffer already carries traffic between the worker and the main thread; with it, the pipeline stays the same and IPC costs drop.

What you get in practice

  • Less CPU and GPU work thanks to early rejection of occluded objects.
  • One occluder setup for both GPU HiZ and CPU HZB.
  • Buffer resolution tuned to the device.
  • Straightforward authoring: spheres, boxes, and planes in the editor.
  • Threading that scales: ring buffer today, SharedArrayBuffer when the environment allows it.

In short: software HiZ gives fast CPU-side occlusion culling without breaking the GPU path, and keeps the scene and editor shared between both modes.

sw-hiz

1 Like

Hi everyone,

playcanvas-opti-pixel now has documentation. Previously there was almost no entry point: no README, no guides, and no public API reference. The library now has system overviews, usage scenarios, and WebGL / WebGPU limitations written down.

What was added:

  • a README with install instructions, a module map, and minimal instancing and occlusion examples;
  • guides: getting started, architecture, choosing an instancer, choosing an occlusion backend;
  • subsystem docs: GPU instancing + LOD, HZB (WebGL / WebGPU), occlusion queries, CPU software occlusion, BVH, AABB store and data textures;
  • the shared lock → enqueue → unlock contract, including how to treat OCCLUSION_UNKNOWN;
  • JSDoc on the public API and a TypeDoc reference.

The guides cover when and in what order to call things; method signatures come from the code.

Docs: repo / docs
API reference: GitHub Pages

If anything is still unclear while integrating the library, drop a note in this thread and we will expand the docs.

3 Likes

Rendering Architecture Update: WebGL2 Optimization and CameraFrame Support

We have updated the library to improve stability on mobile devices and align with the latest engine versions.

Occlusion Culling Changes

We have reworked the visibility testing approach for WebGL2.

  • WebGL2: Completely removed HZB (Hierarchical Z-Buffer) implementation. The library now relies solely on the Coverage Buffer method. This reduces GPU load and eliminates issues with depth buffer readbacks on mobile platforms.
  • WebGPU: Full HZB support is retained, as the API architecture allows for efficient hierarchical depth operations.

CameraFrame Integration

Added full support for running the library via CameraFrame — the engine’s new standard API for rendering control.

The system now correctly retrieves camera and buffer data through a unified interface, simplifying integration and ensuring compatibility with future engine updates.

1 Like