r/PlayCanvas

▲ 71 r/PlayCanvas+1 crossposts

Gaussian splat encased in refractive glass — real screen-space refraction + chromatic dispersion (PlayCanvas)

Latest experiment with Gaussian splats in the PlayCanvas engine: sealing a splat inside a solid glass shape and refracting the view through it. Video above; live demo at the bottom.

You pick the shape — cube, sphere, gem, or hex prism — and the glass bends both the splat and the skybox behind it at the surface, with chromatic dispersion splitting the colors slightly. There are live controls for refraction index, reflection, dispersion, and frost.

How it works:

  • The splat renders into its own layer placed before the camera frame's scene-color grab pass, so the refractive glass material can sample that grab texture and bend the already-rendered splat + background through the shape's surface.
  • The splat is cropped to the inside of the shape by scaling any splats outside its faces to zero, and splats near the surface are shrunk a bit so they don't poke through the glass.
  • Refraction/dispersion/reflection are a fairly standard screen-space glass material on the shape mesh — the interesting part was getting the splat to live inside the grab pass so it refracts correctly rather than just compositing on top.

Runs on WebGPU and WebGL. It's an open PR into the engine examples, so the full source is there to read and reuse.

Live demo: https://engine-it4qgogtr-playcanvas.vercel.app/#/gaussian-splatting/glass-refraction

Happy to answer questions on the approach.

u/mvaligursky — 4 hours ago
▲ 43 r/PlayCanvas+1 crossposts

Reusable "wind" script for Gaussian splats in PlayCanvas — trees sway in the breeze, even on streamed LOD scenes (WebGPU + WebGL)

I've been playing with adding some life to Gaussian splat scenes and built a small reusable script for the PlayCanvas engine that makes trees sway in the wind. Video above — and this is a streamed LOD scene (a skatepark loaded progressively), not a single baked splat, which was the fun part to get working.

The idea is that it's drop-in: you add the script to a splat entity, hand it a list of spheres marking where the trees are (center + radius), and it does the rest. The bottom of each sphere is treated as the trunk anchor, so the sway is zero there and grows up and out toward the branch tips — trunks stay planted, canopies move.

How it works under the hood:

  • During the copy-to-work-buffer stage, each splat's "binding" to a tree (sway amount, height, tree index) is baked once into an extra work-buffer stream — not per frame. A uniform grid accelerates the sphere lookup so hundreds of trees stay cheap.
  • Because it hooks that stage, it works transparently on streamed LOD content: as new LOD chunks stream in and get copied to the work buffer, their splats get bound to the trees automatically — no need for the whole scene to be resident up front.
  • A tiny per-frame vertex modifier then reads the baked data and applies the actual sway (a cantilever oscillation + a slow gust envelope + fast flutter).

Controls for strength, speed, direction, gustiness and flutter are all live. There's also an edit mode with gizmos to place the tree spheres and print them back out.

Runs on both WebGPU (sway happens in the projection compute pass) and WebGL (per-vertex). It's going into the engine examples as an open PR, so the script and the full example are there to read/reuse.

Happy to answer questions about the approach — curious if anyone has cheaper ideas than the per-splat texture fetch for the animated read.

u/mvaligursky — 4 hours ago
▲ 51 r/PlayCanvas+1 crossposts

I was 3D printed in a clear resin block

My friends had a Gaussian splat of me (scanned in 2023) printed in clear resin by crysta.ai and I'm honestly amazed how well the detail survived. My bike gear + helmet, face + hair...the fidelity is insane!

The source splat is here if you want to compare against the print:

https://superspl.at/scene/a5d25fb4

Happy to answer questions about how it turned out.

u/MayorOfMonkeys — 3 days ago
▲ 126 r/PlayCanvas+1 crossposts

SuperSplat can now render 360° videos of your splats

SuperSplat (the free, open-source splat editor from PlayCanvas) just got 360° video rendering. You set up a camera fly-through on the timeline as usual, pick Render → Video → Projection: 360° Equirectangular, and it exports a 2:1 equirect video up to 4096×2048 that plays in any 360 viewer.

Demo (YouTube 360 — drag to look around, works in a headset):
https://www.youtube.com/watch?v=6oGjT8eubMc

