How to get the Normal Vector of a picked position/point?

I want to get the Normal Vector of a picked position/point, like the result of viewer.scene.pickPosition() or viewer.scene.pick().

Those two functions, pick() and pickPosition() are already very useful. While under some circumstances, I want to get the Normal Vector and picked position at the same time.

For example:

  • when I click the globe with terrain layer, I can get the clicked position and the Normal Vector of the clicked point lying on terrain.
  • when I click on a 3D Tileset Model, such as a house with many walls, if I click on the wall, I can get the clicked position and the Normal Vector of the clicked point lying on the wall.

Are there some methods in Cesium could support my requirement?
Or do you have some advice for me if I try to achieve this function.

Thanks!

Off the top of my head, you could start with a normal to the center of the earth (invert if needed);

let pickedPosition = viewer.scene.pickPosition(screen_coord);
let globePosition = viewer.camera.pickEllipsoid(screen_coord);
let normal = new Cesium.Ray( pickedPosition, globePosition );

Then you use the normal (ray) for a variety of intersection calculations; IntersectionTests - Cesium Documentation.

Cheers,

Alex

Hello Alex,

Thank you for your reply!
I think I need to explain more details of the “Normal Vector”, which I mentioned in the question.
It’s more related to the data source like terrain tiles, entities, primitives and 3D Tileset models.

Actually I have wrote a demo to get the Normal Vector, but in a very roughly way. And the Normal Vector I get is not very precisely.

I added a left click event to draw the Normal Vector of the click point and return it. Here is how I tried to calculate the Normal Vector.

// choose the clicked screen_coord and two other screen cooedinates nearby (mostly these three screen coordinates will be on the same feature surface)
var screenP0 = movement.position;
var screenP1 = new Cesium.Cartesian2(movement.position.x, movement.position.y - 5);
var screenP2 = new Cesium.Cartesian2(movement.position.x - 5, movement.position.y);

// get the cartesian coordinates for each of them
var P0 = viewer.scene.pickPosition(screenP0);
var P1 = viewer.scene.pickPosition(screenP1);
var P2 = viewer.scene.pickPosition(screenP2);

// calculate the Normal Vector by Cesium.Cartesian3.cross()
var vec1 = Cesium.Cartesian3.subtract(P1, P0, new Cesium.Cartesian3());
var vec2 = Cesium.Cartesian3.subtract(P2, P0, new Cesium.Cartesian3());
var normalVec = Cesium.Cartesian3.cross(vec1, vec2, new Cesium.Cartesian3());

Draw Normal Vectors in the scene will be like this:

The Green volumes in the picture represents Normal Vector of three click positions.

====================================
But in this way, the calculated Normal Vector of the clicked position has some error which I guess might come from the getDepth() function inside viewer.scene.pickPosition().
So I am wondering if there’s some accurate methods to get the Normal Vector instead of “calculate” it.

Thanks!
Yujie