v2.18.0

playcanvas/enginev2.18.0Apr 17, 2026by mvaligursky

AI Summary

Major release focused on compute-based Gaussian Splatting rendering for WebGPU with significant performance optimizations, new fisheye projection support, and fog rendering capabilities. Also includes HTML-in-Canvas support and various GSplat renderer improvements.

Key Highlights

  • Add compute-based tiled GSplat renderer for WebGPU with local compute and dynamic buffer sizing
  • Introduce fisheye projection for Gaussian splats and skybox support
  • Add fog support for Gaussian splat rendering
  • Implement WebGPU subgroup operations support
  • Add GSplatParams.renderer enum for runtime renderer selection

New Features

  • Compute-based tiled GSplat renderer (WebGPU)
  • Local compute GSplat renderer with dynamic buffer sizing
  • Fisheye projection for Gaussian splats
  • Fog support for Gaussian splats
  • WebGPU subgroup operations
  • HTML-in-Canvas support with texElementImage2D
  • Interactive hit testing
  • Heatmap debug mode for compute GSplat rasterizer
  • GPU compute benchmark example

Full Release Notes

## Changes

* Remove per-resource instance vertex buffer from GSplat rendering by @mvaligursky in #8513
* Expose GSplat rendering properties on GSplatParams by @mvaligursky in #8518
* Add HTML-in-Canvas support with texElementImage2D and interactive hit testing by @mvaligursky in #8519
* Refactor GSplatRenderer into base class with GSplatQuadRenderer derived class by @mvaligursky in #8520
* Refine GSplatRenderer API: rename methods for clarity by @mvaligursky in #8522
* Extract FramePass base class from RenderPass by @mvaligursky in #8523
* Add WebGPU subgroup operations support by @mvaligursky in #8528
* Optimize GPU radix sort with bitmask ranking and multi-element processing by @mvaligursky in #8529
* Add compute-based tiled GSplat renderer (WebGPU) by @mvaligursky in #8531
* Add local compute GSplat renderer and dynamic buffer sizing (WebGPU) by @mvaligursky in #8536
* Replace full-screen quad composite with tile-based indirect draw in local compute GSplat renderer by @mvaligursky in #8544
* Add orthographic camera support to compute GSplat renderers by @mvaligursky in #8545
* Improve compute GSplat rendering and add tonemapping support by @mvaligursky in #8546
* Support dynamic work buffer formats in compute GSplat renderers by @mvaligursky in #8547
* Remove redundant shader includes from ShaderUtils.createShader callers by @slimbuck in #8551
* Add WebGPU Bare device type for testing without optional features by @mvaligursky in #8555
* Add picking support and fix color pipeline in local compute GSplat renderer by @mvaligursky in #8556
* Remove global compute GSplat renderer by @mvaligursky in #8558
* Remove per-splat GPU compaction for CPU sort path by @mvaligursky in #8559
* Extract GSplatFrustumCuller from GSplatWorkBuffer by @mvaligursky in #8560
* Merge frustum culling into compute, convert to storage buffers, fix >16M splat dispatch by @mvaligursky in #8561
* Make frustum culling always-on and remove dead pcNodeIndex pipeline by @mvaligursky in #8562
* Reduce register pressure in compute GSplat TileCount projection by @mvaligursky in #8563
* Store conic form in projection cache to avoid per-tile conversion by @mvaligursky in #8565
* Add GSplatParams.renderer enum for runtime renderer selection by @mvaligursky in #8567
* Remove centers array dependency from GSplatInfo interval check by @mvaligursky in #8568
* Add minContribution property for compute GSplat contribution culling by @mvaligursky in #8571
* Increase default minContribution from 2 to 3 by @mvaligursky in #8575
* Add fisheye projection for Gaussian splats by @mvaligursky in #8576
* Add fisheye projection support for skybox by @mvaligursky in #8577
* Refactor rasterize variant management and beforePasses scheduling by @mvaligursky in #8579
* Add depth testing for compute GSplat renderer when CameraFrame depth prepass is enabled by @mvaligursky in #8581
* Simplify Camera.beforePasses to a plain FramePass array by @mvaligursky in #8582
* Add fog support for Gaussian splat rendering by @mvaligursky in #8583
* Replace atomic scatter with pair-buffer tile binning and cooperative large-splat processing by @mvaligursky in #8586
* Split viewDepth into separate depthBuffer for sort cache locality by @mvaligursky in #8587
* Move FisheyeProjection to scene/graphics for shared use by @mvaligursky in #8588
* Modernize README and improve npm discoverability by @willeastcott in #8591
* Remove Bundlephobia badge from READMEs by @willeastcott in #8592
* Per-node granular SH color updates with angle-based threshold by @mvaligursky in #8593
* Optimize tile-count pass with multi-splat threads and extract dispatch prep shaders by @mvaligursky in #8594
* Remove workgroup-level early-out atomics from rasterize pass by @mvaligursky in #8596
* Vectorize Gaussian evaluation across 2x2 pixel quad in rasterize pass by @mvaligursky in #8597
* Unify GSplat debug rendering into a single enum-based API by @mvaligursky in #8598
* Add heatmap debug mode for compute GSplat rasterizer by @mvaligursky in #8599
* Revert tile-count pass to single-splat-per-thread by @mvaligursky in #8603
* Decouple compute GSplat renderer from work buffer via setDataSource by @mvaligursky in #8605
* Add shader defines for prepass to support alpha test and dithered opacity by @slimbuck in #8606
* Improve GSplat compute renderer cold-start buffer capacities by @mvaligursky in #8610

