В CesiumJS луч (ray) рассматривается как математическая сущность, описываемая начальной точкой и направлением. Он используется для определения пересечений с объектами сцены: поверхностью земного эллипсоида, тайлами 3D Tiles, примитивами, сущностями и пользовательской геометрией.
Луч задаётся структурой, содержащей:
const ray = new Cesium.Ray(
camera.positionWC,
camera.directionWC
);
Ключевой момент: направление должно быть нормализовано, иначе результаты пересечений становятся некорректными или нестабильными.
На практике чаще всего луч формируется из координат пикселя экрана через камеру сцены.
const ray = viewer.camera.getPickRay(screenPosition);
Или более низкоуровневый вариант:
const ray = Cesium.Ray.fromCamera(camera, screenPosition);
Где screenPosition — координаты в системе canvas (x,
y).
Особенность: разные методы учитывают тип проекции камеры и могут давать различное поведение при перспективной и ортографической проекциях.
Cesium использует математическую модель WGS84 эллипсоида. Для пересечений с ним применяется:
const intersection = Cesium.IntersectionTests.rayEllipsoid(
ray,
Cesium.Ellipsoid.WGS84
);
Возвращаемое значение — параметр t, который
подставляется в уравнение луча:
[ P(t) = origin + t direction]
const point = Cesium.Ray.getPoint(ray, intersection);
Ключевая особенность: пересечение может отсутствовать, если луч направлен в космос или параллелен поверхности.
Cesium предоставляет высокоуровневый метод для пересечения с террейном:
const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
Если требуется проверка наличия пересечения без извлечения точки:
const isHit = Cesium.defined(
viewer.scene.globe.pick(ray, viewer.scene)
);
Для сцен с 3D Tiles используется:
const result = viewer.scene.pickFromRay(ray);
или расширенный вариант:
const result = viewer.scene.drillPickFromRay(ray);
Результат может содержать:
object — объект сцены (tileset, entity, primitive)position — Cartesian3 координата пересеченияprimitive — низкоуровневый графический объектid — связанный entityif (result) {
console.log(result.position);
console.log(result.object);
}
Для геометрических примитивов Cesium использует унифицированный механизм picking через сцены:
const picked = viewer.scene.pick(screenPosition);
Однако при работе с лучами применяется:
const result = viewer.scene.pickFromRay(ray);
Особенность: не все примитивы поддерживают точное геометрическое пересечение; некоторые используют bounding volumes.
Cesium включает набор низкоуровневых утилит для аналитической геометрии.
const plane = Cesium.Plane.fromPointNormal(
planePoint,
planeNormal
);
const intersection = Cesium.IntersectionTests.rayPlane(ray, plane);
Результат — параметр t вдоль луча.
const result = Cesium.IntersectionTests.rayTriangle(
ray,
vertexA,
vertexB,
vertexC,
true, // cull backface
intersectionResult
);
Применение:
const t = Cesium.IntersectionTests.raySphere(ray, sphere);
или
const t = Cesium.IntersectionTests.rayEllipsoid(ray, ellipsoid);
При работе через Scene методы Cesium использует внутреннюю систему приоритетов:
Метод:
const results = viewer.scene.drillPickFromRay(ray);
возвращает массив пересечений, отсортированный по глубине.
[
{ object, position, primitive },
{ object, position, primitive },
...
]
Особенность: порядок соответствует увеличению расстояния от камеры.
Классическая схема построения луча из координаты мыши:
const ray = viewer.camera.getPickRay(movement.position);
const result = viewer.scene.pickFromRay(ray);
if (result && result.position) {
const cartesian = result.position;
}
Пересечения зависят от нескольких факторов:
Важное наблюдение: прозрачные объекты могут быть пропущены при стандартном pickFromRay из-за оптимизаций глубины.
Cesium активно использует несколько систем координат:
Переходы:
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const cartesianBack = Cesium.Cartesian3.fromRadians(
cartographic.longitude,
cartographic.latitude,
cartographic.height
);
Луч всегда оперирует Cartesian3, поэтому преобразования являются обязательной частью цепочки вычислений.
Любой метод пересечения может вернуть undefined.
Типовые сценарии:
const hit = viewer.scene.globe.pick(ray, viewer.scene);
if (!Cesium.defined(hit)) {
// пересечения нет
}
Система пересечений в Cesium строится на комбинации:
Следствие: результат пересечения не всегда является чисто математическим, часто он оптимизирован под производительность.
Луч применяется не только для выбора объектов, но и для:
Пример проверки видимости:
const ray = new Cesium.Ray(origin, direction);
const blocked = viewer.scene.pickFromRay(ray);
const visible = !Cesium.defined(blocked);
Для комплексного анализа сцены часто комбинируются методы:
const terrainHit = viewer.scene.globe.pick(ray, viewer.scene);
const objectHit = viewer.scene.pickFromRay(ray);
const closest = Cesium.Cartesian3.distance(
camera.positionWC,
terrainHit || objectHit.position
);
Такой подход позволяет учитывать как рельеф, так и объекты сцены одновременно.