Description
Intro
Building off of #197, we'll want to add something akin to PointCloudShading
in CesiumJS to Cesium for Unity. This will improve the visual quality of point clouds in Unity, should users choose to add it to their point clouds.
The main benefits of point cloud shading are:
- attenuation, which allows more control over point size (points are currently drawn as a single pixel)
- eye dome lighting (EDL), which shades points so that they appear to have more depth. This will be important when we allow users to increase point size, since constant-color point clouds will appear like big globs of color without it.
This Sandcastle demonstrates PointCloudShading
's effects.
No shading | Attenuation only | Attenuation + EDL |
---|---|---|
![]() |
![]() |
![]() |
In CesiumJS, attenuation accounts for various factors and adjusts the gl_pointSize
accordingly. EDL is accomplished by rendering the depth values of the point cloud to a separate texture, then blending them with the point cloud colors. (CesiumJS implementation here) So to summarize, the following is necessary to implement point cloud shading:
- a way to visualize points at larger sizes
- the ability to write to two outputs, depth + color
- the ability to blend the two outputs together
Unity implementation
Points are currently rendered just like other tilesets. The only difference is that the mesh is constructed with MeshTopology.Points
instead of MeshTopology.Triangles
. This is a great start, but there's no way to control the size of the points that are rendered. I also don't know how to get the depth values of only the points that are rendered
Here, I'm chronicling all of the methods I've considered / tried.
- ❌ Use the PSIZE attribute in a Unity shader
- This involves forcing Unity to use OpenGL, which is pretty unideal.
- ❌ Write a geometry shader to expand the points to quads
- Geometry shaders are not supported by Metal.
- ❔ Draw instanced quad meshes wherever the point positions are
- This only works with
DrawMeshInstanced
. I was not able to getDrawMeshInstancedProcedural
orDrawMeshInstancedIndirect
to work because apparently the instance ID attribute is not available in those functions, so it's 0 for every instance 🤔 - This method involves some duplication of data, since one of the arguments to
DrawMeshInstanced
is aMatrix4x4[]
array. - You'd have to convert the desired point size to an actual world scale for each quad -- something like the way
minimumPixelSize
affects a model's scale in CesiumJS. - This is compatible with Shader Graph, so it might be easier to integrate with what we do for Feature styling with metadata #200.
- I haven't looked into how I'd extract the depth values with this method yet, if it's possible.
- This only works with
- ❔ Use a compute shader to compute point size, then expand the points to quads.
- This should be supported by all the platforms Cesium for Unity supports, according to the documentation.
- This can be used as an alternative to a geometry shader, and can also help with rendering to multiple outputs.
- This isn't compatible with Shader Graph, since it only expects one position output. This could have implications for Feature styling with metadata #200.
I'll update this issue as I go so I can document my various approaches / struggles / woes with the Unity implementation.