How it works under the hood, since I know this sub will ask:

  • Each output frame is rendered as the 6 faces of a cube from the camera position, then a shader projects them into the equirect frame. Everything runs through the existing WebCodecs encode pipeline (H.264/HEVC/VP9/AV1 in MP4/WebM/MOV/MKV).
  • Because gaussian sorting is view-direction dependent, the splats are re-sorted for every face. Adjacent faces can still composite big overlapping splats in a slightly different order (and the projected splat shapes differ a bit off-axis), which initially showed up as visible seams at face boundaries — so the faces are actually rendered at 100° FOV and blended across the overlap, which feathers the mismatch away.
  • MP4/MOV exports get Spherical Video V1 metadata injected, so YouTube, VLC and Quest recognize them as 360 automatically — no need to run Google's spatial media injector.
  • There's a Level Horizon toggle (on by default): only camera yaw is baked into the projection so the horizon stays level even if the camera path pitches up/down — much more comfortable in a headset. Turn it off if you want full camera orientation baked in.

It's monoscopic for now (stereo ODS is a much bigger lift for splat rasterization). Fair warning: it renders each frame 6 times with a re-sort per face, so it's roughly 6× slower than a normal video export — fine for offline rendering.

This will ship in the next release; if you can't wait, build from source — the PR landed here: https://github.com/playcanvas/supersplat/pull/933

Happy to answer questions about the implementation. Would love to see what you render with it — post your 360s!

