For Lucid Trips I’ve needed a fast technique to provide reflection to a water surface. Not only was the surface large, it was also a sphere. A single reflection probe didn’t looked so well. But what would happened if we use thousands instead of one? I’ve made a prototype in Unity:
Not bad, huh?
Reflections by the surface
While this looks good enough, with this amount of probes it’s a engine meltdown. :fire: But there is a thing we can exploit here: the reflection probes share the same resolution and are placed in a deterministic way, we can put them into a single data structure. There are Cubemap arrays, which allow to store up tp ~400 reflection probes, but thats not enough for my case.
I went with a solution that unwraps the reflection probe on to a 2D texture by (ab)using Octahedron Encoding which maps a normalized, three-dimensional vector onto a two dimensional one. One can just use this compressed two dimensional vector as a UV coordinate, after scaling it from [-1, 1] to [0,1]. This texture is placed into a giant atlas which contains all unwraped reflection probes for the object.
For interpolation, each neighbor tile is sampled and interpolated in a bilinear fashion.
Baking the Atlas
For each slice:
- Render your target mesh in UV Layout and store world-position, normal and tangent into different rendertargets
- Use those rendertargets to get the world positions for the cubemaps
- Render the Cubemaps
- Bring the Cubemap into Tangent Space (= hemisphere points in the same direction as the surface it sits on).
- Convert the hemisphere into a texture slice
- Put the Flatted-hemisphere into atlas
Sampling the Atlas
For each pixel:
- Obtain the slice position by the UV
- Get the reflection ray
- Bring the ray into tangent space
- Convert the ray into octahedron / texture coordinate
- Use slice base position and ray to sample the 4 closets slices and interpolate them.
Look into the example implementation on GitHub for more details
Results
Limitations
This technique is rather memory heavy and may not offer the same quality as planar or raytraced reflections. It’s also not dynamic, although one could update a few slices overtime. But since it’s rather low on computational load, it should be a good fit for low-end devices or VR (like shown above in Lucid Trips).
Source
The example implentaion for Unity can be found on GitHub