What is the model positiomMC.y direction in custom shader

I try to flatten the model by multiply a small float value to vsOutput.positionMC.y in customShader:

new Cesium.CustomShader({
    lightingModel: Cesium.LightingModel.UNLIT,
    isTranslucent: true,
    vertexShaderText: `
      void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput)
      {
        vsOutput.positionMC.y = 0.01 * vsInput.attributes.positionMC.y;
      }
    `
})

Then I apply this custom shader to the tileset on officical ion, which id is 75343.

const tileset = new Cesium.Cesium3DTileset({
  url: Cesium.IonResource.fromAssetId(75343),
  customShader,
});
viewer.scene.primitives.add(tileset);
viewer.zoomTo(tileset);

But it’s not work as I expected:

I read the custom shader document, and found a notes:

Note : As of this writing, only tilesets that use the 3DTILES_content_gltf extension will support CustomShaders . Future releases will add support for other formats such as b3dm.

Is that mean I can not flatten the tile model by modify its vertex position in model coordinate system now?

I also try this vertex shader by using glTF model “SampleData/models/CesiumBalloon/CesiumBalloon.glb”, it work as my expected.

So the y-axis of the tile model from b3dm tileset is not the up direction in the eastNorthUp coordinate system?

Hi @onsummer,

Thank you for your question! It seems like we are getting a lot of questions related to custom shaders recently. @ptrgags has a ton of experience in this area and should be able to help you out :rocket: :art:

Best,
Sam

Hi @onsummer, right now positionMC is in the model space of the data. Unfortunately, a lot of old sample tilesets were stored in Cartesian space (up to a matrix translation) so +z points parallel to the earth’s axis. If you want to use positionMC in a shader and have +z be “up”, the data needs to be in east-north-up (ENU) space.

Just the other day this came up in GitHub, see Possible issue regarding custom shaders and rotation of i3dm/b3dm tilesets · Issue #10146 · CesiumGS/cesium · GitHub for further discussion.

As for the note in the documentation, that’s not relevant, and also I think it’s outdated? As long as you use enableModelExperimental, b3dm and i3dm models should work. I’ll make a note to update the documentation soon.

@ptrgags @sam.rothstein Thank you for your reply and thanks to the contribution of Cesium team.

Unfortunately, a lot of old sample tilesets were stored in Cartesian space (up to a matrix translation) so +z points parallel to the earth’s axis.

I realize this, because I see that is no transform property in tileset.rootTile, it means that the vertices in gltf part of b3dm tile are base on ECEF(world coordinate system in cartesian3).

So I will try to use the inverse east-north-up matrix to multiply positionWC, then get the position on east-north-up space.

eg.

const toEcefMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(interestPoint)
const inverse = Cesium.Matrix4.inverse(toEcefMatrix)

// ...

new Cesium.CustomShader({
  uniforms: {
    u_toEcefMatrix: {
      value: toEcefMatrix,
      type: Cesium.UniformType.MAT4
    },
    u_inverse: {
      value: inverse,
      type: Cesium.UniformType.MAT4
    }
  },
  vertexShaderText: `
  void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
    vec4 positionENU = u_inverse * vsInput.attributes.positionWC;
    // modify positionENU as output here, for example, scale z by 0.1
    vec4 modifiedPosition = positionENU * vec4(1.0, 1.0, 0.1, 1.0);
    vsOutput.positionMC = u_toEcefMatrix * modifiedPosition;
  }
  `,
  // ...
})

I do not know what will happen, I will test later.