(Fun fact: the feature was built using Claude's latest model Fable 5 — welcome to the future!)

u/MayorOfMonkeys — 4 days ago
▲ 28 r/PlayCanvas+1 crossposts

PlayCanvas engine now loads Gaussian Splats from glTF/GLB (KHR_gaussian_splatting)

We've just added support for the new KHR_gaussian_splatting glTF extension to the open-source PlayCanvas engine — meaning gaussian splats can now be loaded directly from standard .glb files.

What is KHR_gaussian_splatting?

It's a Khronos extension (currently a release candidate, ratification expected soon) that defines how splat data is stored inside glTF: positions, rotations, scales, opacity and spherical harmonics as vertex attributes on a points primitive. It was developed by a group including Cesium, Niantic, Esri and NVIDIA, and is also planned as a building block of OGC 3D Tiles 2.0. Khronos announcement: https://www.khronos.org/news/press/gltf-gaussian-splatting-press-release

Why this matters

This is mostly about interoperability. Until now, every splat pipeline spoke its own dialect — PLY variants, SPLAT, KSPLAT, SPZ and so on. With a Khronos-standardized glTF extension, splats become regular citizens of the glTF ecosystem: they can flow through standard tooling and pipelines, and they can live in the same file as regular meshes, materials and animations. In PlayCanvas, a splat GLB loads like any other glTF container — you instantiate it and get an entity hierarchy with gsplat components, and files that mix meshes and splats just work.

A nice detail of the spec: viewers that don't support the extension can still render a fallback colored point cloud, so the files degrade gracefully.

What about file size?

One honest caveat: the base extension stores splat data uncompressed, so files are roughly PLY-sized. Treat it as an interchange format, not a delivery format. For production web delivery we still recommend SOG, which is ~15-20× smaller and loads faster. (There's an SPZ-based compression companion extension in draft at Khronos, but it's not finalized yet.)

Try it

You can create these files today with our open-source CLI tool splat-transform (splat-transform scene.ply scene.glb) — it handles conversion from PLY, compressed PLY, SPZ, KSPLAT and more. Engine support ships in the next PlayCanvas release, with a new example in the examples browser.

Everything is MIT-licensed and open source: https://github.com/playcanvas/engine

Video attached is our biker splat, converted from PLY to GLB and loaded straight into the engine. Happy to answer questions about the implementation.

u/mvaligursky — 3 days ago
▲ 19 r/PlayCanvas+1 crossposts

PlayCanvas Engine can now load and render Niantic's SPZ format directly

If you have splats in SPZ format — scans from Scaniverse or anything else in the Niantic ecosystem — the PlayCanvas Engine can now render them in the browser without a conversion step.

A few technical details for those interested:

  • The splat data stays in its quantized form on the GPU (24-bit fixed-point positions, 8-bit log scales, smallest-three rotations, quantized SH) and is dequantized on the fly in the shader — so GPU memory use is small.
  • Spherical harmonics are supported up to 3 bands, so view-dependent shading comes through.
  • Works on both WebGL2 and WebGPU.
  • The parser isn't baked into the engine — it's a script you register with the resource handler at runtime (the engine recently gained a parser registry for exactly this kind of format extension). The ZSTD-compressed attribute streams are decompressed with a small wasm module you register alongside it.

The video shows "Japanese Bee" by yyouzhen (CC BY 4.0, https://superspl.at/scene/ae58ed2c) — 978K gaussians with full spherical harmonics — converted to SPZ with SplatTransform (https://github.com/playcanvas/splat-transform) and loaded directly.

Engine PR with the implementation: https://github.com/playcanvas/engine/pull/9018

Happy to answer questions about the format or the GPU decode approach.

u/mvaligursky — 3 days ago
▲ 128 r/PlayCanvas+1 crossposts

Collision Mesh Generation in the SuperSplat Editor

Here is a preview of an upcoming feature in the free and open source SuperSplat Editor: collision/proxy mesh generation! It uses splat-transform under the hood to generate the mesh and you can visualize the mesh in the viewport to get it 'just right'. You can then export the mesh to the glTF GLB format.

What do you think?

u/MayorOfMonkeys — 6 days ago
▲ 406 r/PlayCanvas+1 crossposts

A 1,000-year-old church you can walk through in your browser

St. Stephan's Church in Bamberg, Germany — over 1,000 years old, with a Baroque interior dating to the 17th century.

Captured as a 3D Gaussian splat by majomedia. It's ~173 MB of SOG and runs free-roam right in the browser — you can wander the whole nave, choir and side altars:
https://superspl.at/scene/bc0984bf

The detail holds up really well, especially the light on the stucco and the gilded carvings.

Disclosure: I work on SuperSplat, the free Gaussian splatting platform from PlayCanvas. The capture itself is majomedia's, not mine — full credit to them.

Curious what people think of the quality. I suspect it's a PortalCam scan!

u/MayorOfMonkeys — 9 days ago
▲ 383 r/PlayCanvas+1 crossposts

WebGL Water upgraded to WebGPU Water 💧

Back in August 2011, Evan Wallace (who later co-founded Figma and wrote esbuild) released WebGL Water - the raytraced pool with real-time caustics that pretty much every web-graphics enthusiast remembers. ~15 years on, I figured it deserved a WebGPU version, so I ported the whole thing.

Live demo (WebGPU, falls back to WebGL2): https://willeastcott.github.io/webgpu-water-playcanvas/

Source: https://github.com/willeastcott/webgpu-water-playcanvas

The 2011 original: https://madebyevan.com/webgl-water/

The bit that's interesting for this sub: rather than transpiling GLSL → WGSL at runtime, every shader is authored in both languages side by side (LLMs are great and managing both versions and keeping them in sync). On WebGPU it runs native WGSL - no transpiler, no WASM - and still falls back to WebGL2 with the original GLSL.

It's a faithful port of the original rendering + sim:

  • GPU heightfield water sim on ping-pong float render targets (RGBA32F, half-float fallback)
  • Real-time caustics via the differential-area method (the projected-mesh trick from Evan's writeup)
  • Raytraced reflection + refraction off the pool and a draggable, buoyant sphere
  • Analytic ambient occlusion, soft blob shadow, sky cubemap
  • Built on the PlayCanvas engine (just the npm package - standalone Vite app)

I also added scroll-to-zoom and made click-drag paint a continuous ripple trail instead of a row of separate drops.

Disclosure: I work on PlayCanvas. This is just a fun open-source port, though - all the original genius is Evan's.

u/MayorOfMonkeys — 10 days ago
▲ 177 r/PlayCanvas+3 crossposts

PlayCanvas Engine 2.20 — WebXR on WebGPU + 3DGS Upgrades + Physics Joints

PlayCanvas is a free, open-source (MIT) real-time 3D engine that runs in the browser on both WebGL2 and WebGPU. We just shipped 2.20 — here's what's new.

Gaussian Splatting (the big one this release):

  • Real-time relighting of splats
  • Soft shadows
  • Depth of field
  • Clipping planes
  • Billions of splats via streaming + LOD
  • Shader effects (dissolve, rings)
  • Gaussian Splatting in VR (with LOD)

WebXR on WebGPU 👇
WebXR (VR/AR) now runs on the WebGPU backend — not just WebGL2. So you can build immersive experiences on the modern graphics API, including the new Gaussian Splatting features in VR. That combo is still pretty rare in the wild — most WebXR today is WebGL-only.

Also new:

  • Procedural sky
  • Clustered light cookies
  • Physics: joints + ragdolls
  • Draco mesh decoding in Node (via worker_threads)

Links:

Quick montage of the new examples attached — happy to answer anything about what we're releasing today!

u/MayorOfMonkeys — 12 days ago