My idea is roughly like this: if there is a model with a completely flat bottom, but the terrain is not flat, I want to use `CustomShader`

to adjust the position of vertices, so that the bottom of the model is close to the surface of the terrain.

Hi @SAYEOR,

Interesting question! I think this will be a bit tricky, as `CustomShader`

is related to glTF and 3D Tiles rendering, while terrain is a different system in CesiumJS. However, I have some ideas that might help you find a workaround.

First, While the `CustomShader`

doesnâ€™t have direct access to the terrain, note that you can pass in texture uniforms either from an image or a procedurally generated texture (see the Custom Shader Models Sandcastle for examples of both). So one thing that might help is to pass in terrain heights as a texture.

As for acquiring terrain heights, CesiumJS does provide a method for sampling terrain heights, see the Terrain Sandcastle.

The tricky thing will be how to turn terrain heights into vertex offsets, as the terrain and your modelâ€™s vertices are in very different coordinate systems:

- Sampling the terrain produces a grid of
`Cartographic`

coordinates (i.e.`(lon, lat, height)`

). Note that the heights are relative to the WGS84 ellipsoid and measured in meters. `CustomShader`

provides`positionMC`

(model coordinates) for positions. The quality of this highly depends on the position values stored in your gTF model. I find that east-north-up model coordinates are the best if youâ€™re going to use`CustomShader`

. This way`+z`

points up and not at some oblique direction (CesiumJS uses a coordinate system where +z is parallel to the earthâ€™s axis, which is often inconvenient in the shader)

Hereâ€™s a rough sketch on how I would attempt this:

- If youâ€™re able to modify the model, I would recommend these things for best results:
- the model should be in east-north-up coordinates so that the model appears right-side up when rendered and in the shader +z is the â€śupâ€ť direction.
- Make sure the modelâ€™s origin is at the bottom where itâ€™s flat, this will help with positioning it.
- Take a note of the coordinates of a rectangle around the bottom of the model, this will be helpful later.

- In CesiumJS, apply a model matrix to position the model on the globe (see
`Transforms.eastNorthUpToFixedFrame`

. There are many Sandcastles in the gallery that use this). Something like this:

```
// Set the height to 0 so the bottom of the model is exactly at the height of the ellipsoid
const center = Cesium.Cartesian3.fromDegrees(lon, lat, 0);
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
```

- Sample the terrain in a rectangle that lines up with the base of your model, and create a procedural texture of just the height values. This step might be a little involved to set up, but you have all the information you need:
- The coordinates of the base of the model so you know how far away from the origin in meters
- The terrain Sandcastle I linked above will provide some of the framework for setting up a grid of samples.
- See classes in CesiumJS such as
`Cartographic`

,`Cartesian`

,`Ellipsoid`

, and/or`EllipsoidTangentPlane`

for the math of computing sample positions (which may require converting between ENU space and Cartographic space)

- Pass the procedural texture (essentially an elevation map) to the shader following the sandcastle example
- Using the fact that your model is in ENU coordinates,
`positionMC.xy`

will be very helpful for sampling the elevation map. You just need to scale/shift the coordinates so theyâ€™re in the range`[0.0, 1.0]`

- Those height offsets are in meters, so you can add
`vsOutput.positionMC.z`

to shift it up

The above is just a rough algorithm, you may need to tweak some steps since I havenâ€™t tried this myself. Let me know if it helps your use case!

Peter

Thank you very much for sharing these ideas, which will be of great help to me. However, this issue is indeed more complex than I imagined, and I need more time to try it out. Thank you again!