Modify 3Dtile vertex shader

Hi!
I have been using Cesium for a while for my graduation project. Recently, I want to achieve height flattening for 3DTile. Like this:

I think it might be a good way to modify the vertex shader of 3DTile.

I want to know how can I modify the vertex shader of 3D Tile. Otherwise, I would like to know how to get and modify the partial 3DTile vertex shader.

Looking for answer!

Thanks!

Hi @W-Joker-cmd,

This is possible with a CustomShader, which allows you to specify a custom GLSL vertex or fragment shader to apply to a 3D Tileset or glTF model. We have a Custom Shader Guide which provides more information.

I will also mention that results may vary depending on the data. For something like this where you want to flatten vertices vertically, the data in the glTF should ideally be in a local east-north-up (ENU) coordinate system. This way, vsInput.attributes.positionMC.z points “up”. In such a case, this should be just a matter of scaling/shifting the z coordinate as desired. However, I’ve also seen tilesets where the tile coordinates are relative to global Cartesian coordinates, so positionMC.z is a direction parallel to the earth’s axis. At a local scale, this looks like the axes are pointing in an oblique direction. Please see this GitHub issue for more details.

Also, are you trying to flatten the entire dataset, or just specific buildings? CustomShader does support 3D Tiles Next feature IDs (as well as 3D Tiles 1.0 batch IDs). Such IDs can be used if selective flattening is needed.

Best,
Peter

Hi @ptrgags ,

Thank you for the response and suggestions! This is really helpful to me. I’ll try some and share my results later.

In my project, I just want to flatten specific building in 3D Tiles and add a new model to replace it. I think this will be of great help in building renovations.

I’m still in the learning phase for Cesium. If new questions arise in the future, I may continue to ask here.

Thank you for your time!

Best,
Hancheng

Hi @W-Joker-cmd,

Ah, interesting, if you’re trying to not just flatten the building but hide it from view, here are some more ideas:

  1. If you only need to replace a small number of specific buildings, clipping planes might be an easier method. See the Clipping Planes Sandcastle for an example. This way, you don’t need to edit your data.
  2. If you do try using a custom vertex shader, you can hide the building’s triangles. The code would look something along these lines:
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
  const float ID_REMOVE_BUILDING = 1.0; // whatever feature ID you chose for the building to be removed
  if (vsInput.featureIds.featureId_0 == ID_REMOVE_BUILDING) {
    // Shrink all the triangles in this building to a single point, so they won't appear on the screen.
    vsOutput.positionMC *= 0.0;
  }
}

Hi @ptrgags ,

First of all, sorry for replying to your message so late. I’ve been doing various attempts with custom vertex shaders.

In my previous job, I tried to apply Clipping Planes to my own 3Dtile like this:

I found two places that didn’t fit my needs:

  • Clipping Plane affects the entire 3Dtile instead of the buildings within it. (Maybe I made some mistakes while applying)
  • There will be holes at the bottom of the model. I just want to flatten the building height to the ground and place a new model. The appearance of these holes has a great impact on the rendering effect.

So I gave up using Clipping Planes. If you have some good suggestions, I’d be happy to try further.

Also, I tried Custom vertex Shader. Since I don’t know much about Custom Shader, I just made a simple attempt like this:

  var customShader = new Cesium.CustomShader({
    vertexShaderText: `
      void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput)
      {
        vsOutput.positionMC.z = 0.1 * vsInput.attributes.positionMC.z;
      }
    `
  })

  tileset = viewer.scene.primitives.add(
    new Cesium.Cesium3DTileset({
      url: url,
      customShader: customShader,
      enableModelExperimental: true,
    })
  );

image

This does work a bit, but there are still some issues:

  • Obviously, it targets the entire 3Dtile.
  • When I zoom in and out, the flattened 3Dtile will disappears like this:
    image

After, I tied to get feature Id of my 3DTile. I print tileset.content.featuresLength and get 0. It seems that my 3DTile has no feature. So I don’t know how to get a feature ID of specific buildings.

Is it a data problem or a method problem? Do you have any better suggestions for getting the 3DTile feature ID of specific buildings? Looking forward to your reply.

Thanks again for your help!

Best wishes,

Hancheng

Hi @W-Joker-cmd,

From your screenshot, it looks like you are using a single horizontal clipping plane, so indeed this would clip buildings all over the tileset.

Another option is to use multiple vertical clipping planes to cut out a polygon around the building. See this Sandcastle for some examples.

That said, there are some limitations. If your replacement model doesn’t cover the whole clipped region, you will still see holes which I know you said is undesirable. Furthermore, clipping planes can only clip out a single convex region, see Add support for concave /convex clipping planes + holes in CesiumJS · Issue #8751 · CesiumGS/cesium · GitHub

Your custom vertex shader code looks reasonable. I’m not sure why part of the flattened tile disappears. Are you able to share a Sandcastle link? If so I could take a look to see what’s happening here.

As for the feature IDs, you would have to add this to your data. I should have asked sooner, is this a tileset uploaded through Cesium ion, or 3D Tiles you’ve generated yourself? Unfortunately, ion doesn’t support labeling buildings like this currently.

Here is some more information on feature IDs from the relevant specifications:

  • For older 3D Tiles 1.0 formats such as .b3dm, the _BATCHID attribute is used for this purpose. See the spec
  • For 3D Tiles Next, we recently wrote the EXT_mesh_features glTF extension which defines a few different ways of defining feature IDs

Hi @ptrgags ,

Thanks for your tips about clipping plane and I have also realized this problem. I read the Issue #8751 carefully. But I didn’t try it right away because I found it seems don’t work on 3DTiles. Of course, I will also do some attempts later.

As for 3D Tiles, there seems to be something wrong with my own data. In order to use Sandcastle, I uploaded my data in Cesium ion but got some errors: Cesium Sandcastle

Since I don’t have feature IDs in my 3DTile, does that mean I should do something with the data? And how to achieve this? I noticed that 3D Tiles Next can define and use feature IDs, but I don’t know how to do it.

In your opinion, should I try convex clipping planes or process the 3DTile data to use vertex shaders?

Thank you again for everything you’ve done.