Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overriding the final output of custom shaders #12291

Open
UniquePanda opened this issue Nov 7, 2024 · 2 comments
Open

Allow overriding the final output of custom shaders #12291

UniquePanda opened this issue Nov 7, 2024 · 2 comments
Labels
needs feedback On hold until additional info is supplied needs triage type - enhancement

Comments

@UniquePanda
Copy link
Contributor

Feature

Context
I have some vector data that I'd like to show in a CesiumJS viewer using a streamable data format.
The obvious choice is to use 3DTiles. 3DTiles does not have built-in support for vector data, however I am already able to convert my vector data into GLTF tiles.
This is working fine for polygons and points. Lines however require some special handling, because you usually don't want to show vector lines only with a fixed width (of e.g. 1 meter). Instead you want to be able to e.g. control their width.

Use Case for this issue
As explained in Cesium's own blog post here https://cesium.com/blog/2013/04/22/robust-polyline-rendering-with-webgl/ and as implemented for example here https://github.com/pmndrs/meshline/blob/master/src/MeshLineMaterial.ts for THREE.js, there are some neat vertex shader tricks for rendering lines. I can apply those to a 3DTileset that contains lines from a vector dataset and it works great.
However, it only works if I am able to control the final gl_Position.
The current way how custom shaders are implemented does not allow for such precise control of the shader output, because the custom shader code is not run at the end of the shader.
In my specific case the problem is that the geometryStage will always run after the custom shader code and will transform the output of the custom shader code.
Simply cancelling out the calculations of the geometryStage by applying the inverted matrices on the positionMC in the custom shader will lead to massive precision loss and therefore to jagged lines.

Similar use cases may exist. In fact, I have a smaller use case for a fragment shader, too, where I want to prevent an override of the output color because I use a combination of CPU styling and fragment shader styling. This however might be resolvable with some other workarounds I didn't try yet.

Proposed solutions/ideas
I have two ideas how this might be possible to achieve:

  1. Allow to set an option on the custom vertex and fragment shader objects that prevents any modification of the output of the custom shader code.
  2. Allow to define a second custom shader function, like overrideShaderOutput(), that will be run at the end of the final shader. This would allow for having some shader code in the normal custom shader and some in the "override" shader to use the advantages of both worlds.

Disclaimer
I know that this would open the door for much more developer error than is currently possible.
However, as the current way of adding custom shaders wouldn't be removed, I think this solution would still be a nice addition to the framework.

If you'd consider this idea feasible, I could try to come up with a PR for it.

@ggetz
Copy link
Contributor

ggetz commented Nov 13, 2024

Thanks for the suggestion @UniquePanda!

What you propose would certainly be one way to solve the issue of handling lines in vector data. However, I wonder if there is a more fundamental question here about how to handle line width display. How is the line data stored in glTF in this case?

@ggetz ggetz added the needs feedback On hold until additional info is supplied label Nov 13, 2024
@UniquePanda
Copy link
Contributor Author

UniquePanda commented Nov 14, 2024

Thanks for the repsonse, @ggetz!
Sure, obviously the "nicer" solution in my case would be for 3DTiles to support the direct usage of vector data! However, I think this topic is off the table for now. 😄

Another solution would be, to use LINE_STRIPs in the GLTF. This technically works, but only allows for 1px wide lines, because of the limitations of gl.lineWidth(). So currently, when a 3DTiles tileset contains a GLTF with LINE_STRIP primitives those lines are always rendered as 1px wide lines.
However, my research in this topic is already some months old now, so maybe I just missed something or something changed by now?

I thought that somewhere I read something about this and concluded that Cesium won't support "better" line rendering from GLTFs, because essentially what you need to do is what I did by myself now:

  1. Make the line a polygon by extruding it and triangulate the shape
  2. Use that polygon together with a shader to change the lines thickness

I might be mistaking about this, because I wasn't able to find any issue or forum thread about this right now. :)

So to answer this question:

How is the line data stored in glTF in this case?

The lines are triangulated and then stored as a polygon (primitive mode TRIANGLES) in the GLTF.
However, as this is done in my own preprocessing, I could store them in any other way, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs feedback On hold until additional info is supplied needs triage type - enhancement
Projects
None yet
Development

No branches or pull requests

2 participants