## Fixes

* Reset render pass merge flags each frame in FrameGraph.compile() by @mvaligursky in #8516
* Fix TAA ghosting artifacts on WebGPU by @mvaligursky in #8517
* Prevent division by zero in CAS sharpening shader by @slimbuck in #8532
* Preserve blend state in drawQuadWithShader / RenderPassQuad by @mvaligursky in #8535
* Fix double decrement of octree file ref counts on entity disable by @mvaligursky in #8537
* Use y-first approach in Compute.calcDispatchSize to minimize wasted workgroups by @mvaligursky in #8538
* Round up compressed texture dimensions to block size on WebGPU by @mvaligursky in #8540
* Replace StopThePop tile intersection with exact FlashGS method in compute GSplat by @mvaligursky in #8548
* Smooth Gaussian falloff for capped splat radii in compute renderer by @mvaligursky in #8549
* Avoid workgroupUniformLoad on atomic type for iOS WGSL compatibility by @mvaligursky in #8552
* Use unfilterable-float sample type for RGBA32F textures in node culling shader by @mvaligursky in #8553
* Use unfilterable-float sample type for RGBA32F GSplat textures on WebGPU by @mvaligursky in #8554
* Pass alphaClip to scatter pass instead of hardcoding 1/255 by @mvaligursky in #8564
* Match quad renderer near-plane behavior in compute GSplat renderer by @mvaligursky in #8566
* Match raster minPixelSize culling threshold in compute GSplat renderer by @mvaligursky in #8569
* Use logarithmic depth quantization in compute GSplat bitonic sort by @mvaligursky in #8570
* Match raster Gaussian radius cap in compute GSplat renderer by @mvaligursky in #8573
* Improve compute GSplat tile entry buffer scaling to reduce overflow artifacts by @mvaligursky in #8574
* Preserve layerPlacementsDirty flag when octree placements are removed by @mvaligursky in #8584
* Include fresnelSchlick chunk when refraction is enabled without specular by @willeastcott in #8595
* Suppress frame:ready until full LOD update after param changes by @mvaligursky in #8602

## Examples

* Fix FOV slider default value in LOD streaming example by @mvaligursky in #8510
* Hide test two-sided lighting example thumbnails by @mvaligursky in #8511
* Add radial sorting toggle to LodStreaming example by @mvaligursky in #8515
* Add clear button to examples sidebar filter input by @mvaligursky in #8541
* Limit examples sidebar to left half of screen on mobile by @mvaligursky in #8542
* Use consistent XR session check for viewport sizing and add stereo GSplat test example by @mvaligursky in #8557
* Add URL input and orientation controls to LOD streaming example by @mvaligursky in #8572
* Add procedural weather particle system example using Gaussian splats by @mvaligursky in #8580
* Add renderer selection UI to all Gaussian splat examples by @mvaligursky in #8585
* Add environment map and metallic reflections to html-texture example by @mvaligursky in #8589
* Add URL parameter support to LOD streaming example by @mvaligursky in #8590
* Add GPU compute benchmark and GSplat benchmark example by @mvaligursky in #8600
* Add cloud shadows shader chunk override example by @mvaligursky in #8604
* Replace share buttons with save buttons in GSplat benchmark example by @mvaligursky in #8608

## Engine Dependencies

* Update rollup to v4.59.0 (security) in #8483

### Contributors

* @mvaligursky
* @slimbuck
* @willeastcott

**Full Changelog**: https://github.com/playcanvas/engine/compare/v2.17.2...v2.18.0